docs(spec): re-anchor the dead tracker citations in ui/ and two freed sites to the commits that decided them (stage 5) - #20576
Conversation
… sites to the commits that decided them (stage 5) Comment and docblock lines only. Each line that cited a tracker number answering 404 now cites the commit on main that decided what the line describes, or ADR-0087's own amendment where the line quotes it. Two sibling pairs are respelled so each number carries its own qualifier (objectui#6110 + objectui#6111, objectui#8221's PR objectui#8758). No code token moves; every file keeps its line count. Claude-Session: https://claude.ai/code/session_014EJ1ED8X4MMrT18BhVx4tx Co-authored-by: Claude <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_014EJ1ED8X4MMrT18BhVx4tx Co-authored-by: Claude <noreply@anthropic.com>
…e-anchored docblock Generated by `pnpm --filter @objectstack/spec check:generated --fix`, which proved only this page stale; never hand-edited. Claude-Session: https://claude.ai/code/session_014EJ1ED8X4MMrT18BhVx4tx Co-authored-by: Claude <noreply@anthropic.com>
Brings in the landed citation-qualifier grammar (scripts/check-issue-citations.mjs) so the derived gates run against it; no file of this diff moved on main. Claude-Session: https://claude.ai/code/session_014EJ1ED8X4MMrT18BhVx4tx Co-authored-by: Claude <noreply@anthropic.com>
📓 Docs Drift CheckThis PR changes 1 package(s): 2 hand-written doc(s) NAME something this change touched and may need an implementation-accuracy re-verification:
⛔ 6 release-owned page(s) also name something this change touched. These are read-only:
What this run could not see
Coarse fallback — 137 page(s) merely mention a changed package (the pre-#9192 predicate, kept for the deliberately-wide backstop): Which tree this was computed onThis run read A worktree cut from an older # while this PR is open — GitHub drops the merge commit once it closes
git fetch origin 5282ad8d830a1f5006264885f9baff5802cc5a5a && git checkout 5282ad8d830a1f5006264885f9baff5802cc5a5a
# afterwards, rebuild it from the two parents, which stay fetchable
git fetch origin f572a7eb3c272a5be85e3ec64d2516c944c3b243 1b885d3c277b668ac4d9c1533b65dc436204ed2a && git checkout -B drift-repro f572a7eb3c272a5be85e3ec64d2516c944c3b243 && git merge --no-ff 1b885d3c277b668ac4d9c1533b65dc436204ed2a
node scripts/docs-audit/affected-docs.mjs --json f572a7eb3c272a5be85e3ec64d2516c944c3b243
|
Contract reviewServed-tier: Read: card #20234 (body; every comment: triage ① Derived judgments(a) Scope and file surface: right. 27 files: 23 (b) Comment-only, no test string or code token moves: right. (c) Numbers: right. Over the whole diff, added-minus-removed tracker numbers is empty for every one of the 27 files; net-removed is exactly the dev's 25 numbers, 87 sites (85 in the (d) Anchor truth: right, 23 of 23. 23 distinct sha-shaped tokens stand on added lines and none on removed lines (the
(e) (f) The three respellings: right. (g) The generated page: right. (h) Form C over the whole diff: right. Each rewrite leads with ② Semver level
③ Boundary flagsBlocking: none. Dev deviations, each answered:
Non-blocking, each true of its commit: (1) Escalated: none. CI at this head, the judging read at 2026-09-29T04:31Z: 32 check-runs, 16 success, 2 skipped ( Implemented-by: VERDICT: PASS Generated by Claude Code |
Part of #20234
Clause-②: no
What changed
This is stage 5 of the staged sweep: the
ui/area (packages/spec/src/ui/**, 133 files), plus two sites freed since stage 4:data/filter-subtree-provenance.ts(PR #20460 landed without touching it) andmeta-spelling/manifest-collection-spelling.ts(the census hand-over, comment 5882628946 on #20234).ui/view-grouping-query.tsis excluded because #20446's claim holds it; it carries 4 citations and none of them is dead, so the exclusion removes nothing. Later stages cover the other areas, so this PR saysPart of.Every comment and docblock site in that population that cites a tracker number answering 404 has been rewritten in ruling C+D's form C (comment 5749154545 on #19123). That is 87 comment sites: 84 re-anchored and 3 respelled.
origin/mainhistory that decided what the line describes, and says in its own words what that commit decided. One line (ui/dashboard.zod.ts:686) quotes ADR-0087 itself; it keeps ADR-0087 as its citation and paraphrases the amendment heading instead of quoting its number.ui/view.zod.ts:3634now readsobjectui#6110 + objectui#6111, andui/component.zod.ts:3479and:4140now readobjectui#8221's PR objectui#8758. Each second number answers 404 here, and the sentence attributes it to objectui (objectui REST:issues/6111200,pulls/8758200, merged 2026-09-09).Only comments changed, plus the one generated reference page they project into and a patch changeset. Every source file keeps its line count (90 lines out, 90 in, over 25 files). Three of the 90 lines held no dead number; each is the other half of a rewritten sentence:
ui/action.zod.ts:400,ui/action-param-carryover.test.ts:13andui/expression-bindable-text-keys.test.ts:119. No code token moves (see the guard below).No tracker number is added. Every tracker number on an added line was already on the lines it replaces, and no
PR #Nis added.Census: before and after
Instrument. This is the instrument of stages 1 to 4, rebuilt for this stage. It sends REST
GET /repos/objectstack-ai/objectstack/issues/Nwithout following redirects, for every distinct number cited in the population. The population is:CITATION_REandNON_CITATION_HEADSat the base, kept when the qualifier is none,objectstack,objectstack-ai/objectstack,framework,pre-orpost-;Pre-,POST-,Framework);summonheads.A qualifier covers only the number it is joined to. Each site is classified by the TypeScript parser as a line comment, a docblock, a block comment or a string.
Controls. The lit controls were
#16862,#16847and#17698. The dead controls were#16714,#16715and#16697. They were probed at the start, after every 100 numbers and at the end: 18 of 18 lit (200) and 18 of 18 dead (404) over 6 checkpoints in the base run, and 15 of 15 and 15 of 15 over 5 checkpoints in the head run.487a7846df, probed 2026-09-29T02:57:01Z to 02:59:36Z83e39641d0, probed 2026-09-29T03:15:00Z to 03:18:06ZThe head probe found no number newly dead since the base probe: the same 372 numbers answer 200. The head was probed at
83e39641d0; every census file is byte-identical at the final head.Cross-check under the grammar that landed during this stage. PR #20554 (
199002b3e4) landed the closed qualifier set while this stage ran, and it readsobjectui PR #8758as objectui's number. Re-run with that gate's ownextractCitationsandnamesThisRepository, the same population reads 108 dead sites before and 21 after, all 21 test strings. The difference is exactly the threeobjectui PR #8758prose sites below, which that PR's own header measured as "census deaths here that are not deaths at all".Per file. Cited sites are every in-repo citation the population reads, live or dead.
data/filter-subtree-provenance.tsmeta-spelling/manifest-collection-spelling.tsui/action-param-carryover.test.tsui/action.test.tsui/action.zod.tsui/bulk-action.test.tsui/bulk-action.zod.tsui/component-element-navigation-17987.test.tsui/component-type-vocabulary.test.tsui/component-type-vocabulary.tsui/component.test.tsui/component.zod.tsui/dashboard.zod.tsui/expression-bindable-text-keys.test.tsui/expression-bindable-text-keys.zod.tsui/form-select-option.test.tsui/index.tsui/interaction-config-retirement.test.tsui/react-blocks.test.tsui/react-blocks.tsui/view-form-features-root.test.tsui/view-metadata-schema.test.tsui/view-submit-redirect-url.test.tsui/view.test.tsui/view.zod.tsui/widget-i18n-retirement.test.tsui/alone went from 106 dead sites in 24 files to 24. The other 107ui/files carry no dead site.Per-number table
Anchors are 9-hex commit abbreviations. "Wrote" means the commit's own diff added the line being rewritten.
#5970action.zod.ts:819,action.test.ts:268,:304,:35497e7e3caa:ActionSchema.visible/disabledspeak one condition shape;visiblegains its boolean arm. Stage 1's anchor for the same number#6276component.zod.ts:34,:165,:568,:2455,:2546,:2554,component.test.ts:212678f0be872: declareselement:record_picker's flatsort/limiton the #5611 rule (maintainer ruling 2026-08-08, direction A). It wrote:34,:2455and the "enumerate by the renderer's read pattern" lesson#8794,#8836filter-subtree-provenance.ts:130,:131,:1561850ebbb0: corrects the reuse-safety claim from the survey and pins the invariant. It wrote:131itself. Stages 1 and 3 gave both numbers this anchor#9933view.zod.ts:2517,:5060,:5086,:5118,:5513,view-metadata-schema.test.ts:398,:410d5552ca13: admitscolumnStateas an explicitly runtime-only view-overlay key, rejected by name at every authoring door. It wrote "explicitly out of #9933's scope"#9972component.zod.ts:2213,component.test.ts:382,:3565; also:3612's#9881/#9972, a slash-joined spelling the grammar does not read60e0f900a: records the live read point ofpage:tabsitems[].iconand its accept-pin. It wrote the:382header#10194manifest-collection-spelling.ts:71(pre-#10194)2306a765c:/meta/themeand/meta/analytics_cubestop storing any JSON as success and validate at the write door. The line now says "the store-anything branch from before commit 2306a76". Stage 1's anchor#10274component.zod.ts:2304,component.test.ts:308,:405,:3591,:3603,:3612d1ba685ec: re-measures the four pin citations and gates the class. Its gate header records that the re-measure found two anchors wrong since they were written, which is why a refresh re-reads. Stage 3's anchor#10485index.ts:51,interaction-config-retirement.test.ts:116,widget-i18n-retirement.test.ts:112,manifest-collection-spelling.ts:6735ad101bc: retires thethemescarrier andThemeSchemawhole (ruled B, 2026-08-21; ADR-0049 stays cited). Stage 1's anchor#11284react-blocks.ts:39,:94,:109,:295,react-blocks.test.ts:1395383fa670: the react tier converges on the metadata-tier vocabulary, deprecate-first. Its changeset heads "(#11284, maintainer ruling 2026-08-23)"#11350index.ts:105ece4dad31: records the maintainer ruling of 2026-08-23 that a type in an entry's public declarations must be nameable from that entry. Same wording as stage 1'skernel/index.ts:53#11507component.zod.ts:1465,component.test.ts:272688b9d749a: declaressys_activity.typean open, author-extensible vocabulary (maintainer ruling 2026-08-24, direction 4). Stage 3's anchor#11658component.zod.ts:1464,component.test.ts:27251a6a19c31: opensRecordActivityProps.typesto author-contributed kinds, executing that ruling. Stage 3's anchor#11703action.zod.ts:399to:400,:460,action-param-carryover.test.ts:12to:135cb62d88b:clone_permission_setcarries all five copied facets; its params list had silently dropped three. The lines now name "the silent-drop shape commit 5cb62d8 fixed"#11753action.zod.ts:66,:390,:398,:409,action-param-carryover.test.ts:10e4e51b0a:ActionParamSchema.carryOver, the spec half of the 2026-08-25 maintainer ruling (recommendation A). It wrote every one of these lines, and its changeset records thevisible: falsemeasurement:398names#12194view.zod.ts:4838311433f6b: declares the metadata item-name grammar (QUALIFIED_ITEM_NAME_PATTERNamong it) and refuses it at the publish door. Stage 2's anchor#12868view.zod.ts:2938,:2966,:3179,:7087,form-select-option.test.ts:4c459da6bc: narrows the per-optiondefaultkey out of the form-view options vocabulary. Its changeset records the ruled census:2966cites ("measured ZERO occurrences"). Stages 3 and 4's anchor#12950component-type-vocabulary.ts:4,component-type-vocabulary.test.ts:4,:101225e7690f: createdcomponent-type-vocabulary.ts; its message records the readiness read:101pins (global:searchandglobal:notificationsstay declared)#13156view-form-features-root.test.ts:70,view-submit-redirect-url.test.ts:110fd289be45: strips tracker ids from function-declaration-built refusal prose. It wrote both lines. Stage 3's wording ("commit fd289be's strip")#13670expression-bindable-text-keys.zod.ts:728c6a7fc0b: recordstext.valueas deliberately omitted; its message states the ruling thattext's evaluation channel iscontentalone#13672expression-bindable-text-keys.zod.ts:89,.test.ts:65,:118e854a531a: narrows thebuttonrow to the spelling its key reaches, and recordsaction:buttonandui:buttonas deliberately out#16626component.test.ts:233630b099078: the objectui pin bump to53ded82bf7a4that ships objectui#7754's array-analytics lowering, the door the family waited on. The association is PR #16788's body (it names #16626 as the card it lands), and30b099078is that PR's merge commit; neither its message nor its diff names #16626 (the stage-3 #11065 precedent)#17987component.zod.ts:10,:4014,:4062,:4153,:4193,:5068,:5226,:5457,component-element-navigation-17987.test.ts:4e233db9db: declares element-levelnavigationonobject-kanban/object-calendarand givesobject-timelineitsComponentPropsMaprow, executing the objectui#8652 ruling (verbatimB)#18003dashboard.zod.ts:686#18177bulk-action.zod.ts:51,:169,:262,bulk-action.test.ts:61,:307adabccf5f:BulkActionParamSchemais strict and declaresdependsOn, executing decision batch #146 item 4, letter A#6111view.zod.ts:3634objectui#6111(not re-anchored): it is objectui's number#8758component.zod.ts:3479,:4140PR objectui#8758(not re-anchored): objectui's PR #8758, merged 2026-09-09No ADR or ruling-record file in
docs/adr/orscripts/adr-anchors/records the decision behind any of the 25 re-anchored numbers except #18003. ADR-0126 mentions #11703 and #11753 only as references ("permission-set precedent"), not as the record of either decision.Anchor checks. Every sha on an added line is one of 23, and none is on a removed line. At the base
487a7846df:git rev-parse --disambiguate, count 1, 23 of 23);git merge-base --is-ancestor, exit 0, 23 of 23); the control lege9584681a4also exits 0, and the repository is not shallow;0e4e51b0a,5383fa670,c459da6bc,225e7690f,e854a531a, and for [finding] The filter-subtree provenance negative holds only incidentally — nothing states or tests "a vouchable filter must not outlive its request", andgetReadFilterhands hosts the exact reusable shape #8836 in1850ebbb0).30b099078is the exception explained in the table.Wordings to check, each true of its commit:
filter-subtree-provenance.ts:130and:156read 「survey commit 1850ebb records」: the survey was the card's, and the commit's message records its measurement. It is stage 3's wording for the same relation (「from the survey it records」).component.zod.ts:1465andcomponent.test.ts:2726read 「maintainer ruling commit 88b9d74 declared」: that commit landed the ruling (direction 4) as thesys_activity.typedeclaration.manifest-collection-spelling.ts:71reads 「the store-anything branch from before commit 2306a76」: before that commit,PUT /meta/theme/:namestored any JSON as success.Mechanical guard: no code token moves
The check compares leaf tokens with comments stripped, base
487a7846dfagainst the head. It uses the TypeScript parser's leaf tokens from the head's lockfile, so template literals are scanned in context, and it excludes JSDoc nodes. It ran over all 25 touched.tsfiles, and every control mutates the head text in memory only.ui/index.ts): 0 files changed (exit 0).ui/view.zod.ts): 1 file reads DIFFER at token 19222 (exit 1).component.test.tstest title): 1 file reads DIFFER at token 14972 (exit 1).Line balance holds in every file, 90 out and 90 in over the 25, and every line count is equal at base and head. Tracker numbers: added-not-removed is empty in every file. The net-removed numbers are the 25 in the table, 85 sites: the census's 84 comment sites, plus the slash-joined
#9972atcomponent.test.ts:3612.Generated page
check:generatedproved one artifact stale:content/docs/references/ui/expression-bindable-text-keys.mdx, the projection ofexpression-bindable-text-keys.zod.ts's module docblock.check:generated --fixregenerated only that page, and a re-run readAll 15 generated artifacts are up to date. Its two changed lines are the:72and:89substitutions verbatim. No other docblock here projects into a reference page, and nothing underskills/**moved.Changeset
This change ships bytes, so a
patchchangeset for@objectstack/specis included. It says only that the provenance comments were re-anchored.Clause-②: no: no export, key, value or type moves (the guard above).Measured on the head's built package: 6 touched sources are
src/**/*.zod.ts, whichfiles[]ships verbatim. The rewritten comments also reachdist:c459da6bcappears in 32 bundled.jsfiles and 2.d.ts;adabccf5fin 24.jsand 2.d.ts;d5552ca13and0e4e51b0ain 24.jseach;e233db9dband78f0be872in 2.jsand 2.d.tseach;Gates (head
1b885d3c27)pnpm check:issue-citations && node scripts/check-issue-citations.mjs, both under the grammar PR fix(scripts): check-issue-citations reads a qualifier only when it names a known repository, so pre-#N / post-#N are judged and framework#N is this repository #20554 landed, exit 0. The self-test passes 114 cases in 8 batteries. The live, diff-scoped run judged 13 citations across 11 files: 3 resolve and 10 are declared cross-repo references. It reads "every citation this change adds resolves".pnpm check:doc-authoringexits 0. Its 16,759 customer-facing strings across 1,174 spec sources carry no internal issue id, and the sibling-package prose-id baseline holds with no growth.node scripts/pm/dispatch-gates.mjs --repo objectstack-ai/objectstack --commandsat this head derived 112 families, and all 112 exit 0.--ranreports 112 run, 0 NOT MEASURED, 0 unrun. A fullturbo run buildof./packages/*at this head ran first, under the shared verify lock: 71 of 71 tasks, VERDICT command-exit 0. So no gate met an unbuilt prerequisite..changeset/orpackages/, so their silence proves nothing):node scripts/check-changeset-fixed.mjs,pnpm --filter @objectstack/spec run check:spec-changes,pnpm check:authz-resolver,pnpm check:error-code-casingandpnpm check:filter-alias-parity. All exit 0.pnpm --filter @objectstack/spec run check:generated(derived) readsAll 15 generated artifacts are up to date, andcheck:docsreads226 generated files in sync.pnpm --filter @objectstack/spec exec vitest run --maxWorkers=2 src/ui src/meta-spelling: Test Files 98 passed (98), Tests 3452 passed (3452), VERDICT command-exit 0 (the chain held the lock 142s on a shared box).src/uithat read the touched files' source text or pin their lines: Test Files 16 passed (16), Tests 489 passed (489). They arescripts/{export-origins,file-description,root-index,schema-closure,skill-map-guards,strictness-ledger}.test.ts,src/ai/tool-confirmation-prescription-tense.pin.test.ts,src/api/api-entry-graph.pin.test.ts,src/contracts/scoped-context.test.ts,src/data/filter-subtree-provenance.test.ts,src/shared/{alias-integrity,evaluated-slot-population,retired-key-migrate-sentence,union-author-message-pins}.test.ts,src/system/constants/platform-object-names.test.tsandsrc/type-alias-convention.pin.test.ts. Three more suites matched the reader scan and are not run here:scripts/build-schemas-check-mode.test.tsonly importsViewItemSchema(code the guard proves unchanged) and rebuilds schemas in a temp tree;scripts/def-key-collisions.test.tsnamesui/view.zod.tsonly in a comment;scripts/published-projection-choke-point.test.tsmatched onbuild-react-blocks-contract.ts, not a touched file. They are left to CI.pnpm --filter @objectstack/spec typecheck: exit 0, includingcheck:test-typecheck(53 files, 251 errors, 138 pinned signatures held). The same three runs also passed, with the same counts, on the pre-merge tree.eslint --no-inline-config --format jsonover the 25 touched.tsfiles gives 25 files, 0 errors and 0 warnings. All 25 are in eslint's own population (isPathIgnoredis false for each, read through eslint's API).eslint.config.mjsnever enables type-aware linting (noparserOptions.project, which its own lines 327 to 328 state), so a comment edit here cannot move the verdict on any untouched file. The repo-widepnpm lintis CI's run.merge-treeof the head ontoorigin/mainf572a7eb3c, from a bare shared clone with no merge driver registered, exits 0 (2026-09-29T04:15Z).Acceptance notes
487a7846df, one commit past the claim's stamp6154165484(PR fix(trigger-api,service-automation): refuse an api flow with no per-flow secret, at arm time and at registration (#20529) #20551, outside the surface).origin/mainthen moved three commits, and199002b3e4(PR fix(scripts): check-issue-citations reads a qualifier only when it names a known repository, so pre-#N / post-#N are judged and framework#N is this repository #20554) changedscripts/check-issue-citations.mjs, so the gate derivation read STALE TREE.origin/maindee9b26f6cwas merged in (1b885d3c27): a clean merge with no driver-routed path and no lockfile change, touching none of this diff's files. The PR's delta againstdee9b26f6cis exactly its 27 files.origin/mainhas since moved one more commit,1c761c0d71(PR test(create-objectstack,metadata): make two version-sensitive tests hold across the 17.5.0 version pass #20565, tests in two other packages), which touches none of them.manifest-collection-spelling.ts:71(pre-#10194). The same comment's first line,:67, cites#10485, which also answers 404, and it is rewritten too. The claim names this file; the fix is the same defect class, mechanical in the form stages 1 to 4 fixed, in a file no other claim holds, under the same gates. Reverting it would be one line.ui/is feat(spec)!: $empty joins FILTER_OPERATORS, and is_empty / is_not_empty lower to it (#20446) #20570 (filter: flipis_empty/is_not_emptyto$emptyand add it toFILTER_OPERATORS, once every compile surface answers it (the last step of ruling A on #20399) #20446's), on the excludedview-grouping-query.ts. The in-flightClaim:comments on the 12pm:dispatchedcards were read too: only filter: flipis_empty/is_not_emptyto$emptyand add it toFILTER_OPERATORS, once every compile surface answers it (the last step of ruling A on #20399) #20446's names aui/file (view-grouping-query.ts, excluded above).ui/, 14 sibling-qualified pairs leave the second number bare: 13 on one line (+,and,,,/or's PRbetween them) andcomponent.zod.ts:3478to:3479, split across a line break. In 3 of them the second number answers 404 here and the sentence attributes it to objectui (#6111once,#8758twice); they are respelled above. In the other 11 the second number answers 200 here, so it is judged as this repository's and left:action.zod.ts:1603,component.test.ts:2052,:2199,:2315,component.zod.ts:3276,:3793,:4812,expression-bindable-text-keys.zod.ts:33,page.test.ts:696,react-blocks.ts:256andwidget.zod.ts:34. The PR fix(scripts): check-issue-citations reads a qualifier only when it names a known repository, so pre-#N / post-#N are judged and framework#N is this repository #20554 header measured,andandpairs as naming this repository's number and/pairs as mostly, but not always, the qualifier's. Whether any/pair here names objectui's number is not measured; a 200 here cannot tell.it/describetitles in 7 test files):#6276×6,#11658×3 and#11507×1 incomponent.test.ts;#9972incomponent.test.ts:411;#17987×4 incomponent-element-navigation-17987.test.ts;#18177×2 inbulk-action.test.ts;#9933inview-metadata-schema.test.ts:406;#11284inreact-blocks.test.ts:147;#11753inaction-param-carryover.test.ts:17;objectstack#11195inview.test.ts:3396. None is a Zod.describe()text, an exported string or a migration-entry field, so no form D site arises here.objectui PR #8758):view.zod.ts:2354,:2579andview.test.ts:426. They are not pairs, and the landed grammar reads them as objectui's.liveness/**notes, thewhystrings and thePROVENANCE_WAIVERSreason,rest-server.zod.ts, the heldanalytics*anddriver/turso.*files, the 2AGGREGATION_CASESnote strings, anddata/'s test strings and deliberate markers.packages/spec/srcis [finding] dead tracker citations outsidepackages/spec/srchave no carrier: #20234 sweeps only the spec tree, and PR #20554 makes 26 more visible (pre-#N/Pre-#N) in cli, drivers, metadata, objectql, plugins, runtime and types #20556's, not this card's. Examples met here: ADR-0087's own amendment heading (docs/adr/0087-metadata-protocol-upgrade-contract.md:390,:397) cites the dead#18003, and ADR-0126 cites#11703and#11753; both are governed.packages/spec/scripts/strictness-ledger.test.ts:375,:380cite#9933, andcheck-objectui-pin-citations.tscites#10274and#9972.react-blocks.test.ts:140says the 2026-08-23 ruling was "recorded on-card". The card is gone, and the changeset of5383fa670(now cited on:139) records the ruling. The line holds no number, so it is left.packages/**/*.test.ts. The 11 touched non-test files are in its judging population.Generated by Claude Code