docs(spec): re-anchor the dead tracker citations in packages/spec/src's test surface to the commits that decided them - #21700
Conversation
…'s test surface to the commits that decided them The test-surface stage of the dead-citation sweep. Every comment and docblock site in packages/spec/src/**/*.test.ts that cited a tracker number answering 404 now cites the commit on main that decided it (ruling C+D form C), reusing the anchor an earlier stage landed for the same number wherever one exists. Two census-dead sites are objectui numbers split from their qualifier; they are respelled so the qualifier joins the number. The two source comments tests read literally move with their readers: data/api-derivation.ts's marker now opens with the deciding commit 6968885 (read by data/api-derivation.test.ts), and identity/identity.zod.ts now opens its explanatory block with commit 2c86fe3 (read by identity/api-key-retirement.test.ts). Comment and docblock text only, plus those two readers. No test title, schema, type, export or behaviour change. Claude-Session: https://claude.ai/code/session_01T9u38rswFp5Rw8DswRUReJ Co-authored-by: Claude <noreply@anthropic.com>
…pped comments src/identity/identity.zod.ts ships verbatim through files[] (src/**/*.zod.ts), and the api-derivation.ts docblock is emitted with its declaration, so the rewritten text publishes. Claude-Session: https://claude.ai/code/session_01T9u38rswFp5Rw8DswRUReJ Co-authored-by: Claude <noreply@anthropic.com>
📓 Docs Drift Check
What this run could not see
Coarse fallback — 138 page(s) merely mention a changed package (the pre-#9192 predicate, kept for the deliberately-wide backstop): |
⛔ merge queue 构建失败 — 先分诊,再决定要不要重排队列构建 37186683796 红了。队列跑的是全量套件(PR 侧 CI 只跑 affected 子集), 失败的 job(日志抽取,best effort):
跨 PR 相同签名(24h,按失败测试文件聚合):
历史信号:
分诊清单:
Generated by Claude Code · merge-queue-triage workflow (#4859) |
|
Queue build
GitHub rebuilt this PR's merge group on |
⛔ merge queue 构建失败 — 先分诊,再决定要不要重排队列构建 37187916146 红了。队列跑的是全量套件(PR 侧 CI 只跑 affected 子集), 失败的 job(日志抽取,best effort):
跨 PR 相同签名(24h,按失败测试文件聚合):
历史信号:
分诊清单:
Generated by Claude Code · merge-queue-triage workflow (#4859) |
Part of #20234
Clause-②: no
What this stage does
The citation gate's census defers
packages/**/*.test.ts, so the dead tracker numbers inpackages/spec/src's test files were never in its count. This stage measured that surface and re-anchored every dead site in its comment and docblock text, in ruling C+D form C (triage5856637615): each line now cites the commit onmainthat decided what it describes, and says the decision in words. Wherever an earlier stage of this card, or a sibling lane, already landed an anchor for the same number, this stage reuses it.It also takes the two source comments that tests read literally, and moves each reader onto the new text:
src/data/api-derivation.ts:163: the[#6259]marker onDATA_ACTION_TO_API_OPERATIONbecomes[commit 6968885ef]and the sentence says what that commit did (it removed the producer-lessbatch: 'bulk'row and stopped the description callingbatcha runtime action). Its reader,src/data/api-derivation.test.ts:236, splits on the new marker.src/identity/identity.zod.ts:230:(#8715,becomes(commit 2c86fe3ea,; the maintainer-ruled DELETE and its date stay. Its reader,src/identity/api-key-retirement.test.ts:118, asserts the new opening phrase.packages/runtime/src/api-exposure.test.ts:152) readspackages/runtime/src/api-exposure.ts, not the spec file, so it is not a reader of this text and is untouched.Comment and docblock text only, plus those two readers. No test title, schema, type, export or behaviour change.
Census (base
7d0781482d, head0e92e882f4)Instrument: the gate's own
extractCitations(comment-prose projection) andnamesThisRepositoryover all 596packages/spec/src/**/*.test.tsfiles (no.test.tsx,.spec.tsor__tests__/files exist there), with string literals read through the sharedscanSourceliteral projection. Every distinct in-repo number was probed with RESTissues/N, redirects not followed, with lit controls #16862 #16847 #17698 and dead controls #16714 #16715 #16697 at the start, every 100 numbers and the end.87 is under the stage's 120-site bound, so this stage takes all of it. By area: package root 36,
shared/10,system/9,data/8,api/5,automation/5,integration/5,conversions/4,security/3,identity/2. The excluded files (migrations/**;automation/flow-slot-refusal-codes.test.ts;automation/flow-write-node-stored-metadata-target.test.ts) carry 0 dead sites, so the exclusions removed nothing.The three literal sites that left are exactly the two readers' literals. Every test title is untouched. No in-repo comment citation was added at head. The one live number that left the in-repo count is #6110, which now carries its
objectui#qualifier (below). A raw#Nscan of the comment projection agrees with the gate's extractor: its only extra hits are threeobjectui #11166sites that are objectui's.The gate's own census (
check-issue-citations.mjs --census --json, board enumerated, 196 pages, frontier #21684) reads 0 findings inpackages/spec/srcat head. The gate's extractor read 2 at base (api-derivation.ts:163#6259,identity.zod.ts:230#8715).Dead numbers left in string literals (not touched; #20749's class (e))
68 numbers at 147 sites, all test titles.
data/40,api/33,ui/21,kernel/18,contracts/10,shared/6,system/6,integration/5,(root)3,identity/3,conversions/2,automation/1. One of them is not a tracker number at all:#0000inshared/retired-key*.test.tsis a fixture placeholder.Anchors
18189983d7f713b662(the squash commit of PR #6072, ADR-0122 phase 1)53068c130(ADR-0122 phase 2)026101660(added this very pin file)f549a0d4a(the sweep commit, cited on the sweep's header line)6968885efe2798fab7(its diff wrote all five lines)b5404f496259459d8b(the squash commit of PR #6527)d127ff002c6b05c76a(wrote the prose-count check)42b05af892c86fe3ea24206416ad491625c12a29caa532306a765c35ad101bcd173125fbcccbe51bf735f5c709(the runtime and service-datasource lanes' anchor)e58ea8b38(stage 6's anchor for the same phrase)311433f6baa5994e17901355c3b9e0ba21a1fd289be45(the sibling files' spelling, "commit fd289be's strip")c45d8e6b4c5a9a437d(the squash commit of PR #14240, whose body names #14162 as the card it lands; it is the load path that judges eachpackages[]entry withArtifactPackageEntrySchema)c5a7448d5(its message names #14419 as the card it lands)35dffeace13c48c2a5279431e7ab3a63d32c23c72be3c(stage 1's "refuted in commit 23c72be")ecdfc941129dd1a6dd(it wrote this very pin line)86c505286(the service-analytics and core lanes' anchor)Every anchor is unique at nine hex digits, single-parent, and an ancestor of
main. That was read from a full, not shallow, treeless clone ofmainat the base. For 40 of the 49 (number, anchor, file) pairs, the anchor's own diff wrote a line naming the number into that file. Where it did not, the anchor's message or its PR body names the number.Two census-dead sites are not this repository's numbers. They are respelled so the gate reads their qualifier, following stage 5's precedent, and are not re-anchored. Both numbers answer 200 on objectui.
api/export-job-family-retirement.test.ts:24-25:objectui/PR #10264was split across a line break, so the census read dogfood: simulate a brand-new developer's first-run journey — README → create an app → skills-driven AI build → validate & test #10264 as bare. The line break now falls beforeobjectui PR #10264.shared/editability-boundary.test.ts:391-392:(objectui#6010 / #6110 / #6111)becomes(objectui#6010 / objectui#6110 / objectui#6111), the spellingui/view.zod.tsanddata/field.zod.tsalready use for the same pair.Proof that only text moved
maskComments, whitespace collapsed) run over all 36 files, base vs head. 34 files are IDENTICAL on both instruments. The other two differ only in the declared reader literals:api-derivation.test.tsin 2 string tokens ('[#6259]'and its assertion message), andapi-key-retirement.test.tsin 1 ('are NOT declared here (#8715').VERDICT text-only (36 files), exit 0.Reverse verification of the two readers (each leg through
scripts/ablation-replace.mjs, restore proven againstHEAD)api-derivation.ts:[commit 6968885ef]back to[#6259][commit 6968885ef]removal note vanished from the TSDoc", 1 failed, 31 passedapi-derivation.test.ts: the reader back tosplit('[#6259]')identity.zod.ts: back toare NOT declared here (#8715toContain('are NOT declared here (commit 2c86fe3ea'), 1 failed, 2 passedapi-key-retirement.test.ts: the reader back to(#8715Each leg's mutation landed (anchor 1 → 0, blob changed), and each restore read blob == HEAD with an empty
git diff HEAD. Both files are green atHEAD(32/32, 3/3), and the tree is clean afterwards.Generated artifacts and the changeset
pnpm --filter @objectstack/spec build, the rewrittenDATA_ACTION_TO_API_OPERATIONdocblock is indist/data/index.d.tsandindex.d.mts. The positive control, the same docblock's unchanged first sentence, is in the same two files, and the old[#6259]marker is in 0distfiles.identity.zod.tsblock comment is in nodistfile, and neither is the control sentence from the same block. Butfiles[]shipssrc/**/*.zod.tsverbatim, so the new text publishes.@objectstack/specpatch changeset (.changeset/spec-test-surface-dead-citation-anchors.md, with theClause-②: noline), andskip-changesetdoes not apply. Test files do not ship.check:generated: all 15 generated artifacts are up to date, with nothing regenerated.check:docsis green, so no reference page renders either comment.Verification
pnpm --filter @objectstack/spec build, thencheck:generated: exit 0.pnpm --filter @objectstack/spec exec vitest run --project local --maxWorkers=2: 610 files passed, 18,113 tests passed, 1 todo.repo-project files (export-job-family-retirement,rest-api-config-dead-keys-retirement) are green in the 34-file run.pnpm --filter @objectstack/spec typecheck: exit 0 (check:test-typecheckOK: 52 files, 246 errors, 135 pinned signatures held).dispatch-gates --commandsat0e92e882f4derives 85 families.--ranreports 85 accounted, 84 run (all exit 0), 1 NOT MEASURED and 0 unrun.check:dual-build-cjs-loads, which exits 3 (PREREQUISITE NOT MET) without a full monorepo build. It is a declared narrowing: the diff is comment-only inpackages/spec, and spec's 19 require entries from the gate's own--listall load at head (a missing-entry control throws). CI runs the full gate.eslint --no-inline-config --format jsonover the 36 touched files gives 36 files, 0 errors and 0 warnings.isPathIgnoredis false for all 36, read from eslint's own config.eslint.config.mjsenables no type-aware linting (noparserOptions.project), so a comment edit cannot move any untouched file's verdict. The repo-widepnpm lintis CI's.0e92e882f4.origin/mainwas re-fetched before opening this PR (83e2feeb46, 5 commits past the base). None of those commits touchespackages/specor any file here, andgit merge-treeonto it exits 0, so no merge was taken.Acceptance notes
retiredFromLoadPath: truedoes not keep a conversion off any load path — three runtime seams replay every retired entry withincludeRetired: true, andapply.tssays onlymigrate metadoes #16864 cites29dd1a6dd, the commit that wrote this exact pin line; stage 8 took ADR-0087's 2026-09-13 addendum for a different sentence about the three data-at-rest seams. [spec] View-Management 五方法(listViews/getView/createView/updateView/deleteView)是零实现零路由的声明面 —— 已导致 #5948 把它的响应 schema 误当成线上路由的契约 #6239's row in the-7receipt table now readsviews, and the sweep commitf549a0d4ais cited on the sweep's header line beside the live#6486.packages/spec/srcthere are no dead comment or docblock citations left: the gate census reads 0 and the test-surface census reads 0. What remains are the 68 dead numbers in 147 test-title literals listed above. This stage's dispatch assigns those to runtime strings in thedomain:specpackages carry tracker numbers (spec175 andlint83 messages): this lane's share of the #20513 A/A burn-down #20749's class (e), so this PR saysPart ofand leaves the card open for that call.docs/audits/2026-07-unknown-key-strictness-ledger.md:676(element:record_picker的sort/limit扁平简写:renderer 兑现、schema 未声明(#5775 实施中新测出,A 表之外的第 7 处) #6276) has no carrier.Generated by Claude Code