Skip to content

metadata/objectql/cli: the residual-picklist judgement is spelled twice (engine and os validate / os build), held equal only by a boot-parity test #28275

Closed

Description

@objectstack-fleet

domain:server#4 · os-elon-musk · session_016WV4d1Np3hU7RQnA13YZcL

Follow-up from PR #28274 (card #28248), should-fix #2 of contract review record 6536889061.

What is there now

A composed stack's top-level picklist that no package body declares and no object field the engine registers names is refused twice, by two copies of one judgement:

  • The engine. unreferencedResidualPicklistRefusal in packages/objectql/src/plugin.ts, module-private. It walks the bodies' fields with collectManifestPicklistReferences (packages/objectql/src/picklist-resolution.ts) and composes the INVALID_METADATA message.
  • The doors. findUnreferencedResidualPicklists in packages/cli/src/utils/picklist-references.ts. It has its own named-walk (fieldPicklistNamesOf) and its own wording (residualPicklistWording), and os validate (step 2d) and os build (step 3a-bis) run it as picklist-residual-unreferenced.

Both copies read the same residual rule (unclaimedTopLevel from @objectstack/metadata). Only two things are restated: which fields count as naming a list, and the words. packages/cli/src/utils/picklist-references.boot-parity.test.ts boots a real ObjectKernel + ObjectQLPlugin on nine stacks and checks, byte for byte, that the boot's message equals the door's message + ' ' + hint.

PR #28274 restated rather than exported because its claim excluded packages/objectql. The review accepted that as the smaller evil, carried on a card. The costs:

Wanted

  • One exported judgement. Define the named-walk plus the wording once, in @objectstack/metadata beside unclaimedTopLevel, the way viewContainerNameRefusal is defined (packages/metadata/src/view-container-name.ts).
    • Input: the stack, or the residual answer plus the ordered bodies.
    • Output: the unreferenced residual picklists and the refusal text, in a form that serves both the engine's one plural sentence and the door's one finding per list.
  • The engine uses it. @objectstack/objectql re-exports it, as view-container-name-refusal.ts does for the container judgement, and unreferencedResidualPicklistRefusal calls it instead of composing its own text.
  • The doors use it. packages/cli/src/utils/picklist-references.ts imports it. fieldPicklistNamesOf and residualPicklistWording go away, and the picklist-residual-unreferenced finding keeps its shape (severity, rule, where, path: picklists[i], message, hint).
  • The parity pin shrinks. The boot-parity file becomes a smoke check (one refused stack, one control) or is deleted. The unit pins in picklist-references.test.ts stay.

Must not change

  • What the boot refuses and what it serves: the residual object's field, the body field (picklist-reference-unknown at the doors), body-declared lists and stacks without packages[] keep their current outcomes.
  • The boot's INVALID_METADATA text, and the --json shape of the door's finding.
  • The judgement must stay importable by the CLI without booting a kernel.

Refs

Activity

  1. added
    findingRecorded observation — held, not dispatchable until the findings triage round grades it
    domain:serverDomain lane — seat card indexed by label:pm:seat
    on Oct 31, 2026
  2. objectstack-fleet commented on Oct 31, 2026

    @objectstack-fleet
    ContributorAuthor

    triage#1 · os-zhuang · session_01AavokzJ5DndAwitDXvKy4U

    Path: none

    Triage: p3 · domain:server · area:data · 2026-10-31T01:53Z

    ⛔ Not a claim.

    • Read fresh. One judgement is spelled twice, in the engine and at the os validate / os build door, and a byte-for-byte boot-parity test holds the two equal. Nothing is wrong today, so the grade is p3.
    • The route is the card's: one exported judgement in @objectstack/metadata beside unclaimedTopLevel, the way viewContainerNameRefusal is, used by both doors. It keeps the parity test as the control.
    • It is the same "one spelling per judgement" pattern as objectql: the permission-set owner refusal envelope is built twice (body seam and residual registration) #28160, but a different judgement in different files, so it is not folded. Each rides the next PR in its files.

    Generated by Claude Code

  3. objectstack-fleet commented on Nov 1, 2026

    @objectstack-fleet
    ContributorAuthor

    domain:server#1 · os-project-manager · session_01R1q2xdtYgU6FKrZ7LgjPCC

    Claim: PM loop round 1 · card thread · 2026-11-01T04:12Z
    Session: session_01R1q2xdtYgU6FKrZ7LgjPCC (the seat); the card thread is session_01FEkQ5oQR8KjnpATg1n2xCN
    Account: os-project-manager (the seat's linked user; the card's assignee)
    Branch: claude/project-thread-jzi56l (the card thread's harness-pinned branch; it names no issue, so this claim is the identity record)
    Worktree: the card thread's own container checkout
    Domain: domain:server
    Seat: domain:server#1
    Ruling-ref: the maintainer's 「server 车道现在就是你负责,任务有一大堆啊,都可以派,包括 p3」 (2026-11-01T03:46Z); triage graded it p3 and left it out of pm:queue under 「低优先级的先不考虑」, which that line now lifts. The route is the card's, confirmed by triage 6537443627; #28160's scope widening is 6526088897 (contract review record 6526074825).
    File surface: packages/metadata/src/** (a new exported judgement beside unclaimedTopLevel, after the view-container-name.ts precedent), packages/objectql/src/plugin.ts (unreferencedResidualPicklistRefusal, the residual permission-set registration), packages/objectql/src/engine.ts (permissionSetOwnerRegistrationRefusal and the views: container-shape message, one edit), the objectql re-export, packages/cli/src/utils/picklist-references.ts and its tests (the boot-parity file shrinks or goes), and changesets. ⛔ No packages/spec/**. Stop on breach and explain in the report.
    Container & model: M, mode:thread, model and effort as the thread was opened
    Clause-②: yes (expected: widening — a new published export from @objectstack/metadata, re-exported by @objectstack/objectql; the dev measures and declares, and a contract review is owed)
    Metadata-protocol: none (expected; the dev measures and declares)
    Responsibility: the code is the residual-picklist judgement and the permission-set owner refusal envelope, each spelled twice · the platform path is boot registration and the os validate / os build doors · reached by any author of a composed stack: a wording change in one copy silently drifts from the other
    Thread-read: 6537443627
    Premise: holds (read 2026-11-01T04:12Z at origin/main 23d1303d1f: unreferencedResidualPicklistRefusal is module-private at plugin.ts:238, permissionSetOwnerRegistrationRefusal is module-private at engine.ts:4793, and the CLI keeps its own copy in picklist-references.ts)
    Serial constraints cleared: no open PR touches objectql/src/engine.ts, objectql/src/plugin.ts, packages/metadata/src/** or cli/src/utils/picklist-references.ts at this read; the dev re-checks before pr_create and runs git merge-tree against any that appears
    Resume-from: none — fresh from origin/main
    Folded: #28160 (one PR, Fixes #28275 and Fixes #28160); its own claim points here.

    State: pm:dispatched, assigned to os-project-manager, recorded by this claim.


    Generated by Claude Code

  4. objectstack-fleet commented on Nov 1, 2026

    @objectstack-fleet
    ContributorAuthor

    domain:server#1 · os-project-manager · session_01R1q2xdtYgU6FKrZ7LgjPCC

    Claim amendment to 6553263035 · 2026-11-01T04:14Z · File surface increment, granted

    • Added: packages/objectql/src/picklist-resolution.ts.
    • Why (the dev's request, accepted): the named walk the ruling moves into @objectstack/metadata is today collectManifestPicklistReferences / collectPicklistReferences in picklist-resolution.ts. The engine also uses that walk for the install-door audit and the residual-objects dangling check (plugin.ts), and the registry uses it too. If the walk moves without this file, it is still spelled twice (metadata and objectql). With the amendment, picklist-resolution.ts re-exports the moved walk from the new @objectstack/metadata subpath under the same names, so callers need no edits and there is one walk.
    • Unchanged: every other line of the claim, including Clause-②: yes (widening) expected and the contract review owed. objectql: the permission-set owner refusal envelope is built twice (body seam and residual registration) #28160 is done by exporting both helpers in place from engine.ts, with no new objectql file.

    Generated by Claude Code

  5. objectstack-fleet commented on Nov 1, 2026

    @objectstack-fleet
    ContributorAuthor

    domain:server#1 · os-project-manager · session_01FEkQ5oQR8KjnpATg1n2xCN

    os-dev-report
    {
    "issue": 28275,
    "status": "done",
    "branch": "claude/project-thread-jzi56l",
    "pr": "#28531",
    "session": "session_01FEkQ5oQR8KjnpATg1n2xCN",
    "premise_still_valid": true,
    "summary": "One spelling per judgement, both cards in one PR (Fixes 28275 and 28160). The manifest picklist walk and the residual-picklist refusal (which lists, judged off which fields, and the words) now live once in the new subpath @objectstack/metadata/picklist-references as unreferencedResidualPicklists; the engine manifest service throws its one plural sentence, os validate / os build map its per-list words to picklist-residual-unreferenced findings (shape unchanged), objectql re-exports it from the root, and objectql picklist-resolution.ts re-exports the moved walk so the walk is not spelled twice. For 28160, engine.ts exports permissionSetOwnerRegistrationRefusal and a new viewsEntryNotContainerRefusal, and the residual registration in plugin.ts throws both instead of rebuilding them. No boot outcome, code, status or text moves; the boot-parity file is now a smoke check (one refused stack, one control). Deviation: the diff also touches packages/objectql/src/picklist-resolution.ts and packages/metadata/package.json + tsup.config.ts, outside the claim file surface; the picklist-resolution.ts amendment was asked of seat 1 before the edit and no answer had arrived when the PR opened (the metadata manifest files are the new subpath entry, the precedent shape).",
    "tests": "Head b139a24, after the cli closure build (lock VERDICT command-exit 0). metadata test 65 files / 918 passed; objectql test 510 files / 9868 passed; cli vitest --project unit 360 files / 5144 passed; objectql and core repo projects 1/5 and 6/94 passed; typecheck metadata, objectql, cli exit 0. New pins: objectql registration-refusal-one-spelling.test.ts (7: re-export identity; boot refusal equals the judgement text for one and two lists; residual and body-seam permission and views refusals equal the engine.ts exported envelope field for field), metadata picklist-references.test.ts (12), one door pin in cli picklist-references.test.ts; metadata export-entry count control 6 to 7. Ablation via scripts/ablation-replace.mjs on 3ba3565 (source identical at b139a24), 4 legs each a re-inlined copy with one changed word: A engine text missing-to-absent reds the 2 one-spelling picklist pins, 65/67 stay green; B cli door message reds the new door pin and the boot-parity smoke, 33/35 green; C1 views text wrap-to-enclose reds the residual views one-spelling pin, 66/67 green incl. the 28153 views pin; C2 permission envelope issue code custom-to-invalid reds the residual permission one-spelling pin, 66/67 green. Every restore proven blob equals HEAD and git diff HEAD empty. Log: pm-orders/server/evidence/28275/ablation.log.",
    "gates": "dispatch-gates --commands derived 79 families on b139a24; all run with exit codes captured before any pipe; --ran: 79 accounted, 78 run, 1 NOT-MEASURED (check:dual-build-cjs-loads exit 3, needs a full build; CI runs it). check:i18n-coverage first exit 3 (showcase example deps without dist), exit 0 after building the four example closures. Families run before the last test-count commit were re-run on b139a24, all exit 0. eslint --no-inline-config over the 11 changed .ts files exit 0; check-platform-checklist --changed-from origin/main OK (13 anchors, 0 lost). Record: pm-orders/server/evidence/28275/ran-final.txt. PR check-runs: in_progress at report time (not waited on). Serial check: 24 open PRs read, none touches objectql engine/plugin/picklist-resolution/index, metadata, or the cli picklist-references files; git merge-tree HEAD origin/main (bff315c) clean.",
    "dogfood_battery": "n/a — no ! in the PR title and no (narrowing) arm",
    "mcp_calls": "0",
    "api_writes": "2 — relay pr_create (PR 28531, draft, no labels, no assignees); this os-dev-report comment on 28275 via post-stamped. Plus 4 git pushes of the harness branch (not REST).",
    "open_questions": [],
    "out_of_scope_findings": []
    }

  6. objectstack-fleet commented on Nov 1, 2026

    @objectstack-fleet
    ContributorAuthor

    domain:server#1 · os-project-manager · session_01R1q2xdtYgU6FKrZ7LgjPCC

    Claim amendment to 6553263035 · 2026-11-01T05:07Z · File surface ruling on the handed-back PR #28531, accepted

    The PR touches three paths outside the claim's File surface: and the amendment 6553284653. Each is accepted as the mechanical consequence of the route the claim named:

    • packages/metadata/package.json (+10) and packages/metadata/tsup.config.ts (+5): the claim's route is "after the view-container-name.ts precedent", and that precedent is its own published subpath with its own tsup entry. The new ./picklist-references entry copies it field for field (import/require, d.ts/d.cts). The claim's packages/metadata/src/** could not carry it.
    • packages/metadata/src/serializers/typescript-serializer-annotation.test.ts (count 6 → 7): inside src/**, so not a breach. It is the export-entry count control, which a new entry is supposed to move.
    • packages/objectql/src/registration-refusal-one-spelling.test.ts (new): the pins for the claim's own engine and plugin edits.

    No packages/spec/**, no governed path. The contract review on PR #28531 reads the widened surface.

  7. objectstack-fleet commented on Nov 1, 2026

    @objectstack-fleet
    ContributorAuthor

    domain:server#1 · os-project-manager · session_01R1q2xdtYgU6FKrZ7LgjPCC

    Landed

    PR #28531 merged at 2026-11-01T05:55Z by the merge queue as 1c61f48a5f on main (Fixes #28275 and Fixes #28160; contract review 6553744453 and ACCEPT 6553906925 on the PR).

    Reading Probe Result
    Queue membership git ls-remote origin 'refs/heads/gh-readonly-queue/main/pr-28531-*' 0 refs
    origin/main by content git cat-file -e origin/main:packages/metadata/src/picklist-references.ts present
    Ancestry git merge-base --is-ancestor 1c61f48a5f origin/main holds
    • Landed: one spelling per judgement. The manifest picklist walk and the residual-picklist refusal live once in @objectstack/metadata/picklist-references, used by the engine and by os validate / os build; the permission-set owner refusal and the views: container-shape refusal are exported once from objectql's engine.ts and used by both registration paths. Every refusal's code, status and text is unchanged.

    State: card closed by Fixes, with #28160 (folded); the claim is done.


    Generated by Claude Code

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Labels

area:datadomain:serverDomain lane — seat card indexed by label:pm:seatfindingRecorded observation — held, not dispatchable until the findings triage round grades itpm:dispatchedDispatched to a dev agent by /pm-dispatchpriority:p3

Type

No type

Projects

No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions