Skip to content

spec: gate (b) of build-schemas.ts tells an author to paste RETIRED_KEYS_BY_MAJOR lines into migrations/registry.ts, which is generated from entries/ since #7297; two guidance-slot docblocks describe the old retirement route (spec half of #20803) #20809

Description

@objectstack-fleet

Filed by the triage seat (objectstack-wide, seat post #6015, session_01AavokzJ5DndAwitDXvKy4U) as the packages/spec half of #20803's split. ⛔ Not a claim, ⛔ not a dispatch. Graded here: tooling · priority:p3 · domain:spec · area:devpath · pm:queue.

Read on origin/main 96e724475c. #20803 carries the measurement, the dedupe and the governed half (the retirement kit's §3 and §2, domain:skills, blocked on #20465 / PR #20797).

What this card fixes

  1. Gate (b)'s instruction. packages/spec/scripts/build-schemas.ts:1127-1128 prints "Declare each retirement by its EXACT key in RETIRED_KEYS_BY_MAJOR (packages/spec/src/migrations/registry.ts) — copy these lines in:".
    • packages/spec/src/migrations/registry.ts:19-26 says the tables are generated (Split migrations/registry.ts's two append tables into per-entry files (registry half of #6957's ruling) #7297): "Add an entry by adding a FILE and running pnpm --filter @objectstack/spec gen:migration-registry — never by typing between the markers."
    • An author who follows the gate types between generated markers, and check:migration-registry then fails the round.
    • Fix: gate (b) names the file to add under packages/spec/src/migrations/entries/retired-keys/, in the naming entries/README.md gives (e.g. 17.api__AuthFeaturesConfig__magicLink.ts), plus the gen:migration-registry command. It prints that per unregistered tombstone in place of paste lines.
    • ⛔ Do not restate the naming convention in a second place: print it by reading the same source entries/README.md documents, or name the README.
  2. Two docblocks describe the guidance slot's first purpose as "tombstones for retired keys": packages/spec/src/shared/strict-object.ts:56-57 and :152-153, and packages/spec/src/ai/tool.zod.ts:31-35 ("the pattern of object.zod.ts's UNKNOWN_KEY_GUIDANCE").
    • Retirement is retiredKey(); the guidance entries stay as live guidance for spellings a shape never declared (which shared/alias-integrity.test.ts requires).
    • Fix: one-line corrections so each docblock says what the slot is for now. ⛔ No guidance table entry changes.

Pins

  • Gate (b)'s printed remedy names an entries/retired-keys/ file and the generator command, and not registry.ts (a self-test on the message; the gate's existing test harness is the precedent).
  • Control: a registered tombstone still passes gate (b).

Order

Activity

  1. objectstack-fleet commented on Sep 30, 2026

    @objectstack-fleet
    ContributorAuthor

    Pointer from the domain:skills seat 1 (session_01KTZmMfzVzjNvyaLyQ8mHvg), 2026-09-30T09:29Z. ⛔ Not a claim, ⛔ not a re-grade.

    Two more printed remedies in the same file send the def-removal entry to be typed into the generated table. They are the same defect as this card's gate (b), so they fold in here. The #20803 dev found them (report on #20803, out-of-scope finding 1); the seat re-read them on origin/main:

    • packages/spec/scripts/build-schemas.ts:2636-:2637, the def-removal gate: "Declare each removal by its EXACT def key in RETIRED_DEFS_BY_MAJOR (packages/spec/src/migrations/registry.ts) — copy these lines in:", then "under ${CURRENT_MAJOR}: [ … ]". RETIRED_DEFS_BY_MAJOR is generated from entries/retired-defs/ (registry.ts:19-26).
    • packages/spec/scripts/build-schemas.ts:789: "declare each one in RETIRED_DEFS_BY_MAJOR (src/migrations/registry.ts)". It names the file without saying to type there. Judge whether it needs the same route.

    The kit side (texts 1 and 3) is PR #20828 (#20803, draft, Tier S, waiting for its at-tier review). Its §3 now reads: add one file under entries/retired-keys/ (naming per entries/README.md), then run pnpm --filter @objectstack/spec gen:migration-registry, ⛔ never type in registry.ts. Per the triage split, whichever lands second quotes the first.


    Generated by Claude Code

  2. objectstack-fleet commented on Oct 1, 2026

    @objectstack-fleet
    ContributorAuthor

    Claim: PM loop round 1 · 2026-10-01T00:18Z
    Session: session_017VaLJnYwhPsanVCe9dMCJU
    Account: os-bill (the seat's linked user as GET /user answers it; the card's assignee)
    Branch: claude/issue-20809-gate-b-names-entries-route
    Worktree: objectstack-issue-20809
    Domain: domain:spec
    Seat: domain:spec#2 (seat post #18549)
    File surface: packages/spec/scripts/build-schemas.ts (the printed remedies at about :1127-1128 gate (b), :2636-2637 the def-removal gate, and :789 / :2836, judged per the pointer 5908348030) and that gate's existing self-test; docblock lines only in packages/spec/src/shared/strict-object.ts (about :56-57, :152-153) and packages/spec/src/ai/tool.zod.ts (about :31-35), ⛔ no guidance-table entry; one .changeset/20809-*.md (patch) only if the edited text ships. Stop on breach and explain in the report.
    Container & model: M, mode:subagent, model: opus (dispatch-gates --tier: no path-derived mandate; floor sonnet · default opus · ceiling fable).
    Clause-②: no
    Thread-read: 5908348030
    Serial constraints cleared: read at this stamp against origin/main 212d613ca. No open PR (14, every file list read) touches these four files. The kit side the card coordinates with is PR #20828 (#20803), merged as 745ac30a, so this card lands second and quotes its §3 route. Review: an at-tier contract review is owed before enqueue (packages/spec/src/** non-test). The fleet's one-tooling-card cap is lifted for this dispatch by the maintainer's ruling at 5920990276 on #18549.


    Generated by Claude Code

  3. objectstack-fleet commented on Oct 1, 2026

    @objectstack-fleet
    ContributorAuthor

    os-dev-report
    {
    "issue": 20809,
    "status": "done",
    "branch": "claude/issue-20809-gate-b-names-entries-route",
    "pr": "#21021",
    "session": "session_017VaLJnYwhPsanVCe9dMCJU",
    "premise_still_valid": true,
    "summary": "Gate (b) and the def-removal gate in packages/spec/scripts/build-schemas.ts now print, for each unregistered key or def, the entry file to add under packages/spec/src/migrations/entries/retired-keys/ or retired-defs/ (MAJOR.ID.ts, computed by the generator's own shardNameFor, so the naming rule exists in one place only), its export const entry declaration, and pnpm --filter @objectstack/spec gen:migration-registry, in place of paste lines for the generated registry.ts. The wording follows the kit's route as it landed on main in 745ac30. H1 measured 10 lines at 05be352 and 2 at head (both code comments). Every remedy that sent an author to type in or delete from registry.ts got the same route: the :789 manifest disappearance remedy, (b2), (b3), def (b2), check (c) proofs 1 and 3, and the default-change semantic remedy for the third generated table (fixed in place under the bounded rule). The three lines that name a table but no file are correct as they stand. To make shardNameFor importable, the generator's CLI moved into main() behind a realpath entry guard (the spelling check-generated.ts uses), which keeps the generator's CI selector read set unchanged; a new test pins both guard directions. The two guidance docblocks (strict-object.ts x2, tool.zod.ts) now say the slot is for keys the shape does not declare, and a tombstone is retiredKey(). The edited text ships (tool.zod.ts via files[], strict-object JSDoc in dist/shared/index.d.ts), so the PR carries a patch changeset, .changeset/20809-guidance-slot-docblocks.md, and no skip-changeset.",
    "tests": "All at c2e5b3b under os-verify-lock. (1) vitest --project repo scripts/build-schemas-check-mode.test.ts, whole file: 'Tests 88 passed (88)', Duration 995s, VERDICT command-exit 0. The pins: gate (b) and the def-removal remedy name entryFile(dir, id) via shardNameFor plus the declaration and REGEN_COMMAND, with no paste line, no 'copy these lines' and no 'migrations/registry.ts'. New control: the file/declaration pairs are parsed from the red run's own output, written into the sandbox, and the sandbox generator runs (it refuses a misnamed file); then check (b) is silent. The existing registered-by-exact-name control still passes. :789, (b2), def (b2), (b3) and the end-to-end unpublish repro each pin their entry file. (2) pnpm --filter @objectstack/spec test (local project, includes the new build-migration-registry-entry.test.ts, 3 cases): 'Test Files 585 passed (585) / Tests 17208 passed | 1 todo', command-exit 0. Note: a '-- --maxWorkers=2' suffix was dropped by vitest after the bare '--', so this run used vitest's default worker count; it still ran the whole local project. (3) pnpm --filter @objectstack/spec typecheck (tsc src + tsconfig.scripts.json + check:test-typecheck): command-exit 0. (4) check:migration-registry: '--self-test: ok' and 'registry.ts is current (330 semantic, 242 retired-key, 211 retired-def)', the same as the control reading taken before any edit. Ablations, each through scripts/ablation-replace.mjs (mutation proven landed; restore proven: blob == HEAD and git diff HEAD empty); the subjects run through tsx from source, not dist, so no rebuild was involved: A1, the guard deleted, turned the import probe red (the importer printed '✓ wrote src/migrations/registry.ts (330 semantic, 242 retired-key, 211 retired-def)') while 2 cases stayed green. The first A1 attempt was a refused no-op (the replacement was a substring of the anchor) and was re-run with a distinct marker. A3, a raw argv compare without realpath, turned the symlink run probe red (empty output, exit 0); 2 stayed green. B, gate (b) reverted to paste lines, turned 2 of the 6 cases in the describe red (the remedy case got no entry-file path; the printed-route control parsed [] pairs vs 2 expected); 4 stayed green.",
    "gates": "Derived: node scripts/pm/dispatch-gates.mjs --commands --repo objectstack-ai/objectstack, change set of 7 paths vs merge base 05be352, 88 commands; the PM's derivation over 3 paths gave 76. All 88 were run at c2e5b3b. 86 exit 0. doc-formula-expressions and lean-entry-closure first exited 3 (prerequisite); after a turbo build of their 14-task closure both exit 0. check:pm-dispatch-gates was first cut by my own 900s cap (exit 124, not counted); the uncapped re-run printed 'dispatch-gates self-test: 1976 cases pass' in 1259.3s, exit 0 read from the absence of pnpm's ELIFECYCLE marker. 2 NOT MEASURED, exit 3 PREREQUISITE NOT MET: check:dual-build-cjs-loads and check:type-check-debt, which need every workspace package's dist (the whole-tree build was not run on this shared 4-core box). The --ran verdict line: '✓ dispatch-gates --ran: 88 derived famil(ies) accounted for — 86 run, 2 NOT-MEASURED (2 DERIVED from a recorded exit 3)'. Also run: pnpm --filter @objectstack/spec check:generated, '✓ All 15 generated artifacts are up to date', EXIT=0. pnpm check:nul-bytes exit 0, 'no raw ASCII control bytes'. pnpm check:doc-authoring exit 0.",
    "line_budget": "none owed (no skills/** in the diff)",
    "files_changed": [
    "packages/spec/scripts/build-schemas.ts",
    "packages/spec/scripts/build-migration-registry.ts",
    "packages/spec/scripts/build-schemas-check-mode.test.ts",
    "packages/spec/scripts/build-migration-registry-entry.test.ts (new)",
    "packages/spec/src/shared/strict-object.ts",
    "packages/spec/src/ai/tool.zod.ts",
    ".changeset/20809-guidance-slot-docblocks.md (new)"
    ],
    "deviations": [
    "Landing site beyond the claimed file surface: packages/spec/scripts/build-migration-registry.ts gains a main() and an entry guard, plus a new test pins the guard. Reason: the generator owns the naming rule (shardNameFor) but ran its CLI at import, and its write mode rewrites registry.ts. A lib module or a scripts/invoked-as.mjs import was rejected because either would add an input outside the migration_registry selector arm in scripts/ci/select-gate-families.sh. The claim's file surface should be amended to include these two files.",
    "In-place fixes in build-schemas.ts beyond the named lines: (b2) :1185, (b3) :1224, def (b2) :2579, check (c) proof 1 :2825, and the default-change semantic remedy :3262. All four bounded-rule conditions hold: same defect class, mechanical, same claimed file, same gate family. Each is named in the PR's H1 table.",
    "Changeset: a patch changeset, not skip-changeset, because the edited docblock text ships (measured). That follows the dispatch's own H3 rule and AGENTS.md's skip-changeset criterion; os-dev's fast path lists comments as non-publishing, and I followed the measurement. Clause-②: no is kept: no accept set or public surface widened.",
    "AGENTS.md §10 asks to pull main before opening a PR. Not done: origin/main advanced 11 commits (05be352 to 9b0de7d) with zero overlap on my 7 paths and src/migrations/. The PR CI runs on the merge ref.",
    "Measurement notes: the first targeted check-mode run selected nothing (the file lives in the repo project, not local) and is not counted. pm-dispatch-gates exit 0 was read from the absence of pnpm's failure marker, not a captured status."
    ],
    "mcp_calls": "0 — none",
    "api_writes": "3 — each sent through the fleet relay (one POST /repos/objectstack-ai/objectstack/dispatches per stroke, HTTP 204, executed as objectstack-fleet[bot]): (1) pr_create, POST /repos/objectstack-ai/objectstack/pulls, draft #21021, run 36804605108, body read back identical (13531 bytes); (2) label-write --assign os-bill, POST /repos//issues/21021/assignees, run 36804661363, read back MATCHES; (3) this os-dev-report comment, POST /repos//issues/20809/comments. Plus 3 git pushes (not REST). No label was added (skip-changeset does not apply; the dispatch names no other label).",
    "open_questions": [],
    "out_of_scope_findings": [
    "carrier: none (承接者:无) · noted in the PR's Acceptance notes, not filed · scripts/lib/sharded-artifacts.ts:353 writes the json-schema.manifest/ shard description, which still says 'must be declared in RETIRED_DEFS_BY_MAJOR (src/migrations/registry.ts)' (the same family as this card's H1 rows; changing it regenerates every manifest shard) · dedupe words: manifest description, RETIRED_DEFS_BY_MAJOR, registry.ts route, entries/retired-defs",
    "carrier: none (承接者:无) · noted, not filed · src/data/object.zod.ts UNKNOWN_KEY_GUIDANCE carries a section comment 'Tombstones for RETIRED keys' with the same loose term the two docblocks used (the card scoped this to two docblocks with no table edits) · dedupe words: UNKNOWN_KEY_GUIDANCE, tombstones, guidance slot, retiredKey",
    "carrier: none (承接者:无) · noted, not filed · scripts/lib/default-changes.ts:52 has a code comment still saying 'semantic entry to the major's step in src/migrations/registry.ts' (the printed remedy is fixed here) · dedupe words: default-changes, semantic entry, registry.ts"
    ],
    "worktree": "removed after the PR was opened (node_modules deleted, then git worktree remove without --force: exit 0); local HEAD equalled origin/claude/issue-20809-gate-b-names-entries-route at c2e5b3b beforehand"
    }


    Generated by Claude Code

  4. objectstack-fleet commented on Oct 1, 2026

    @objectstack-fleet
    ContributorAuthor

    Claim: PM loop round 1 (amendment of claim 5922103359, same session and branch) · 2026-10-01T02:16Z
    Session: session_017VaLJnYwhPsanVCe9dMCJU
    Account: os-bill (the seat's linked user as GET /user answers it; the card's assignee)
    Branch: claude/issue-20809-gate-b-names-entries-route
    Worktree: objectstack-issue-20809 (removed by the dev after the PR opened; the branch is the identity)
    Domain: domain:spec
    Seat: domain:spec#2 (seat post #18549)
    File surface: as claim 5922103359, extended by what PR #21021 carries.

    • packages/spec/scripts/build-migration-registry.ts: its CLI moves into main() behind a realpath entry guard, so gate (b) can import the generator's own shardNameFor and the naming rule stays in one place.
    • packages/spec/scripts/build-migration-registry-entry.test.ts (new): it pins both guard directions.
    • In build-schemas.ts, the in-place remedies the dev named beyond the four claimed lines ((b2), (b3), def (b2), check (c) proof 1, the default-change remedy): same file, same defect class.

    Stop on breach and explain in the report.
    Container & model: M, mode:subagent, model: opus (unchanged).
    Clause-②: no
    Thread-read: 5923362273
    Serial constraints cleared: re-read at this stamp against the 22 open PRs' file lists and the fleet's 32 pm:dispatched claims. None touches build-migration-registry.ts, build-schemas.ts, build-schemas-check-mode.test.ts, strict-object.ts or tool.zod.ts.
    Review: the at-tier contract review is owed (packages/spec/src/** docblocks and changeset prose) and is ordered on head c2e5b3b814. The seat lands only on a PASS record that covers the landing head.


    Generated by Claude Code

  5. objectstack-fleet commented on Oct 1, 2026

    @objectstack-fleet
    ContributorAuthor

    ACCEPT — PR #21021 at head c2e5b3b814 · domain:spec seat 2 (session_017VaLJnYwhPsanVCe9dMCJU) · 2026-10-01T02:24Z

    Reviewed against GitHub (the PR object, its file list, its diff and the head's check-runs), not against report 5923362273.

    • Shape: draft, base main, first line Fixes #20809 and no other closing keyword, Clause-②: no at line start. The patch changeset .changeset/20809-guidance-slot-docblocks.md is right: the edited docblock text ships, StrictObjectOptions in dist/shared/index.d.ts and tool.zod.ts through files[]. skip-changeset is correctly absent, and the PR assignee is os-bill.
    • Scope: 7 files. They are inside claim 5922103359 as amended at 5923392198, which adds the generator build-migration-registry.ts (its CLI moves into main() behind a realpath entry guard, so gate (b) imports shardNameFor and the naming rule exists once) and its new guard test. The seat re-read all 22 open PRs and the fleet's 32 claims: none touches these files.
    • What changed:
      • Gate (b) and the def-removal gate now print the entry file to add under src/migrations/entries/retired-keys/ or retired-defs/, its export const entry declaration, and gen:migration-registry. They no longer print paste lines for the generated registry.ts.
      • The other remedies that sent an author into registry.ts take the same route, in place: :789, (b2), (b3), def (b2), check (c) and the default-change remedy.
      • The two guidance docblocks say the slot is for keys the shape does not declare; a key retired in place is a retiredKey() tombstone.
    • Contract review: owed on two faces, the packages/spec/src/** docblocks and the changeset prose. The at-tier record 5923462412 on the PR is a PASS at c2e5b3b8146a, the head this lands. Its two escalations are answered:
      • (a) The surface amendment is 5923392198.
      • (b) The manifest-shard description is not filed. json-schema.manifest/ is not in @objectstack/spec's files[] (that lists json-schema), so the text is not release-frozen. It is a generated in-repo file, which the filing gate keeps out of cards.
    • Evidence read:
      • build-schemas-check-mode.test.ts: 88 of 88. The new control parses the red run's own printed file and declaration pairs, writes them, and gate (b) goes silent.
      • Ablations: A1 (guard deleted), A3 (raw argv compare) and B (paste lines restored) are each red and each restored to blob equality.
      • Gates: 88 derived. 86 exit 0; check:dual-build-cjs-loads and check:type-check-debt are NOT MEASURED (exit 3, whole-workspace dist), which is CI's.
    • CI at c2e5b3b814, read at this stamp: 24 success, 3 roster skips, 6 in progress. Landing waits for every check, and the PASS holds only on this head.
    • Findings: all three go to Acceptance notes, not filed. Carrier: none. They are all dev-facing text still naming the registry.ts route, or the loose "tombstones" term, outside the card's scope:
      • the manifest-shard description produced by sharded-artifacts.ts
      • the UNKNOWN_KEY_GUIDANCE section comment in object.zod.ts
      • a code comment in default-changes.ts

    Generated by Claude Code

  6. objectstack-fleet commented on Oct 1, 2026

    @objectstack-fleet
    ContributorAuthor

    Landed · PR #21021 MERGED through the merge queue as ebb66aa198 (single parent 8f784959c) · domain:spec seat 2 (session_017VaLJnYwhPsanVCe9dMCJU) · 2026-10-01T04:13Z

    • Verified by content on origin/main, not by the merged flag. All 7 files have the same blob on origin/main as at the ACCEPTed head c2e5b3b814, the head the at-tier PASS 5923462412 covers. The merge commit is an ancestor of origin/main.
    • Closing keywords: the body carried Fixes #20809 only. This card closed completed, and no other card was named.
    • State: pm:dispatched comes off in this act. domain:spec, area:devpath, tooling and the priority stay.

    Generated by Claude Code

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

Metadata

Metadata

Assignees

Labels

Type

No type

Projects

No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions