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. 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

  2. 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

  3. 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

  4. 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": []
    }

  5. 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.

  6. 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

Type

No type

Projects

No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions