docs(core): re-anchor the dead tracker citations to the commits and ADRs that decided them (stage 8 of #20595) - #21506
Conversation
…DR that decided them Comment and docblock prose in packages/core only. 81 sites on 80 lines in 34 files, covering 24 tracker numbers that answer 404 and one dead comment id, now cite the commit in this repository that decided them (ADR-0025 §3.7 for the comment id; two sites state in words that the unpack-time re-verification leg is unbuilt). Every file keeps its line count; no code token moves. Claude-Session: https://claude.ai/code/session_01DDZNkDVwPQnevTFcYE47H3 Co-authored-by: Claude <noreply@anthropic.com>
The rewritten docblocks reach the published dist (index.d.ts / index.d.cts, and index.js / index.cjs): measured with a base-text build leg against a restored-head leg that is byte-identical to the first. Claude-Session: https://claude.ai/code/session_01DDZNkDVwPQnevTFcYE47H3 Co-authored-by: Claude <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01DDZNkDVwPQnevTFcYE47H3 Co-authored-by: Claude <noreply@anthropic.com>
… records it verbatim ADR-0131's 2026-09-17 amendment quotes the same sentence verbatim and untranslated, so the ADR comes before the commit as its anchor. Claude-Session: https://claude.ai/code/session_01DDZNkDVwPQnevTFcYE47H3 Co-authored-by: Claude <noreply@anthropic.com>
📓 Docs Drift CheckThis PR changes 1 package(s): 9 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 — 27 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 fd0cd0f8b4101bdbebd1ba5404b90881a9e0fb5e && git checkout fd0cd0f8b4101bdbebd1ba5404b90881a9e0fb5e
# afterwards, rebuild it from the two parents, which stay fetchable
git fetch origin 2ee8383f4e16248322a45a3e4fde5de75598eef4 bb55f72ec067840cdc6343eba0dbf68c53e23af6 && git checkout -B drift-repro 2ee8383f4e16248322a45a3e4fde5de75598eef4 && git merge --no-ff bb55f72ec067840cdc6343eba0dbf68c53e23af6
node scripts/docs-audit/affected-docs.mjs --json 2ee8383f4e16248322a45a3e4fde5de75598eef4
|
…ore rewrite carries The paragraph named only the two by-words comments. The diff also anchors one source comment to ADR-0131's 2026-09-17 amendment and one test comment to ADR-0025 §3.7; the paragraph now says so. Claude-Session: https://claude.ai/code/session_01DDZNkDVwPQnevTFcYE47H3 Co-authored-by: Claude <noreply@anthropic.com>
Part of #20595
Clause-②: no
What changed
Stage 8 of the
domain:enginelane of the dead-citation sweep:packages/core/**, comment and docblock prose only, per the claim (5963404083). Stages 1 to 7 landed asa7d9768ec,d150c3039,4bf4e7e70,13a24ece2,db0cf2231,85986144cand48fa7a381. #20595 stays open: the other half of this lane is the packages this stage does not touch (metadata-core19,drivers/driver-turso14,drivers/driver-mongodb9,formula4,metadata-fs2 on the census after this stage, 48 in all), plus the test-string sites the card carries for a widened stage.Every comment or docblock site in the package that cited a tracker number answering 404, and the one comment-id citation that answers 404, is rewritten in ruling C+D's form C (record
5749154545on #19123), in the form #20234 applies it to the spec tree: the ADR when one records the decision, otherwise the commit in this repository's history that made it, otherwise the fact in words. That is 81 sites on 80 lines in 34 files, covering 24 numbers and 1 comment id:src/): the wholeallocated-but-absentpopulation of the gate's own census in this package at the base.plugin-permission-enforcer.ts:119carries two numbers on one line;vitest.config.ts:21([finding] vitest 的 --project 过滤器落空即静默成功 —— 点名一个 integration 文件跑 --project unit,报它是通过的文件、执行零个用例,并把它从文件计数里减掉 #17853, a//line), and five//lines in three JSON-with-comments files,tsconfig.examples.json:1,:2and:22([finding]@objectstack/coredeclares notypecheckscript, so no CI job ever type-checks it — and its own tsconfig program is currently red #14613, [finding] check:type-check-coverage cannot see PACKAGE-ROOT source (depth 0 is skipped by construction) — three more objectstack.config.ts manifest sites sit outside every tsc program with no ledger entry #14386 twice),tsconfig.json:30andtsconfig.test.json:1([finding]@objectstack/coredeclares notypecheckscript, so no CI job ever type-checks it — and its own tsconfig program is currently red #14613). These follow stage 1'stsup.config.ts, stage 5'stsconfig.typecheck.jsonand stage 7'stsconfig.scripts.jsonprecedents;src(finding: ExecutionContext 在 dispatcher / REST / share-link 三处独立组装 —— 收敛为单一共享装配函数前,先裁决匿名面分歧 #6216, Nothing binds the last-admin-guard standing-key lists to what the authz resolver actually reads — the correspondence is prose only #8734, [finding] a permission-store read failure resolves as an AUTHENTICATED caller holding ZERO capabilities — the package door answers 403 FORBIDDEN, byte-identical to a genuine capability denial #13279,packages/core/examples/phase2-integration.tsis the sole composer ofPluginSecurityScanner, which FOLLOW-UPS.md already records as exported dead code with 3 of 5 scan methods empty stubs — repair it, or retire it as #4939 did to its neighbour? #14919, [Decision] The declared plugin contract does not govern what the runtime accepts:LiteKernelnever runsPluginSchema, andisDefaultsurvives the kernel that does #16721, Phase 1b of #11333: make the registered granted-permission set actually REFUSE — the ADR-0025 materialize seam that gives each plugin its own SecurePluginContext #17147), 1 it reads as dead elsewhere (driver-sql: the $contains MEMBERSHIP spelling on any multi-valued / JSON column is a DATABASE_ERROR 500 on live PostgreSQL (SQLSTATE 42883, operator does not exist: json ~~ text) — it has only ever been executed on SQLite #17590, atpackages/spec/src/data/filter.zod.ts:1067), and 4 it never judges on this tree because they stand only in test files or outside the census glob (finding: ObjectQL test doubles ignorelimit, so a limit regression is invisible to every suite that uses one #10978, [text correction · ruled B] manifest.runtime tombstone/describe reads truthfully: publish-gate enforced (cloud), load-side NOT enforced #11330, [finding] A tracker id sits inpackages/core's plugin-registration refusal message — the ruled audience, in a packagecheck-doc-authoringRule 3's scanned root (packages/spec/src) cannot reach #13179, [finding]@objectstack/coredeclares notypecheckscript, so no CI job ever type-checks it — and its own tsconfig program is currently red #14613), which the board and a single read each settle;granted-permissions-not-enforced.pin.test.ts:9named maintainer ruling5486840233, a comment that answers 404 (see Census).Anchors: 22 numbers by commit, 1 by ADR, 1 by words, and the comment id by ADR; 24 distinct shas. Two numbers are split by subject:
#14386(7cbe705b0for the plugin-auth program's widening,c49007a7cfor the finding the sentence describes, see Wordings) and#17147(aaacf1d5cfor the pin and the seam,65481183bfor the pin's follow-up).#11333and#17147share one line. 19 numbers reuse the anchor another lane or stage already used for them; measured here are 5 commits (fd289be45for #13179,cc00df2f7for #14919,7cbe705b0andc49007a7cfor #14386,65481183bfor #17147's follow-up half) and 2 ADR anchors (ADR-0131's 2026-09-17 amendment for #16682, ADR-0025 §3.7 for the comment id). The plugin-security lane's#16682anchor (9b9581b11) was not taken: it is a different subject (see the table).#11331takes words, as the spec lane gave it (see Wordings).Only comments changed. Every file keeps its line count (81 lines out, 81 in, plus the changeset), so no line citation into any of them moves. One changed line carries no number (
plugin-artifact-integrity.ts:12, see Wordings). No code token moves (the guard below). No citation number is added: on every changed line the numbers on the new text are a subset of those on the old (the only numbers on+lines are #3984, #5286, #5881, #6551, #10869, #11974, #16404 twice and #17978, each already on its line and each answering 200).A
patchchangeset: 21 of the 40 rewritten non-test lines are in the publisheddist(the.d.tskeeps JSDoc on exported members, and esbuild keeps some comments in the JS), 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 basefd96a8473(the before run below),allocated-but-absentper remainingdomain:enginepackage:coremetadata-coredrivers/driver-tursodrivers/driver-mongodbformulametadata-fsmetadata-protocol,objectql,metadata,drivers/driver-sql,drivers/driver-memory,drivers/driver-sqlite-wasm,plugins/plugin-pinyin-search,platform-objectsThe lane total goes 88 to 48.
coreis the largest remaining package and reads 40, as at stage 7's census (e5d9a5d85), so the stage went ahead.Census:
core, before and afterInstrument (A1). The gate's own
node scripts/check-issue-citations.mjs --census --json, read-only and unchanged. The count is itsallocated-but-absentfindings underpackages/core/.allocated-but-absentfd96a8473, run 00:07:44Z to 00:11:10Z195aa6bdb, run 00:27:00Z to 00:30:25ZThe whole-repo drop is 40, and the two finding sets differ by exactly the 40 rows of this package, removed; none was added.
resolves(35,428),resolves-as-pull-request(2,388) andcross-repo-unjudged(1,243) did not move.The head's later commits are the changeset, one merge of
main, and one comment line inresolve-authz-context.ts(the ADR re-anchor of:925, which adds and removes no number). The census was run a third time at the heada4c483901(00:50:57Z to 00:54:06Z, 194 pages, frontier #21504, 19,325 records, newest #21504 before and after): whole-repo 163,core0, and itsallocated-but-absentfinding set is identical to the after run's (0 removed, 0 added). Itsresolvesreads 35,441, 13 more than above, from the mergedmaincommits outside this package.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 (175) and classifies each citation with the gate'sclassifyCitationagainst one board enumerated by the gate'senumerateBoard(194 pages, frontier #21494, 19,315 records, 00:11:24Z to 00:14:37Z), the same board for both readings. Every one of the 24 numbers in the population was then read on its own over the issues endpoint (00:19:57Z): all 24 answer 404; the lit controls#5286and#12624answer 200, and so do the numbers that stay on changed lines (#3984, #5881, #6551, #10869, #11974, #16404, #17978).vitest.config.tscommenttsconfig*.json/ rest)fd96a8473195aa6bdbThe citation count drops by exactly the 80 rewritten tracker-number sites (the 81st site is the comment id, which the citation grammar does not read). The live counts did not move (src comment: 755 resolve, 19 as pull requests, 3 cross-repo; test comment: 382, 12 and 4). A third, raw reading (every
#followed by 2 to 6 digits, whatever surrounds it) counts 2,069 before and 1,989 after: also a drop of 80. The twoother filesrows left are a JSON string and a markdown line (see Sites left).Comment ids. Every ten-digit run under
packages/core(itsCHANGELOG.mdaside) was read. Three distinct comment ids are cited, on four lines:5257880748(auth-gate.test.ts:195, inside a verbatim quotation of a ruling) and5394453215(platform-admin.ts:5,resolve-authz-context.ts:1076) answer 200;5486840233(granted-permissions-not-enforced.pin.test.ts:9) answers 404 and is in this stage's population; the control5963404083(the claim) answers 200. The other runs are decimals, epochs and fixtures in tests, and two CI run ids inkernel.ts:33and:34, which are not citations of this tracker. Anissuecomment/discussion_rgrep finds no line (exit 1). After the rewrite,5486840233stands in 0 files underpackages/core.Per-number table
censuscounts census sites,outsidethe six sites outside the census glob,testthe test-comment sites. Every sha matches exactly one commit (git rev-parse --disambiguate, count 1) and is an ancestor of the basefd96a8473(git merge-base --is-ancestor, exit 0 for all 24; the clone is not shallow). The+lines carry exactly these 24 nine-hex spans as new ones (the one other span on a+line,abc4b83ce, was already on its line). Each commit names the number it replaces, in its message, its diff or both, exceptc49007a7c, whose message names#10869(see Wordings); each ADR anchor names its number or id in the cited section.git blameat the base puts 52 of the 76 commit-anchored lines on their anchor; the other 24 were written by a commit that cites the number as an earlier decision (for example07150b33aciting #16721's convergence,baf974527citing #16649's registration,82da264e1citing #6216's closed field set), and in each case the anchor is the commit that made the change the sentence credits to the number.sourcesays whether another lane or stage already used this anchor for this number (reused) or it was measured here (measured).#62068e13ca876accessible_org_idsis no longer dropped#6216f586f1a89#624183a3b1f2e:typesegment once per handler, closing the third plural-spelling bypass of the audience gate#67251507ba356MetadataFacadeobject writes reach the map its reads use#8734f8eb73601#109784c9780c7alimit, by presence#11330a9ee98992manifest.runtimetrust-tier text states publish-gate-only enforcement truthfully: the tier half of the same sentence#1133121ab410417: 「The enforce leg is unbuilt.」)#11333ea4d16420#13179fd289be45HotReloadManager's author-facing refusal messages and re-pin the twins (the 2026-08-29 family adjudication's member half); it wrote both test lines#132796a180e42d#133244cda78c9breadObject)#1364434ce8e7dbHookContext.referentialFieldClearand populate it on every set-null cleanup write#141924d0d9445aManifestSchemagoes strict#143867cbe705b0tsconfig.examples.json#14386c49007a7cplugin-hono-serverand put plugin-auth's published example in a tsc program: the example that 「could not resolve, compile or run for anyone who copied it」#1461381208086a@objectstack/coredeclares atypecheckscript; the test and examples layers enter the ratchet. It wrote all threetsconfiglines#14919cc00df2f7PluginSecurityScannerunder ADR-0049; its message records the 2026-09-05 ruling#16649613bfbd3ddoor: 'none'codes inERROR_CODE_LEDGER,PLUGIN_CONTRACT_VIOLATIONandSERVICE_NOT_REGISTEREDamong them#166829b9581b11is thesingle-posture selection repair, a different subject)singleone」).74832b68f, which wrote the line, quotes it too; the ADR comes first#1672151ae73123LiteKernel.use()enforces the declared plugin contract, converged withObjectKernel(step 2). Its message does not record the 2026-09-08 ruling, so the sites that name it keep its date; step 1 was a measurement with no commit of its own#1712486c505286dateRangearray that is not a two-bound window is refused once, instead of meaning three different things on four faces#17147aaacf1d5c#1714765481183b#17590e04a0aff2json-membership-sql.ts)$containson a JSON column as a per-dialect membership test, the construct that later moved here#1785308f5f0e5a5486840233No ADR or ruling record decides any of the 22 commit-anchored numbers:
git grepoverdocs/adrandscripts/adr-anchorsnames only two of the 24 numbers,#16682(ADR-0131, taken as that number's anchor) and#17147(ADR-0025 §3.7, only as the tracker of the unbuilt seam).Wordings to check
Most rewrites swap a tag in place (
[#N]to[commit SHA],(#N)to(commit SHA),since #Ntosince commit SHA,pre-#N XtoX before commit SHA). These say more than the tag:tsconfig.examples.json:22): 「That is the same shape [finding] check:type-check-coverage cannot see PACKAGE-ROOT source (depth 0 is skipped by construction) — three more objectstack.config.ts manifest sites sit outside every tsc program with no ledger entry #14386 found in plugin-auth's example (a published example that could not resolve, compile or run for anyone who copied it)」. That finding isc49007a7c's, word for word in its message (「the example could not resolve, compile or run for anyone who copied it」, 「Part ofplugin-auth/examples/basic-usage.tsimports@objectstack/plugin-hono-server, which the package declares in no dependency block #10869」), and plugin-auth's owntsconfig.examples.jsoncredits it toplugin-auth/examples/basic-usage.tsimports@objectstack/plugin-hono-server, which the package declares in no dependency block #10869;7cbe705b0([finding] check:type-check-coverage cannot see PACKAGE-ROOT source (depth 0 is skipped by construction) — three more objectstack.config.ts manifest sites sit outside every tsc program with no ledger entry #14386) widened that program to the package-root manifest. So the line reads 「the same shape commit c49007a found」, the anchor that does not name its number, as stage 3's#10629exception did. Line 2 of the same file pairs the program's origin and its widening, 「(plugin-auth/examples/basic-usage.tsimports@objectstack/plugin-hono-server, which the package declares in no dependency block #10869 / commit 7cbe705)」, and keeps the liveplugin-auth/examples/basic-usage.tsimports@objectstack/plugin-hono-server, which the package declares in no dependency block #10869.security/index.ts:41,plugin-artifact-integrity.ts:12and:13):#11331tracked the unpack-time integrity re-verification leg, which was never built, and no commit decides it (b60f48b52andf89812e4dkept the pointer; the cli lane left its three sites for that reason). The spec lane's stage 1 (21ab410417) wrote 「Enforce leg tracked onmanifest.integritydeclares per-file artifact digests the spec says the runtime re-verifies at unpack — nothing computes them and nothing checks them #11331.」 as 「The enforce leg is unbuilt.」. Here 「not by the cloud control plane (manifest.integritydeclares per-file artifact digests the spec says the runtime re-verifies at unpack — nothing computes them and nothing checks them #11331)」 became 「(that leg is unbuilt)」, and 「(tracked onmanifest.integritydeclares per-file artifact digests the spec says the runtime re-verifies at unpack — nothing computes them and nothing checks them #11331, NOT discharged by this module)」 became 「(that leg is unbuilt, and NOT discharged by this module)」. That second sentence wraps, so line 12, which carries no number, changed with line 13: 「(tracked on」 to 「(that leg is」. It is the only line without a number that changed.plugin-permission-enforcer.ts:119): 「the ADR-0025 materialize seam (Phase 1b of #11333: make the registered granted-permission set actually REFUSE — the ADR-0025 materialize seam that gives each plugin its own SecurePluginContext #17147, Phase 1b ofmanifest.permissionsis live on its LEGACYstring[]arm only — the structuredPluginPermissionsSchema(services / hooks / network / fs) has zero readers, and new code is told to prefer it #11333)」 became 「(measured and recorded in commit aaacf1d; the phase after commit ea4d164)」. The first half is the spec lane's wording for the same seam;ea4d16420's diff calls itself 「manifest.permissionsis live on its LEGACYstring[]arm only — the structuredPluginPermissionsSchema(services / hooks / network / fs) has zero readers, and new code is told to prefer it #11333 option A phase 1」.requiresService组件门禁在GET /meta/:type/:name的缓存分支(默认路径)被完全跳过 #5881, GET /meta/books/:name(复数拼写)绕过 ADR-0046 §6.7 audience 门禁 —— 缓存分支的 doc/book 排除写的是字面量比较 #6241)」 became 「bypasses (/meta 的每个按类型闸门只在单数拼写下生效 —— 复数(PD #3 的规范拼写)整条绕过,含 book audience、app RBAC、dashboard 能力门 #3984, ADR-0057 D10 的 dashboardrequiresService组件门禁在GET /meta/:type/:name的缓存分支(默认路径)被完全跳过 #5881, the one commit 83a3b1f closed)」 (metadata-service-contract.ts:44); 「(silent loss, theMetadataFacade.register('object', …)writes where neither of its own object reads look #6725 family)」 became 「(silent loss, the same family as the defect commit 1507ba3 fixed)」 (:68, the parenthesis opening on:67); 「MEASURED onabc4b83ce(A ONE-elementdateRangearray is schema-valid and means two different windows:ObjectQLStrategydegenerates it to the point[start, start], the draft-preview face leaves the upper bound open #17124)」 became 「(the defect commit 86c5052 fixed)」 (analytics-date-range-conformance.ts:124). Stage 7's form.LiteKernelnever runsPluginSchema, andisDefaultsurvives the kernel that does #16721, maintainer ruling 2026-09-08, option A)」 became 「(maintainer ruling 2026-09-08, option A, landed as commit 51ae731)」; 「[Decision] The declared plugin contract does not govern what the runtime accepts:LiteKernelnever runsPluginSchema, andisDefaultsurvives the kernel that does #16721, maintainer ruling 2026-09-08, option A under …」 became 「commit 51ae731 landed maintainer ruling 2026-09-08, option A under …」 (lite-kernel.ts:41, line 42 unchanged); 「(finding: ExecutionContext 在 dispatcher / REST / share-link 三处独立组装 —— 收敛为单一共享装配函数前,先裁决匿名面分歧 #6216 Option A)」 became 「(commit f586f1a, the ruled Option A)」, the plugin-hono-server lane's spelling.resolve-authz-context.ts:925): 「maintainer 2026-09-08 on plugin-security: the first-user promotion picks the oldest authenticable user from an UNORDERED 50-rowsys_userwindow, so on the default driver a seeded job seeker became platform admin and owned every seeded row #16682, verbatim: "The rest of Choice 4A …"」 became 「maintainer 2026-09-08, recorded in ADR-0131's 2026-09-17 amendment, verbatim:」. The quotation is untouched, including its live#11974. The first cut cited74832b68f; the ADR amendment that quotes the same sentence was found before the PR opened and replaced it in its own commit (a4c483901), ruling C's order.LiteKernelnever runsPluginSchema, andisDefaultsurvives the kernel that does #16721 was a measurement with no commit of its own: 「([Decision] The declared plugin contract does not govern what the runtime accepts:LiteKernelnever runsPluginSchema, andisDefaultsurvives the kernel that does #16721 step 1)」 became 「(step 1, before commit 51ae731)」 (lite-kernel.ts:48), and 「the wiring [Decision] The declared plugin contract does not govern what the runtime accepts:LiteKernelnever runsPluginSchema, andisDefaultsurvives the kernel that does #16721 step 1 measured with」 became 「the wiring step 1 (before commit 51ae731) measured with」 (plugin-contract-enforcement.test.ts:599). 「The two inputs [Decision] The declared plugin contract does not govern what the runtime accepts:LiteKernelnever runsPluginSchema, andisDefaultsurvives the kernel that does #16721 was filed on」 became 「The two inputs behind commit 51ae731」 (:472). 「the convergence [Decision] The declared plugin contract does not govern what the runtime accepts:LiteKernelnever runsPluginSchema, andisDefaultsurvives the kernel that does #16721 / ruled for the other eight keys」 became 「the convergence landed in commit 51ae731 as / ruled for the other eight keys」 (plugin-contract.ts:155, line 156 unchanged).pre-#N: 「pre-finding: ExecutionContext 在 dispatcher / REST / share-link 三处独立组装 —— 收敛为单一共享装配函数前,先裁决匿名面分歧 #6216 assembly」, 「pre-finding: ExecutionContext 在 dispatcher / REST / share-link 三处独立组装 —— 收敛为单一共享装配函数前,先裁决匿名面分歧 #6216 transcriptions」, 「verbatim, pre-finding: ExecutionContext 在 dispatcher / REST / share-link 三处独立组装 —— 收敛为单一共享装配函数前,先裁决匿名面分歧 #6216」 (twice), 「Pre-finding: ExecutionContext 在 dispatcher / REST / share-link 三处独立组装 —— 收敛为单一共享装配函数前,先裁决匿名面分歧 #6216 these two」, 「The pre-finding: ExecutionContext 在 dispatcher / REST / share-link 三处独立组装 —— 收敛为单一共享装配函数前,先裁决匿名面分歧 #6216 dispatcher」 and 「the pre-[finding] a permission-store read failure resolves as an AUTHENTICATED caller holding ZERO capabilities — the package door answers 403 FORBIDDEN, byte-identical to a genuine capability denial #13279return []」 became 「… before commit f586f1a」 / 「… before commit 6a180e4」, stage 1's form.5486840233, which assigns the per-plugin context to the ADR-0025 install-flow design effort」 became 「fenced by the maintainer ruling ADR-0025 §3.7 records, which assigns …」. §3.7's note (written byc1078a559) states that the ruling assigns that construction to the ADR's install-flow design work and forbids improvising it elsewhere;aaacf1d5c's message carries the same sentence.json-membership-sql.test.ts:6): 「moved here fromdriver-sql(driver-sql: the $contains MEMBERSHIP spelling on any multi-valued / JSON column is a DATABASE_ERROR 500 on live PostgreSQL (SQLSTATE 42883, operator does not exist: json ~~ text) — it has only ever been executed on SQLite #17590)」 became 「moved here fromdriver-sql, where commit e04a0af wrote it」, so the commit is not read as the move (which is58a77dbde, under the live [finding]$contains/$notContainson a declared multi-valued or JSON-stored field still answer SUBSTRING on five faces, the analytics RLS read scope among them (u1admits a row storingu10) #20987 on line 4).assemble-execution-context.test.ts:33,security-scanner-retirement.pin.test.ts:8andgranted-permissions-not-enforced.pin.test.ts:4are decorated rules; their dashes were not trimmed, so the change on each line is the citation alone.eslint.config.mjsdeclares no line-length rule, and a reflow would move neighbouring lines and every line citation into the file).Sites left
describeandittitles, assertion arguments):#62168 (assemble-execution-context.test.ts),#132797 (authz-store-unavailable.test.ts),#171472 (granted-permissions-not-enforced.pin.test.ts:120,:140),#8734,#10978,#13324,#14919and#167211 each. Every one of the 8 is in this stage's table. Strings are outside this stage's surface; non-test strings cite none.test-typecheck-debt.json:3names [finding]@objectstack/coredeclares notypecheckscript, so no CI job ever type-checks it — and its own tsconfig program is currently red #14613 inside the authored_notestring (a JSON string value, not a comment);PHASE2_IMPLEMENTATION.md:282namespackages/core/examples/phase2-integration.tsis the sole composer ofPluginSecurityScanner, which FOLLOW-UPS.md already records as exported dead code with 3 of 5 scan methods empty stubs — repair it, or retire it as #4939 did to its neighbour? #14919 in markdown prose (not a comment or docblock, and not infiles[]). Both anchors are in this stage's table (81208086a,cc00df2f7).src: the release-ownedCHANGELOG.mdnames dead numbers on 21 sites; left.Mechanical guard: no code token moves
The guard (stages 2 to 7's) compares base
fd96a8473against the tree over all 34 touched files, with TypeScript 6.0.3; the threetsconfig*.jsonfiles are parsed withts.parseJsonText. It ran at195aa6bdbwith the controls below, and again at the heada4c483901: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, JSDoc nodes skipped. String, template and numeric literals are compared in full on both readings.Results:
resolve-authz-context.ts): 0 files changed (exit 0).PLUGIN_CONTRACT_VIOLATION_CODEto…CODEX,plugin-contract.ts): DIFFER on both readings (exit 1).'SERVICE_NOT_REGISTERED'to'SERVICE_NOT_REGISTEREDX',service-not-registered.ts): DIFFER on both readings (exit 1).'b'.repeat(24)to25,api-key.test.ts): DIFFER on both readings (exit 1)."noEmit": truetofalse,tsconfig.test.json): DIFFER on both readings (exit 1).Each mutation went through
scripts/ablation-replace.mjs(wrap mode, anchor hit 1 to 0, blob changed) under a shell trap that restores by absolute path fromHEAD. Each restore was proven equal to itsHEADblob (ca0fbe39fd18,362e8a56a1b9,d36529c990a5,5ebcb9050807,d51f5f214b09), withgit diff HEADempty and a clean tree afterwards.Changeset:
patch(distmeasured)files[]isdist,README.mdandCHANGELOG.md, and the package is not private. In one script under the shared verify lock (VERDICT command-exit 0, held 355s), at195aa6bdb: the workspace was built first (turbo run build --filter='./packages/*' --filter='./packages/*/*' --concurrency=2, 71 of 71 tasks, 1 cached), then the package's ownbuild(tsup,check-dts-emittedand the dev-prereqs stamp) ran three times:distfiles hashed. Of the 40 rewritten non-test lines, 21 appear verbatim indist(docblocks on exported members inindex.d.ts/index.d.cts; thelite-kernel.ts,plugin-loader.tsandplugin-permission-enforcer.tsones also inindex.js/index.cjs).index.js,index.cjs,index.d.ts,index.d.cts, and the two build-input hash stamps), andscripts/ablation-dist-preflight.mjsfinds the base marker 「[[finding] a permission-store read failure resolves as an AUTHENTICATED caller holding ZERO capabilities — the package door answers 403 FORBIDDEN, byte-identical to a genuine capability denial #13279] This function used」 in 2 built files (index.d.ts,index.d.cts; exit 0).HEADblob,git diff HEADempty, porcelain empty): all 14 files are byte-identical to leg 1, and the preflight's--absentreading exits 0 with a clean tree, so the build is deterministic and the difference is the rewrite.So the rewrite ships, and
.changeset/20595-core-provenance-anchors.mddeclares apatchfor@objectstack/core, comment text only, with the claim'sClause-②: noline. The changeset commit touches no file underpackages/core. The one linea4c483901changed after the legs is a//comment inside a function body: its text as built in leg 3 is in nodistfile (grep exit 1), while a docblock line of the same build is in all fourindexfiles (since commit 51ae73123 it is ONE statement, the control), so that commit moves no shipped byte.Gates (head
a4c483901)node scripts/pm/dispatch-gates.mjs --repo objectstack-ai/objectstack --commandsata4c483901(35 paths against merge base6f17d1d36, 179 changed lines) derived 65 commands. All 65 ran, each exit code captured before any pipe: 65 exit 0.--ranreports 「65 derived, 65 run, 0 NOT-MEASURED, 0 UNRUN」 (a derived zero) and exits 0. The PM's lead derivation (55 commands, tree6210f887) is a subset: the extra 10 arecheck:authz-resolverandcheck:dispatcher-error-vocabulary, which this package's paths add, and the 8 changeset families.node scripts/check-changeset-fixed.mjs,pnpm check:error-code-casing,pnpm check:filter-alias-parity,pnpm check:tenant-chokepointandpnpm check:object-def-param-keys: 5 exit 0.node scripts/check-issue-citations.mjsexits 0 (「every citation this change adds resolves (or is a declared cross-repo reference)」: 6 judged across 17 files, all 6 resolve; they are the live numbers kept on changed lines);pnpm check:issue-citationsexits 0 (self-test);pnpm check:doc-authoringexits 0 (the sibling-package prose-id baseline holds, no growth);pnpm check:nul-bytesexits 0 (9,851 files, no raw control bytes), and a control-byte grep over the 35 changed files finds none (exit 1).a4c483901(VERDICT command-exit 0, held 64s):pnpm --filter @objectstack/core test(vitest projectlocal): 76 test files pass (76), 2,156 tests pass (2,156);pnpm --filter @objectstack/core exec vitest run --project repo --maxWorkers=2(the three repo-reading testsvitest.repo-tests.jsonlists, two of them touched here): 3 files pass, 48 tests pass;pnpm --filter @objectstack/core typecheck(tsc --noEmit,tsc --noEmit -p tsconfig.examples.json, thencheck:test-typecheck: 「4 file(s) / 4 error(s) / 4 pinned signature(s) held」) exits 0. The same three were green at67ef07870, before the last commit.tsc --listFilesOnlyputs all 79 tracked test files intsconfig.test.json's program and the 17 changed non-testsrcfiles intsconfig.json's.a4c483901: eslint with inline config disabled, over the 31 touched.tsfiles plusdist/index.jsas the control: 32 results, 0 errors and 1 warning, the control's ignore notice; none of the 31 is reported ignored. The threetsconfig*.jsonfiles answer 「File ignored because no matching configuration was supplied」 (not eslint targets).eslint.config.mjsnever enables type-aware linting (its lines 327 and 328 say so), so a comment edit cannot move the verdict on an untouched file. The repo-widepnpm lintis CI's run.Acceptance notes
fd96a8473and mergesmainonce, pinned to6f17d1d36(merge67ef07870, no conflict). The two commits it brought (9ff74285f, CI test-shard scripts;6f17d1d36,plugin-approvals) touch neitherpackages/core,check-issue-citations.mjsnordispatch-gates.mjs;plugin-approvalswas rebuilt after the merge, before the tests and gates. The net diff againstmainis the 34 rewritten files (+81/−81) and the changeset (+17).server.jsonfor the official MCP registry, in this repo, from the shipped surface (the dev half of #20791) #21494, and the third run at the head saw no movement.scripts/check-meta-type-normalized.mjsnames GET /meta/books/:name(复数拼写)绕过 ADR-0046 §6.7 audience 门禁 —— 缓存分支的 doc/book 排除写的是字面量比较 #6241 in its header and its failure text (outside the census surface, and a gate script, which a citation stage does not edit);docs/adr/0025-plugin-package-distribution.md§3.7 names Phase 1b of #11333: make the registered granted-permission set actually REFUSE — the ADR-0025 materialize seam that gives each plugin its own SecurePluginContext #17147 and the comment id5486840233, and ADR-0131's amendment names plugin-security: the first-user promotion picks the oldest authenticable user from an UNORDERED 50-rowsys_userwindow, so on the default driver a seeded job seeker became platform admin and owned every seeded row #16682 and its comment5587754690, which also answers 404 (both governed, Tier H; the amendment's quotation is what this stage anchors to, and it stays legible whatever the links answer);packages/clikeeps its threemanifest.integritydeclares per-file artifact digests the spec says the runtime re-verifies at unpack — nothing computes them and nothing checks them #11331 sites, which the cli lane left for want of a deciding commit, and this stage's wording is there for whoever takes them; driver-sql: the $contains MEMBERSHIP spelling on any multi-valued / JSON column is a DATABASE_ERROR 500 on live PostgreSQL (SQLSTATE 42883, operator does not exist: json ~~ text) — it has only ever been executed on SQLite #17590 stands atpackages/spec/src/data/filter.zod.ts:1067in the spec lane's population, wheree04a0aff2is the anchor.plugin-artifact-integrity.ts:12, no line without a number was changed.Generated by Claude Code