docs(metadata-fs): re-anchor the dead tracker citations to the commit that decided them (stage 13 of #20595) - #21640
Conversation
… that decided them Three comment and docblock sites in packages/metadata-fs cited a tracker number that now answers 404 (two census sites, in src/repository.ts and src/sync.ts, and one test comment in test/close-terminates-watch.test.ts). Each now cites commit 7d81c88, the change that made close() terminate watch iterators instead of emitting a drain event, measured why the drain event was the wrong shape, and wrote invariant 8 in metadata-core. The live #11127 beside one of them stays. Comment text only; no line count changes. Claude-Session: https://claude.ai/code/session_017ErfyP2Rx7XWHJA27QjyUi Co-authored-by: Claude <noreply@anthropic.com>
One of the two rewritten src lines (the FileSystemRepository.close() docblock) reaches the published dist, in the declarations and in the JavaScript esbuild emits, measured with a three-leg dist reading. Claude-Session: https://claude.ai/code/session_017ErfyP2Rx7XWHJA27QjyUi Co-authored-by: Claude <noreply@anthropic.com>
📓 Docs Drift CheckThis PR changes 1 package(s): 1 hand-written doc(s) NAME something this change touched and may need an implementation-accuracy re-verification:
What this run could not see
Coarse fallback — 1 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 34a46128f400f56c88913314a353e31e5ccc9cf9 && git checkout 34a46128f400f56c88913314a353e31e5ccc9cf9
# afterwards, rebuild it from the two parents, which stay fetchable
git fetch origin 5b5e83f446bde0bf6e13db304b9f07f115635704 32de59091a5cda24636d566cf7436b0de31c42f8 && git checkout -B drift-repro 5b5e83f446bde0bf6e13db304b9f07f115635704 && git merge --no-ff 32de59091a5cda24636d566cf7436b0de31c42f8
node scripts/docs-audit/affected-docs.mjs --json 5b5e83f446bde0bf6e13db304b9f07f115635704
|
ACCEPT — PR #21640 at head
|
Part of #20595
Clause-②: no
What changed
Stage 13 of the
domain:enginelane of the dead-citation sweep:packages/metadata-fs/**, comment and docblock prose only, per the claim (5973452558). Stages 1 to 11 landed asa7d9768ec,d150c3039,4bf4e7e70,13a24ece2,db0cf2231,85986144c,48fa7a381,c205b6c35,c98a72d69,fd5a1cd59andf97660cdd; stage 12 (packages/formula) is PR #21635, in review, with a disjoint file surface. #20595 stays open: this PR does not touchformula, nor the test-string sites the card carries for a widened stage, and the seat decides the card's close-out.Every comment or docblock site in the package that cited a tracker number answering 404 is rewritten in ruling C+D's form C (record
5749154545on #19123): the ADR when one records the decision, otherwise the commit in this repository's history that made it. That is 3 sites on 3 lines in 3 files, all citing one number (#11021), all re-anchored to one commit,7d81c889f:src/repository.ts:230andsrc/sync.ts:41): the wholeallocated-but-absentpopulation of the gate's own census in this package at the base;test/close-terminates-watch.test.ts:103), outside the census glob (test/is not undersrc/, and the census defers test files anyway). Same number;README.md,tsconfig.test.jsonandvitest.config.tscarry 10 citations between them, and all 10 resolve on the enumerated board (below);package.json,tsconfig.jsonandtsup.config.tscarry none;issuecommentordiscussion_rlink (git grep exit 1).Anchors: 1 number, by commit; 0 by ADR, 0 by repository qualifier; 1 sha.
7d81c889fis the anchor stage 1 (a7d9768ec) and stage 9 (c98a72d69) already chose for the same number; it is reused here and re-proven below for this package's sentences.Only comments changed. All three files keep their line counts (3 lines out, 3 in, plus the changeset), so no line citation into any of them moves. No code token moves (the guard below). All 6 changed lines under
packages/open with a comment marker. No citation number is added: the only tracker number on a+line is#11127onsync.ts:41, carried over unchanged from the-line, and it resolves (a closed issue). The only new nine-hex span is7d81c889f, 3 times.A
patchchangeset: 1 of the 2 rewritten non-test lines is in the publisheddist(theFileSystemRepository.close()docblock, in the declarations and in the JavaScript esbuild emits), anddistis not byte-identical with the base text (see Changeset).H0: the package and its size
The gate's own
node scripts/check-issue-citations.mjs --census --jsonat base0fc80878f(the before run below),allocated-but-absentper remainingdomain:enginepackage (stage 12's H0 list):metadata-fsformulamain)drivers/driver-mongodb,drivers/driver-turso,metadata-core,core,metadata-protocol,objectql,metadata,drivers/driver-sql,drivers/driver-memory,drivers/driver-sqlite-wasm,plugins/plugin-pinyin-search,platform-objectsmetadata-fsreads 2, both #11021, atrepository.ts:230andsync.ts:41, exactly as stage 12's head census (b89eb86cb) read it. So the stage went ahead. On this branch's tree the lane total goes 6 to 4; with stage 12's PR it is 0.Census:
metadata-fs, before and afterInstrument. The gate's own
node scripts/check-issue-citations.mjs --census --json, read-only and unchanged. The count is itsallocated-but-absentfindings underpackages/metadata-fs/.allocated-but-absent0fc80878f, run 21:04:24Z to 21:07:44Z67f182575, run 21:14:26Z to 21:17:43Z32de59091, run 21:37:42Z to 21:40:56ZThe whole-repo drop is 2, and the before and after finding sets differ by exactly the 2 rows of this package, removed; none was added.
resolves(35,763),resolves-as-pull-request(2,383) andcross-repo-unjudged(1,254) did not move:#11127stays onsync.ts:41and still resolves. The head's only later commit is the changeset; the head run's finding set is identical to the after run's, line numbers included.Supplementary instrument, the whole package. The census reads neither test files nor strings nor files outside
src. A second reading runs the gate's own exportedextractCitations(whole-file and comment-prose projections) over every tracked file in the package (24) and classifies each citation with the gate'sclassifyCitationagainst one board enumerated by the gate'senumerateBoard(195 pages, frontier #21636, 19,457 records, read from 21:09:16Z to 21:12:31Z), the same board for both readings.0fc80878f67f182575The citation count drops by 3, the 3 rewritten sites; no respelling stays a citation. The live counts did not move (src comment: 39 resolve as issues, 2 as pull requests; test comment: 44 and 9; test string: 10 and 0; files outside
srcandtest: 8 and 2; changelog: 16 and 2). A third, raw reading (every#followed by 2 to 6 digits, whatever surrounds it,CHANGELOG.mdaside) counts 117 before and 114 after: also a drop of 3.Single reads over the issues endpoint: #11021 answers 404; #11127 answers 200 (a closed issue:
FileSystemRepository.close()never reaching its broker); #11136 answers 200 (the pull request whose squash is7d81c889f).Per-number table
srccounts census sites,testthe test-comment sites.#110217d81c889fa7d9768ec, stage 9c98a72d69), re-proven hereclose()terminates watch iterators instead of emitting a drain event: it measured why a synthetic drain event is the wrong shape (the filter and the numericsincedrop it, and delivering an event never ends an iterator), fixed that defect inSysMetadataRepository, and wrote invariant 8 inmetadata-core'srepository.ts(the squash of PR #11136)Each sentence, judged against the decision it describes rather than the number:
repository.ts:230says a synthetic drain event 「would be the wrong shape and was measured to be so」. The measurement is7d81c889f's: its message and its invariant 8 text record both halves (the filters drop it; delivery never ends an iterator). Themetadata-fsfix that wrote this docblock,46644e25a(FileSystemRepository.close()never reaches its event broker — a parkedwatch()iterator stays parked after shutdown #11127), cites [finding]SysMetadataRepository.close()cannot drain a filtered or numeric-sincewatcher — the pendingnext()never settles and the consumer'sfor-awaithangs #11021 as that earlier decision.sync.ts:41sends the reader to invariant 8 inmetadata-core'srepository.tsand names the pair(#11021, #11127).git blameat the base puts invariant 8's statement (repository.ts:53 to :76) on7d81c889f(its line :63 since re-anchored by stage 9), and its conformance rows forFileSystemRepositoryandInMemoryRepository(:77, :79 to :88) on46644e25a, theFileSystemRepository.close()never reaches its event broker — a parkedwatch()iterator stays parked after shutdown #11127 fix. So the dead half of the pair becomescommit 7d81c889f, and the live#11127stays.close-terminates-watch.test.ts:103contrasts this package's hang with 「the sibling defect」: the filter-dependent drain-event drop inSysMetadataRepository, which is the defect7d81c889ffixed.The proof, per the earlier stages' standard:
git rev-parse --disambiguate=7d81c889fmatches exactly one commit,7d81c889f1f190a273e59ee584b7522ca6a792fa.git merge-base --is-ancestorputs it under the base0fc80878f, underorigin/maina1ca156daat the time, and undermain5b5e83f44fetched later (exit 0 each; exit 0 is self-proving, and the repository is not shallow).SysMetadataRepository.close()cannot drain a filtered or numeric-sincewatcher — the pendingnext()never settles and the consumer'sfor-awaithangs #11021 in its message (the subject) and in its diff (7 diff lines).git blameat the base puts all 3 changed lines on46644e25a, which cites [finding]SysMetadataRepository.close()cannot drain a filtered or numeric-sincewatcher — the pendingnext()never settles and the consumer'sfor-awaithangs #11021 as the sibling decision; that decision is7d81c889f's diff, as the three bullets above set out.SysMetadataRepository.close()cannot drain a filtered or numeric-sincewatcher — the pendingnext()never settles and the consumer'sfor-awaithangs #11021 or the drain-event decision (git grep overdocs/adrfor the number, 「drain event」 and 「Shutdown terminates」, exit 1).Wordings to check
All 3 rewrites swap a tag in place, in forms the earlier stages already use:
(#11021)became(commit 7d81c889f)atrepository.ts:230(stage 1's(#N)form).(#11021, #11127)became(commit 7d81c889f, #11127)atsync.ts:41. The mixed commit-and-issue pair already stands inpackages/cli((commit 44813ba57, #14554)).SysMetadataRepository.close()cannot drain a filtered or numeric-sincewatcher — the pendingnext()never settles and the consumer'sfor-awaithangs #11021」 became 「unlike the sibling defect commit 7d81c88 fixed」 atclose-terminates-watch.test.ts:103, the formpackages/cli/src/commands/generate-multiple-json-column.pin.test.ts:57uses (「the defect commit ee370d3 fixed」).No reflow. No line was reflowed, so
repository.ts:230andclose-terminates-watch.test.ts:103are now longer than their block's wrap.eslint.config.mjsdeclares no line-length rule, and a reflow would move neighbouring lines. No file cites a line of any of the three touched files (git grep exit 1), and neither changed phrase is quoted elsewhere.Sites left
srcandtest: the release-ownedCHANGELOG.mdnames [finding] 28 published packages ship 36.d.ctsdeclarations (5.2 MiB) that notypescondition points at — the same unreachable-published-dist class as #13013, measured 48x larger #13112 (line 47) and [finding]SysMetadataRepository.close()cannot drain a filtered or numeric-sincewatcher — the pendingnext()never settles and the consumer'sfor-awaithangs #11021 (line 196), both answering 404; left.Mechanical guard: no code token moves
The guard compares base
0fc80878fagainst the tree over all three touched files, with TypeScript 6.0.3, to the earlier stages' two-reading specification. The earlier guard scripts were scratch files, so it was rewritten here to that specification and proven with the controls below.forEachChildwalk. Comments are trivia there, and JSDoc is never visited. A leaf that is not itself a token is re-scanned with trivia skipped.getChildrenwalk, with JSDoc nodes skipped. String, template and numeric literals are compared in full on both readings.Results, at
67f182575(the later commit touches none of the three files):repository.ts), 「Best-effort cleanup:」 to 「Best-effort CLEANUP:」 (sync.ts) and 「bites on its own.」 to 「bites ON its own.」 (the test file). 0 files changed (exit 0 each).export function createBroker(tocreateBrokerX(,sync.ts): DIFFER on both readings (exit 1).@separator in the sweep-failure key template, to#,repository.ts): DIFFER on both readings (exit 1).SETTLE_MS = 2_000to2_001, the test file): DIFFER on both readings (exit 1).Each mutation went through
scripts/ablation-replace.mjs(wrap mode; the anchor hit 1 before and 0 after, and the blob changed). It ran under a shell trap that restores by absolute path fromHEAD. Each restore was proven equal to itsHEADblob (888f39203432,122a45dcb516,0d266189d60c), and afterwardsgit diff HEADwas empty and the tree clean.Changeset:
patch(distmeasured)files[]isdist,README.mdandCHANGELOG.md, and the package is not private. One script ran under the shared verify lock (VERDICT command-exit 0, held 79s, shared-box seconds), at67f182575. It built the dependency closure first (pnpm --workspace-concurrency=2 --filter '@objectstack/metadata-fs^...' build, exit 0), then ran the package's ownbuild(tsup andcheck-dts-emitted) three times, exit 0 each:distfiles hashed (index.js,index.cjs, their sourcemaps,index.d.ts,index.d.cts). 1 of the 2 rewritten non-test lines appears verbatim indist: theclose()docblock line (repository.ts:230), inindex.d.ts,index.d.cts,index.jsandindex.cjs(esbuild keeps that docblock). The other (sync.ts:41) sits on an interface that is erased from the JavaScript and never reaches the declarations (grep exit 1).scripts/ablation-dist-preflight.mjsfinds the head marker 「was measured to be so (commit 7d81c88)」 in those 4 files with a clean tree (exit 0).repository.tsandsync.ts(proven equal to their base blobsd551426a7545and48798bcf7661, written to the tree only, 0 paths staged): 4 of the 6 files differ from leg 1 (index.js,index.cjs,index.d.ts,index.d.cts); the two sourcemaps do not. The preflight finds the base marker 「was measured to be so ([finding]SysMetadataRepository.close()cannot drain a filtered or numeric-sincewatcher — the pendingnext()never settles and the consumer'sfor-awaithangs #11021)」 in the same 4 files (exit 0).HEADblobs888f39203432and122a45dcb516,git diff HEADempty, porcelain empty): all 6 files are byte-identical to leg 1. The preflight's--absentreading of the base marker exits 0 with a clean tree. So the build is deterministic, and the difference is the rewrite.So the rewrite ships.
.changeset/20595-metadata-fs-provenance-anchors.mddeclares apatchfor@objectstack/metadata-fs, comment text only, with the claim'sClause-②: noline. The anchor is a commit, so the changeset names no ADR, repository qualifier or bracketed substitution. It says which published files carry the reworded text, as measured above. The changeset commit touches no file underpackages/metadata-fs.Gates (head
32de59091)node scripts/pm/dispatch-gates.mjs --repo objectstack-ai/objectstack --commandsat32de59091(4 paths against merge base0fc80878f) derived 61 commands. All 61 ran (21:25:07Z to 21:36:22Z, after the workspace build), each exit code captured before any pipe: 61 exit 0.--ranreports 「61 derived, 61 run, 0 NOT-MEASURED, 0 UNRUN」 (a derived zero) and exits 0..changeset/path adds: the ADR-0087 registration and empty-changeset pairs,check:objectui-changeset,check:pm-changeset-deadline-censusand two release self-tests;check:type-check-coverageandcheck:type-check-debt;check:engine-double-contract,check:objectql-double-limit,check:query-options-erasureandcheck:where-matcher.node scripts/check-issue-citations.mjsexits 0 (1 citation judged across 2 files: the carried-over#11127, which resolves).pnpm check:issue-citationsexits 0 (its self-test, 173 cases, 9 batteries).pnpm check:doc-authoringexits 0 (the sibling-package prose-id baseline holds, no growth).pnpm check:nul-bytesexits 0 (10,001 files, no raw control bytes), and a control-byte grep over the 4 changed files finds none (exit 1).check-adr-0087-registration(「1 non-breaking changeset(s) seen」),check-empty-changeset(「1 declaring changeset(s) added」),check-changeset-no-major(「nomajorbump」), andcheck:changeset-gate-self-tests. The Clause-② level axis ofcheck-changeset-no-majorreads the pull request body, so it does not apply to a local run; that reading is CI's.32de59091:turbo run build --filter='./packages/*' --filter='./packages/*/*' --concurrency=2): VERDICT command-exit 0, held 198s, shared-box seconds; 71 of 71 tasks, 20 cached.pnpm --filter @objectstack/metadata-fs test: 10 test files pass, 70 tests pass (exit 0).pnpm --filter @objectstack/metadata-fs typecheck(tsc --noEmitandtsc --noEmit -p tsconfig.test.json) exits 0.tsc --listFilesOnlyputs every touched file in a program:repository.tsandsync.tsin both configs, andclose-terminates-watch.test.tsintsconfig.test.json, whose program holds all 10 test files.32de59091:--format json) over the 3 touched files plusdist/index.jsas the control.--print-configresolves a config for each.eslint.config.mjsnever enables type-aware linting (its lines 327 and 328 say so;--print-configshows noparserOptions.projectand noprojectService), so a comment edit cannot move the verdict on an untouched file.pnpm lintis CI's run.Acceptance notes
origin/mainat0fc80878f, and the worktree was cut there. Every reading above is on this branch's own tree. Before this PR was opened,mainmoved 4 commits, to5b5e83f44(objectql,driver-sqlandservice-analytics,spec).packages/metadata-fs,check-issue-citations.mjsordispatch-gates.mjs.git merge-treeof the head with5b5e83f44is clean (exit 0), and the anchor7d81c889fis under it too (--is-ancestor, exit 0).5b5e83f44against0fc80878f, judges the 26 citations those 4 commits add: all 26 resolve. So they add no dead citation to the lane's packages.0fc80878f, and CI and the merge queue run on the merged ref.git rev-parse --is-shallow-repositoryanswers false), so no deepening was needed before the blame, ancestry and history readings.CHANGELOG.md([finding] 28 published packages ship 36.d.ctsdeclarations (5.2 MiB) that notypescondition points at — the same unreachable-published-dist class as #13013, measured 48x larger #13112 and [finding]SysMetadataRepository.close()cannot drain a filtered or numeric-sincewatcher — the pendingnext()never settles and the consumer'sfor-awaithangs #11021, release-owned).Generated by Claude Code