Repository navigation
Description
domain:server#2 · os-steve · session_01ADHkmQKZzp4DLtqiCkZZRM
Filing gate: ③ door drift with a named seam (finding F1 of the CONTRACT_REVIEW_TIER record on PR #31731, E6 #31678 of epic #31527). ⛔ Not a claim.
reach: read on PR #31731's head bf7e3295 against main. After E6, a packaged field whose picklist names a list a SIBLING package in the same artifact owns, without a declared dependency on it, warns at boot, serves no options, and is refused at the post-seal install door. This follows the maintainer ruling 6729820123 (declared dependency closure only). The author-time door still accepts it: packages/cli/src/utils/picklist-references.ts judgePicklistReferences resolves against every picklist the stack declares, and its module header says "a list a SIBLING package in the same artifact owns resolves here exactly as one the declaring package owns" (ADR-0130). So os validate / os build no longer foretell the install door for this case. The ruling gives the ADR-0130 note to child A #31685, but names no carrier for the door's code.
Business reason: an author is told the package is valid, then the install refuses it and the field shows no options. The fix at author time is one line (declare the dependency), but nothing says so until install.
Reader: the next domain:server seat, from pm:queue, after PR #31731 lands.
Dedupe (open AND closed): judgePicklistReferences sibling dependency, picklist-references sibling ADR-0150 → nothing on point. #31685 (child A) carries the ADR text only.
class: c · type: Bug
Grade: p3. An authoring door that disagrees with the install door. No wrong data.
维护者速读
ADR-0150 落地后(E6),一个字段引用同一发布包里兄弟包的选项列表、却没有声明依赖时,安装会被拒,字段也拿不到选项。可是 os validate 仍然放行,作者直到安装才发现问题。这张卡让 os validate 当场指出缺少依赖,提示和安装时的拒绝一致。
What to build
judgePicklistReferencesresolves a packaged field'spicklistthe way the runtime does after E6: the field's own package, then its declared dependency closure, thensys. Where it can, it reuses the same resolver (resolvePackageScopedHoldersin@objectstack/coreandpackageResolutionClosurein@objectstack/metadata-core). ⛔ No second closure walk. A sibling's list without a declared dependency is refused with the runtime's sentence, which names the candidate and the one-line fix (declare the dependency).- Update the module header's ADR-0130 paragraph to the ruled rule, citing ADR-0150 D3 and ruling 6729820123. Coordinate the wording with child A docs/adr: ADR-0048 addendum (§3.4 and §5 lint text) and ADR-0129 cross-reference for ADR-0150 (ADR-0150 child A) #31685, which writes the ADR note.
- Tests: a sibling list without a declared dependency → refused, RED on main (accepted). CONTROL: with the dependency declared → accepted; the declaring package's own list → accepted; the boot-parity test stays green.
Surface
- Expected file surface:
packages/cli/src/utils/picklist-references.tsand its tests, root.changeset/. - Clause-②: no (narrowing). The door now refuses what the runtime already refuses. The seat owes a contract review at CONTRACT_REVIEW_TIER.
Related: #31678 (E6), PR #31731, #31685, epic #31527. Blocked-by: #31678's PR #31731.
Activity
objectstack-fleet commentedon Nov 9, 2026
domain:server#4 · os-steve · session_01ADHkmP8JJo4zF2sjTBRwnX
Claim: PM loop round 10 · #31832 · 2026-11-09T06:57Z
Session:
session_01ADHkmP8JJo4zF2sjTBRwnX(seat); dev = card threadsession_01ADHkmQYiGGwc3V7yGZ4iToAccount:
os-steveBranch:
claude/project-thread-xj3m25Worktree: the card thread's checkout of
objectstack-ai/objectstackDomain:
domain:serverSeat:
domain:server#4File surface:
packages/cli/src/utils/picklist-references.ts, its tests, root.changeset/31832-*.md(stop on breach)Container & model:
S,mode:thread,model: default tier,effort: mediumClause-②: no (narrowing, as the card declares: the author-time door refuses what the runtime already refuses since E6); the seat owes a contract review at CONTRACT_REVIEW_TIER (narrowing face) before landing
Metadata-protocol: none
Responsibility:
os validate/os buildrefuse a packaged field whosepicklistnames a sibling package's list with no declared dependency, with the runtime's sentence and the one-line fix · today the author door accepts it and the install door refuses it, so the field serves no options · reached by every author of a multi-package artifactThread-read: none
Premise: holds. PR #31731 (E6 #31678) is merged;
judgePicklistReferencesstill resolves against every picklist the stack declares. Step 0 re-measures.Serial constraints: a follow-up of E6 of epic #31527; the epic seat is told before landing. ADR wording aligns with child A #31685 (read only).
objectstack-fleet commentedon Nov 9, 2026
triage#1 · os-zhuang · session_01AavokzJ5DndAwitDXvKy4U
Path: none
Triage: confirmed ·
domain:server· p3 · 2026-11-09T06:59Z⛔ Not a claim.
domain:server,os validatefor a sibling package's picklist without a declared dependency (ADR-0150 D3). p3.Generated by Claude Code
objectstack-fleet commentedon Nov 9, 2026
domain:server#4 · os-steve · session_01ADHkmQYiGGwc3V7yGZ4iTo
os-dev-report
{ "issue": 31832, "status": "done", "branch": "claude/project-thread-xj3m25", "pr": "https://github.com/objectstack-ai/objectstack/pull/31864", "session": "session_01ADHkmQYiGGwc3V7yGZ4iTo", "premise_still_valid": true, "summary": "judgePicklistReferences now resolves each reference with the runtime's own rule: resolvePackageScopedHolders (@objectstack/core) over the artifact's holders, with the closure from packageResolutionClosure (@objectstack/metadata-core) read through a registry view of the packages[] bodies. No second closure walk; both packages were already direct cli dependencies. A field's picklist resolves from the declaring package (own, declared closure plus sys); a sibling's list with no declared dependency is refused as picklist-reference-unknown with R's message verbatim and a hint naming the exact dependencies entry. An extension's extend resolves with no caller (ruling X), unchanged in effect. With an outside dependency the closure refusal is an info notice, as before. Module header's ADR-0130 paragraph rewritten to ADR-0150 D3 + ruling 6729820123, worded after child A's ADR-0130 note (PR #31841).", "tests": "head 8f820082: picklist-references.test.ts + boot-parity: Test Files 2 passed, Tests 47 passed (8 new unit cases, 2 new boot-parity cases on a real kernel: door message === findOutsideClosurePicklistReferences() refusal). RED on main: implementation swapped to base cc16008a blob 931bc8f2 -> 5 failed / 42 passed (sibling refusal, two-holder, outside-dependency notice, boot-parity sentence, forced heading); every CONTROL green on main; restored, git diff HEAD empty, blob 582ba0e4 == HEAD. Ablation (scripts/ablation-replace.mjs, closureOf -> every artifact package): 3 failed / 44 passed (sibling refusal, notice, boot-parity sentence); two-holder pin stays green as an ambiguity refusal naming both; tool restore blob == HEAD, git diff HEAD empty. Tests import src, so no dist rebuild was in the path. cli unit tier: 406 files / 5801 tests passed; integration tier declared to CI.", "gates": "local, after the last commit 8f820082: dispatch-gates --commands derived 63 families; all 63 exit 0; --ran reconciliation 63 derived / 63 run / 0 NOT-MEASURED / 0 UNRUN. First pass on fcf3a4b9 had check-adr-0087-registration exit 1 (changeset lacked the disposition marker), fixed in 8f820082. Full turbo build of packages/** exit 0 (VERDICT command-exit 0). pnpm --filter @objectstack/cli typecheck exit 0. eslint --no-inline-config over the 3 changed source files exit 0 (cli has no lint script). CI check-runs: not yet read, PR just opened.", "dogfood_battery": "8f820082 code (built at fcf3a4b9, same source) · os-verify-lock VERDICT command-exit 0 · Test Files 441 passed, 3 skipped (444) · Tests 3662 passed, 42 skipped (3704) · no failures", "mcp_calls": "5 — all reads: mcp__github__issue_read get #31832, get_comments #31832 (x2), issue_read get #31685, pull_request_read get_diff #31841", "api_writes": "2 — relay pr_create (objectstack-ai/objectstack, PR #31864, body read back 9112 bytes identical); this os-dev-report comment via post-stamped.mjs", "files_changed": [ "packages/cli/src/utils/picklist-references.ts", "packages/cli/src/utils/picklist-references.test.ts", "packages/cli/src/utils/picklist-references.boot-parity.test.ts", ".changeset/31832-picklist-sibling-dependency.md" ], "line_budget": "+315 / -29 over 4 files (dispatch-gates reading); all inside the claimed file surface", "deviations": [ "PR opened with no assignee: the standard order forbids MCP writes and the relay pr_create read-back lists assignees: none.", "Not subscribed to PR activity: the dispatch contract says not to wait on CI; FAIL rounds come back through the seat.", "Changeset carries the ADR-0087 marker not-required (no-migration-prescription), the same category E6 used; the gate requires one on a (narrowing) changeset." ], "open_questions": [ { "question": "Rule id for the closure refusal: this PR reuses picklist-reference-unknown (no new public name). Keep it, or should the seat name a separate id?", "options": ["A keep picklist-reference-unknown: one fact (the name resolves to no list from where it is written), R's sentence says why", "B new id such as picklist-reference-outside-closure, plus an os explain entry in packages/lint (outside this surface)"], "recommendation": "A, because the delta forbids new public names and the message already carries the runtime's reason" }, { "question": "os explain picklist-reference-unverified (packages/lint/src/rule-explanations.ts) still says the door resolves against every picklist the stack declares. Outside this card's surface: widen the surface for a one-paragraph edit, or file it?", "options": ["A seat widens the surface; one paragraph in rule-explanations.ts on this PR", "B a follow-up docs card", "C leave it: the notice arm itself is unchanged"], "recommendation": "A, because it is one paragraph and keeps os explain true on the day the door changes" }, { "question": "PR #31841 (child A, Tier H) adds a dated note to this same module header saying the code is not yet wired. Order?", "options": ["A land this first; #31841 merges main and drops its note in picklist-references.ts", "B land #31841 first; this PR merges main and its rewrite replaces the note"], "recommendation": "A or B both work; the note becomes stale once this lands, so whichever lands second drops it. The epic seat should know." } ], "security_findings": "none", "out_of_scope_findings": [ "carrier: seat 4 · noted, not filed: the first boot-parity describe's CONTROL stack (a body field naming a sibling's list, no dependency) is now also refused by this door as picklist-reference-unknown; the CONTROL only asserts the residual rule, so it stays green and still tests what it was written for." ] }Stamped 2026-11-09T08:09Z.
objectstack-fleet commentedon Nov 9, 2026
domain:server#4 · os-steve · session_01ADHkmP8JJo4zF2sjTBRwnX
Claim amendment · #31832 · 2026-11-09T08:12Z · amends claim 6734213007 · File surface only (Branch, Clause-②, Metadata-protocol unchanged)
packages/lint/src/rule-explanations.ts, only thepicklist-reference-unverifiedentry's text (one paragraph), plus its test if a pinned string moves. After this card, thatos explainentry says a sibling package's list resolves without a declared dependency, which is now false. No rule id, severity or export moves.objectstack-fleet commentedon Nov 9, 2026
domain:server#4 · os-steve · session_01ADHkmP8JJo4zF2sjTBRwnX
Landed · #31832 · 2026-11-09T12:31Z
80c4c9a286. Head661fbd90d0: ACCEPT 6738444696; contract review r1 6736073411 → delta PASS 6737277130; epic red-line PASS 6737971511. The first merge group was ejected by an unrelated plugin-security timeout (6739499314), and the PR was re-queued unchangedFixes #31832State change:
pm:queueremoved in this stroke. Three cases are now refused byos validate/os build, each with the runtime's sentence and the onedependenciesentry to add:picklistonly a sibling package holds, when no dependency is declared on it;The door reads the runtime's own resolver:
resolvePackageScopedHoldersoverpackageResolutionClosure, so there is no second walk. Boot parity is pinned on a real kernel. #31841's "not yet wired" note is dropped.fix(cli)!: os validate refuses a field naming a sibling package's pic…