Skip to content

Commit c205b6c

Browse files
docs(core): re-anchor the dead tracker citations to the commits and ADRs that decided them (stage 8 of #20595) (#21506)
Part of #20595 Clause-②: no ## What changed Stage 8 of the `domain:engine` lane of the dead-citation sweep: `packages/core/**`, comment and docblock prose only, per the claim (`5963404083`). Stages 1 to 7 landed as `a7d9768ec`, `d150c3039`, `4bf4e7e70`, `13a24ece2`, `db0cf2231`, `85986144c` and `48fa7a381`. #20595 stays open: the other half of this lane is the packages this stage does not touch (`metadata-core` 19, `drivers/driver-turso` 14, `drivers/driver-mongodb` 9, `formula` 4, `metadata-fs` 2 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 `5749154545` on #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**: - **40 census sites** (39 lines, 17 files under `src/`): the whole `allocated-but-absent` population of the gate's own census in this package at the base. `plugin-permission-enforcer.ts:119` carries two numbers on one line; - **6 sites outside the census glob, inside the claimed surface**: `vitest.config.ts:21` (#17853, a `//` line), and five `//` lines in three JSON-with-comments files, `tsconfig.examples.json:1`, `:2` and `:22` (#14613, #14386 twice), `tsconfig.json:30` and `tsconfig.test.json:1` (#14613). These follow stage 1's `tsup.config.ts`, stage 5's `tsconfig.typecheck.json` and stage 7's `tsconfig.scripts.json` precedents; - **34 test-comment sites** (34 lines, 13 test files), which the census defers. They carry 11 numbers: 6 the census itself reads as dead in this package's `src` (#6216, #8734, #13279, #14919, #16721, #17147), 1 it reads as dead elsewhere (#17590, at `packages/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 (#10978, #11330, #13179, #14613), which the board and a single read each settle; - **1 dead comment-id citation**: `granted-permissions-not-enforced.pin.test.ts:9` named maintainer ruling `5486840233`, 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` (`7cbe705b0` for the plugin-auth program's widening, `c49007a7c` for the finding the sentence describes, see Wordings) and `#17147` (`aaacf1d5c` for the pin and the seam, `65481183b` for the pin's follow-up). `#11333` and `#17147` share one line. 19 numbers reuse the anchor another lane or stage already used for them; measured here are 5 commits (`fd289be45` for #13179, `cc00df2f7` for #14919, `7cbe705b0` and `c49007a7c` for #14386, `65481183b` for #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 `#16682` anchor (`9b9581b11`) was not taken: it is a different subject (see the table). `#11331` takes 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 `patch` changeset**: 21 of the 40 rewritten non-test lines are in the published `dist` (the `.d.ts` keeps JSDoc on exported members, and esbuild keeps some comments in the JS), and `dist` is 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 --json` at base `fd96a8473` (the before run below), `allocated-but-absent` per remaining `domain:engine` package: | package | before | after this stage | |---|---|---| | `core` | **40** | **0** | | `metadata-core` | 19 | 19 | | `drivers/driver-turso` | 14 | 14 | | `drivers/driver-mongodb` | 9 | 9 | | `formula` | 4 | 4 | | `metadata-fs` | 2 | 2 | | `metadata-protocol`, `objectql`, `metadata`, `drivers/driver-sql`, `drivers/driver-memory`, `drivers/driver-sqlite-wasm`, `plugins/plugin-pinyin-search`, `platform-objects` | 0 each | 0 each | The lane total goes 88 to 48. `core` is the largest remaining package and reads 40, as at stage 7's census (`e5d9a5d85`), so the stage went ahead. ## Census: `core`, before and after **Instrument (A1).** The gate's own `node scripts/check-issue-citations.mjs --census --json`, read-only and unchanged. The count is its `allocated-but-absent` findings under `packages/core/`. | reading | tree | board | whole-repo `allocated-but-absent` | sites | lines | files | numbers | |---|---|---|---|---|---|---|---| | before | base `fd96a8473`, run 00:07:44Z to 00:11:10Z | enumerated, 194 pages, frontier #21494, 19,315 records (newest number read before and after the run: #21494) | 203 | **40** | 39 | 17 | 17 | | after | `195aa6bdb`, run 00:27:00Z to 00:30:25Z | enumerated, 194 pages, frontier #21498, 19,319 records (newest #21495 before, #21498 after) | 163 | **0** | 0 | 0 | 0 | The 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) and `cross-repo-unjudged` (1,243) did not move. The head's later commits are the changeset, one merge of `main`, and one comment line in `resolve-authz-context.ts` (the ADR re-anchor of `:925`, which adds and removes no number). The census was run a third time at the head `a4c483901` (00:50:57Z to 00:54:06Z, 194 pages, frontier #21504, 19,325 records, newest #21504 before and after): whole-repo 163, `core` 0, and its `allocated-but-absent` finding set is identical to the after run's (0 removed, 0 added). Its `resolves` reads 35,441, 13 more than above, from the merged `main` commits 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 exported `extractCitations` (whole-file and comment-prose projections) over every tracked file in the package (175) and classifies each citation with the gate's `classifyCitation` against one board enumerated by the gate's `enumerateBoard` (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 `#5286` and `#12624` answer 200, and so do the numbers that stay on changed lines (#3984, #5881, #6551, #10869, #11974, #16404, #17978). | reading | citations | dead | src comment | test comment | `vitest.config.ts` comment | other files (`tsconfig*.json` / rest) | test string | changelog | |---|---|---|---|---|---|---|---|---| | before, `fd96a8473` | 2,048 | **125** | 40 | 34 | 1 | 5 / 2 | 22 | 21 | | after, `195aa6bdb` | 1,968 | **45** | 0 | 0 | 0 | 0 / 2 | 22 | 21 | The 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 two `other files` rows left are a JSON string and a markdown line (see Sites left). **Comment ids.** Every ten-digit run under `packages/core` (its `CHANGELOG.md` aside) was read. Three distinct comment ids are cited, on four lines: `5257880748` (`auth-gate.test.ts:195`, inside a verbatim quotation of a ruling) and `5394453215` (`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 control `5963404083` (the claim) answers 200. The other runs are decimals, epochs and fixtures in tests, and two CI run ids in `kernel.ts:33` and `:34`, which are not citations of this tracker. An `issuecomment` / `discussion_r` grep finds no line (exit 1). After the rewrite, `5486840233` stands in 0 files under `packages/core`. ## Per-number table `census` counts census sites, `outside` the six sites outside the census glob, `test` the test-comment sites. Every sha matches exactly one commit (`git rev-parse --disambiguate`, count 1) and is an ancestor of the base `fd96a8473` (`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, except `c49007a7c`, whose message names `#10869` (see Wordings); each ADR anchor names its number or id in the cited section. `git blame` at 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 example `07150b33a` citing #16721's convergence, `baf974527` citing #16649's registration, `82da264e1` citing #6216's closed field set), and in each case the anchor is the commit that made the change the sentence credits to the number. `source` says whether another lane or stage already used this anchor for this number (`reused`) or it was measured here (`measured`). | number | census | outside | test | anchor | kind | source | what it decided | |---|---|---|---|---|---|---|---| | `#6206` | 2 | 0 | 0 | `8e13ca876` | commit | reused (the rest, plugin-security and plugin-sharing lanes) | share-link enforcement takes the whole authz envelope, so `accessible_org_ids` is no longer dropped | | `#6216` | 8 | 0 | 8 | `f586f1a89` | commit | reused (the rest, runtime, mcp, spec, plugin-hono-server and plugin-security lanes) | one ExecutionContext assembler with two named anonymous entries; the frozen parity pins and the closed entry field set. Its message does not record the 2026-08-08 ruling, so the sites that name the ruling keep its date | | `#6241` | 1 | 0 | 0 | `83a3b1f2e` | commit | reused (the rest lane) | normalize the `:type` segment once per handler, closing the third plural-spelling bypass of the audience gate | | `#6725` | 1 | 0 | 0 | `1507ba356` | commit | reused (stage 3; the spec lane) | `MetadataFacade` object writes reach the map its reads use | | `#8734` | 2 | 0 | 1 | `f8eb73601` | commit | reused (the plugin-auth lane) | bind the last-admin standing-key lists to the authz resolver's measured read surface | | `#10978` | 0 | 0 | 5 | `4c9780c7a` | commit | reused (stage 2; the runtime lane) | authorization ObjectQL doubles enforce `limit`, by presence | | `#11330` | 0 | 0 | 2 | `a9ee98992` | commit | reused (the spec lane) | the `manifest.runtime` trust-tier text states publish-gate-only enforcement truthfully: the tier half of the same sentence | | `#11331` | 2 | 0 | 0 | none | words | the spec lane's form (`21ab410417`: 「The enforce leg is unbuilt.」) | it tracked the unpack-time integrity re-verification leg, which was never built; no commit or ADR decides it | | `#11333` | 1 | 0 | 0 | `ea4d16420` | commit | reused (the runtime lane) | option A phase 1 of that card, binding an artifact's granted permissions at load (its diff says so); the site names the phase after it | | `#13179` | 0 | 0 | 2 | `fd289be45` | commit | measured | strip the tracker ids from `HotReloadManager`'s author-facing refusal messages and re-pin the twins (the 2026-08-29 family adjudication's member half); it wrote both test lines | | `#13279` | 7 | 0 | 2 | `6a180e42d` | commit | reused (stages 4 and 6; the service-settings, plugin-hono-server and cloud-connection lanes) | fail loud when a permission-store read fails; its message records the 2026-08-30 ruling verbatim | | `#13324` | 1 | 0 | 0 | `4cda78c9b` | commit | reused (stages 1, 4 and 6; the types lane) | a missing-table error must name the table that was read (`readObject`) | | `#13644` | 1 | 0 | 0 | `34ce8e7db` | commit | reused (stage 3) | declare `HookContext.referentialFieldClear` and populate it on every set-null cleanup write | | `#14192` | 1 | 0 | 0 | `4d0d9445a` | commit | reused (the cli and spec lanes, for the same 「strictObject since」 sentence) | `ManifestSchema` goes strict | | `#14386` | 0 | 1 | 0 | `7cbe705b0` | commit | measured | put three more package-root plugin manifests inside a tsc program; it widened plugin-auth's `tsconfig.examples.json` | | `#14386` | 0 | 1 | 0 | `c49007a7c` | commit | measured | declare `plugin-hono-server` and put plugin-auth's published example in a tsc program: the example that 「could not resolve, compile or run for anyone who copied it」 | | `#14613` | 0 | 3 | 2 | `81208086a` | commit | reused (the rest lane) | `@objectstack/core` declares a `typecheck` script; the test and examples layers enter the ratchet. It wrote all three `tsconfig` lines | | `#14919` | 1 | 0 | 1 | `cc00df2f7` | commit | measured | retire `PluginSecurityScanner` under ADR-0049; its message records the 2026-09-05 ruling | | `#16649` | 2 | 0 | 0 | `613bfbd3d` | commit | reused (stage 4; the runtime and spec lanes) | register the fourteen remaining `door: 'none'` codes in `ERROR_CODE_LEDGER`, `PLUGIN_CONTRACT_VIOLATION` and `SERVICE_NOT_REGISTERED` among them | | `#16682` | 1 | 0 | 0 | ADR-0131's 2026-09-17 amendment | ADR | measured (the plugin-security lane's `9b9581b11` is the `single`-posture selection repair, a different subject) | the amendment's 「What the ruling did NOT decide」 section quotes the 2026-09-08 ruling verbatim and untranslated, the sentence this site quotes (「retiring the walled write must not retire the `single` one」). `74832b68f`, which wrote the line, quotes it too; the ADR comes first | | `#16721` | 7 | 0 | 8 | `51ae73123` | commit | reused (the cli and plugin-hono-server lanes) | `LiteKernel.use()` enforces the declared plugin contract, converged with `ObjectKernel` (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 | | `#17124` | 1 | 0 | 0 | `86c505286` | commit | reused (the service-analytics lane) | a `dateRange` array that is not a two-bound window is refused once, instead of meaning three different things on four faces | | `#17147` | 1 | 0 | 1 | `aaacf1d5c` | commit | reused (the spec and runtime lanes) | the install-time granted permission set is registered at load and refuses nothing: say so, and pin the measurement. It created the pin file | | `#17147` | 0 | 0 | 1 | `65481183b` | commit | measured | the pin's follow-up: sweep the retracted phrasing repo-wide instead of reading one file. It wrote the line | | `#17590` | 0 | 0 | 1 | `e04a0aff2` | commit | reused (stages 4 and 5; this package's own `json-membership-sql.ts`) | compile `$contains` on a JSON column as a per-dialect membership test, the construct that later moved here | | `#17853` | 0 | 1 | 0 | `08f5f0e5a` | commit | reused (stage 3; the cli, rest, runtime, types and dogfood lanes, for the same line) | a vitest filter that selects no test file says so | | comment `5486840233` | 0 | 0 | 1 | ADR-0025 §3.7 | ADR | measured | the ruling that fences per-plugin context construction to ADR-0025's install-flow design work; §3.7 records that fence | No ADR or ruling record decides any of the 22 commit-anchored numbers: `git grep` over `docs/adr` and `scripts/adr-anchors` names 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 #N` to `since commit SHA`, `pre-#N X` to `X before commit SHA`). These say more than the tag: - **The sentence credits a finding to the wrong number** (`tsconfig.examples.json:22`): 「That is the same shape #14386 found in plugin-auth's example (a published example that could not resolve, compile or run for anyone who copied it)」. That finding is `c49007a7c`'s, word for word in its message (「the example could not resolve, compile or run for anyone who copied it」, 「Part of #10869」), and plugin-auth's own `tsconfig.examples.json` credits it to #10869; `7cbe705b0` (#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 `#10629` exception did. Line 2 of the same file pairs the program's origin and its widening, 「(#10869 / commit 7cbe705)」, and keeps the live #10869. - **By words, the spec lane's form** (`security/index.ts:41`, `plugin-artifact-integrity.ts:12` and `:13`): `#11331` tracked the unpack-time integrity re-verification leg, which was never built, and no commit decides it (`b60f48b52` and `f89812e4d` kept the pointer; the cli lane left its three sites for that reason). The spec lane's stage 1 (`21ab410417`) wrote 「Enforce leg tracked on #11331.」 as 「The enforce leg is unbuilt.」. Here 「not by the cloud control plane (#11331)」 became 「(that leg is unbuilt)」, and 「(tracked on #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. - **The two numbers on one line** (`plugin-permission-enforcer.ts:119`): 「the ADR-0025 materialize seam (#17147, Phase 1b of #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 「#11333 option A phase 1」. - **A defect, not a change**: 「bypasses (#3984, #5881, #6241)」 became 「bypasses (#3984, #5881, the one commit 83a3b1f closed)」 (`metadata-service-contract.ts:44`); 「(silent loss, the #6725 family)」 became 「(silent loss, the same family as the defect commit 1507ba3 fixed)」 (`:68`, the parenthesis opening on `:67`); 「MEASURED on `abc4b83ce` (#17124)」 became 「(the defect commit 86c5052 fixed)」 (`analytics-date-range-conformance.ts:124`). Stage 7's form. - **Rulings the anchor's message does not record keep their date**: 「The maintainer ruling of 2026-08-08 on #6216 (Option A)」 became 「The maintainer ruling of 2026-08-08 (Option A, landed as commit f586f1a)」; 「(#16721, maintainer ruling 2026-09-08, option A)」 became 「(maintainer ruling 2026-09-08, option A, landed as commit 51ae731)」; 「#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); 「(#6216 Option A)」 became 「(commit f586f1a, the ruled Option A)」, the plugin-hono-server lane's spelling. - **The quoted ruling** (`resolve-authz-context.ts:925`): 「maintainer 2026-09-08 on #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 cited `74832b68f`; 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. - **Step 1 of #16721** was a measurement with no commit of its own: 「(#16721 step 1)」 became 「(step 1, before commit 51ae731)」 (`lite-kernel.ts:48`), and 「the wiring #16721 step 1 measured with」 became 「the wiring step 1 (before commit 51ae731) measured with」 (`plugin-contract-enforcement.test.ts:599`). 「The two inputs #16721 was filed on」 became 「The two inputs behind commit 51ae731」 (`:472`). 「the convergence #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-#6216 assembly」, 「pre-#6216 transcriptions」, 「verbatim, pre-#6216」 (twice), 「Pre-#6216 these two」, 「The pre-#6216 dispatcher」 and 「the pre-#13279 `return []`」 became 「… before commit f586f1a」 / 「… before commit 6a180e4」, stage 1's form. - **The comment id**: 「fenced by maintainer ruling `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 by `c1078a559`) 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. - **The moved construct** (`json-membership-sql.test.ts:6`): 「moved here from `driver-sql` (#17590)」 became 「moved here from `driver-sql`, where commit e04a0af wrote it」, so the commit is not read as the move (which is `58a77dbde`, under the live #20987 on line 4). - **Follow-up and rule lines**: 「[#17147 follow-up]」 became 「[commit 6548118, the follow-up]」. `assemble-execution-context.test.ts:33`, `security-scanner-retirement.pin.test.ts:8` and `granted-permissions-not-enforced.pin.test.ts:4` are decorated rules; their dashes were not trimmed, so the change on each line is the citation alone. - No line was reflowed, so some are longer than their block's wrap (`eslint.config.mjs` declares no line-length rule, and a reflow would move neighbouring lines and every line citation into the file). ## Sites left - **In comments (src, test, outside the glob): none.** - **String literals: 22 test-string sites, 8 numbers, 7 files** (`describe` and `it` titles, assertion arguments): `#6216` 8 (`assemble-execution-context.test.ts`), `#13279` 7 (`authz-store-unavailable.test.ts`), `#17147` 2 (`granted-permissions-not-enforced.pin.test.ts:120`, `:140`), `#8734`, `#10978`, `#13324`, `#14919` and `#16721` 1 each. Every one of the 8 is in this stage's table. Strings are outside this stage's surface; non-test strings cite none. - **Outside comment prose**: `test-typecheck-debt.json:3` names #14613 inside the authored `_note` string (a JSON string value, not a comment); `PHASE2_IMPLEMENTATION.md:282` names #14919 in markdown prose (not a comment or docblock, and not in `files[]`). Both anchors are in this stage's table (`81208086a`, `cc00df2f7`). - **Outside `src`:** the release-owned `CHANGELOG.md` names dead numbers on 21 sites; left. ## Mechanical guard: no code token moves The guard (stages 2 to 7's) compares base `fd96a8473` against the tree over all 34 touched files, with TypeScript 6.0.3; the three `tsconfig*.json` files are parsed with `ts.parseJsonText`. It ran at `195aa6bdb` with the controls below, and again at the head `a4c483901`: - **Reading 1**: the parser's leaf nodes, from a `forEachChild` walk. Comments are trivia there, and JSDoc is never visited. A leaf that is not itself a token is re-scanned with trivia skipped. - **Reading 2**: the full token stream in parser context, from a `getChildren` walk, JSDoc nodes skipped. String, template and numeric literals are compared in full on both readings. Results: - Real run: 50,680 base tokens, **0 files with a token change** (exit 0), at both trees. - Comment control (「distinguish the two」 to 「DISTINGUISH the two」, `resolve-authz-context.ts`): 0 files changed (exit 0). - Positive control, an identifier (`PLUGIN_CONTRACT_VIOLATION_CODE` to `…CODEX`, `plugin-contract.ts`): DIFFER on both readings (exit 1). - Positive control, a string literal (`'SERVICE_NOT_REGISTERED'` to `'SERVICE_NOT_REGISTEREDX'`, `service-not-registered.ts`): DIFFER on both readings (exit 1). - Positive control, a numeric literal (`'b'.repeat(24)` to `25`, `api-key.test.ts`): DIFFER on both readings (exit 1). - Positive control, a JSON value (`"noEmit": true` to `false`, `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 from `HEAD`. Each restore was proven equal to its `HEAD` blob (`ca0fbe39fd18`, `362e8a56a1b9`, `d36529c990a5`, `5ebcb9050807`, `d51f5f214b09`), with `git diff HEAD` empty and a clean tree afterwards. ## Changeset: `patch` (`dist` measured) `files[]` is `dist`, `README.md` and `CHANGELOG.md`, and the package is not private. In one script under the shared verify lock (VERDICT command-exit 0, held 355s), at `195aa6bdb`: the workspace was built first (`turbo run build --filter='./packages/*' --filter='./packages/*/*' --concurrency=2`, 71 of 71 tasks, 1 cached), then the package's own `build` (tsup, `check-dts-emitted` and the dev-prereqs stamp) ran three times: - **Leg 1**, the head text: 14 `dist` files hashed. Of the 40 rewritten non-test lines, 21 appear verbatim in `dist` (docblocks on exported members in `index.d.ts` / `index.d.cts`; the `lite-kernel.ts`, `plugin-loader.ts` and `plugin-permission-enforcer.ts` ones also in `index.js` / `index.cjs`). - **Leg 2**, the base text put back in the 17 non-test touched files (17 of 17 proven equal to their base blob): 6 of the 14 files differ from leg 1 (`index.js`, `index.cjs`, `index.d.ts`, `index.d.cts`, and the two build-input hash stamps), and `scripts/ablation-dist-preflight.mjs` finds the base marker 「[#13279] This function used」 in 2 built files (`index.d.ts`, `index.d.cts`; exit 0). - **Leg 3**, after the proven restore (17 of 17 equal to their `HEAD` blob, `git diff HEAD` empty, porcelain empty): all 14 files are byte-identical to leg 1, and the preflight's `--absent` reading 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.md` declares a `patch` for `@objectstack/core`, comment text only, with the claim's `Clause-②: no` line. The changeset commit touches no file under `packages/core`. The one line `a4c483901` changed after the legs is a `//` comment inside a function body: its text as built in leg 3 is in no `dist` file (grep exit 1), while a docblock line of the same build is in all four `index` files (`since commit 51ae731 it is ONE statement`, the control), so that commit moves no shipped byte. ## Gates (head `a4c483901`) - **Derived gates:** `node scripts/pm/dispatch-gates.mjs --repo objectstack-ai/objectstack --commands` at `a4c483901` (35 paths against merge base `6f17d1d36`, 179 changed lines) derived 65 commands. All 65 ran, each exit code captured before any pipe: 65 exit 0. `--ran` reports 「65 derived, 65 run, 0 NOT-MEASURED, 0 UNRUN」 (a derived zero) and exits 0. The PM's lead derivation (55 commands, tree `6210f887`) is a subset: the extra 10 are `check:authz-resolver` and `check:dispatcher-error-vocabulary`, which this package's paths add, and the 8 changeset families. - **Roster families under touched directories**, run as well: `node scripts/check-changeset-fixed.mjs`, `pnpm check:error-code-casing`, `pnpm check:filter-alias-parity`, `pnpm check:tenant-chokepoint` and `pnpm check:object-def-param-keys`: 5 exit 0. - **Named readings:** `node scripts/check-issue-citations.mjs` exits 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-citations` exits 0 (self-test); `pnpm check:doc-authoring` exits 0 (the sibling-package prose-id baseline holds, no growth); `pnpm check:nul-bytes` exits 0 (9,851 files, no raw control bytes), and a control-byte grep over the 35 changed files finds none (exit 1). - **Tests and typecheck, under the verify lock, at `a4c483901`** (VERDICT command-exit 0, held 64s): `pnpm --filter @objectstack/core test` (vitest project `local`): 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 tests `vitest.repo-tests.json` lists, two of them touched here): 3 files pass, 48 tests pass; `pnpm --filter @objectstack/core typecheck` (`tsc --noEmit`, `tsc --noEmit -p tsconfig.examples.json`, then `check:test-typecheck`: 「4 file(s) / 4 error(s) / 4 pinned signature(s) held」) exits 0. The same three were green at `67ef07870`, before the last commit. `tsc --listFilesOnly` puts all 79 tracked test files in `tsconfig.test.json`'s program and the 17 changed non-test `src` files in `tsconfig.json`'s. - **Lint, as a proven narrowing, at `a4c483901`:** eslint with inline config disabled, over the 31 touched `.ts` files plus `dist/index.js` as the control: 32 results, 0 errors and 1 warning, the control's ignore notice; none of the 31 is reported ignored. The three `tsconfig*.json` files answer 「File ignored because no matching configuration was supplied」 (not eslint targets). `eslint.config.mjs` never 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-wide `pnpm lint` is CI's run. ## Acceptance notes - **Base and merge.** The branch was cut at `fd96a8473` and merges `main` once, pinned to `6f17d1d36` (merge `67ef07870`, no conflict). The two commits it brought (`9ff74285f`, CI test-shard scripts; `6f17d1d36`, `plugin-approvals`) touch neither `packages/core`, `check-issue-citations.mjs` nor `dispatch-gates.mjs`; `plugin-approvals` was rebuilt after the merge, before the tests and gates. The net diff against `main` is the 34 rewritten files (+81/−81) and the changeset (+17). - **The census frontier moved during the after run** (newest #21495 before, #21498 after; the board's frontier is #21498). Nothing in this package's reading depends on numbers above #21494, and the third run at the head saw no movement. - **The same dead numbers outside this package**, each left to its own carrier: `scripts/check-meta-type-normalized.mjs` names #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 #17147 and the comment id `5486840233`, and ADR-0131's amendment names #16682 and its comment `5587754690`, 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/cli` keeps its three #11331 sites, which the cli lane left for want of a deciding commit, and this stage's wording is there for whoever takes them; #17590 stands at `packages/spec/src/data/filter.zod.ts:1067` in the spec lane's population, where `e04a0aff2` is the anchor. - **Wording only:** apart from `plugin-artifact-integrity.ts:12`, no line without a number was changed. --- _Generated by [Claude Code](https://claude.ai/code/session_01DDZNkDVwPQnevTFcYE47H3)_ --------- Co-authored-by: Claude <noreply@anthropic.com>
1 parent 529d971 commit c205b6c

35 files changed

Lines changed: 101 additions & 81 deletions
Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
---
2+
'@objectstack/core': patch
3+
---
4+
5+
Provenance comments in `@objectstack/core` cite the commits that decided them, not tracker numbers that no longer resolve
6+
7+
Clause-②: no
8+
9+
Docblocks and comments across the package cited issue-tracker numbers that now answer 404 on GitHub.
10+
Each now cites the commit in this repository's history that made the decision it describes, except
11+
three source comments: one in `resolve-authz-context.ts` that quotes a maintainer ruling now cites
12+
ADR-0131's 2026-09-17 amendment, which records that ruling verbatim, and two on the unpack-time
13+
integrity re-verification leg, which pointed at a tracker for work that was never built, now say in
14+
words that the leg is unbuilt. One test comment named a maintainer-ruling comment that also answers
15+
404; it now cites ADR-0025 §3.7, which records that ruling's effect. Some of these docblocks sit on
16+
exported members, so the reworded text appears in the published declaration files (`index.d.ts` /
17+
`index.d.cts`), and the comments esbuild keeps appear in the JavaScript output (`index.js` /
18+
`index.cjs`).
19+
20+
Comment only: no export, type, error code, status, message text or runtime behaviour changes.

‎packages/core/src/artifact-packages.ts‎

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -89,7 +89,7 @@
8989
* not disagree.
9090
*
9191
* ⛔ The other half of that reason — "and Zod strips undeclared keys" — is GONE,
92-
* not merely reworded. `ManifestSchema` is `strictObject` since #14192 and
92+
* not merely reworded. `ManifestSchema` is `strictObject` since commit 4d0d9445a and
9393
* `AssembledPackageBodySchema` inherits the closed posture through `.extend()`,
9494
* so an undeclared key on an entry is REFUSED by this very parse, by name, and
9595
* never reaches a clone to be dropped from. Defaults are what still move bytes;

‎packages/core/src/hot-reload.test.ts‎

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -260,7 +260,7 @@ describe('[#12340] stateStrategy refusal', () => {
260260
expect(m).toContain('were removed');
261261
expect(m).toContain("Use 'memory'");
262262
expect(m).toContain('p'); // locates the offending plugin
263-
// The negative twin (#13179's strip): the prescription anchors on the
263+
// The negative twin (commit fd289be45's strip): the prescription anchors on the
264264
// ADR and the version — never on a tracker id the refused author
265265
// cannot resolve. Mirrors the spec-side door's own pin.
266266
expect(m).not.toMatch(/(?<![#&])#\d{3,5}(?![0-9A-Za-z])/);
@@ -385,7 +385,7 @@ describe('[#12428] startWatching refusal and the watch-handle removal', () => {
385385
expect(m).toContain('never watched');
386386
expect(m).toContain('scheduleReload');
387387
expect(m).toContain('p'); // locates the offending plugin
388-
// The negative twin (#13179's strip, extended to this door's sibling id):
388+
// The negative twin (commit fd289be45's strip, extended to this door's sibling id):
389389
// anchored on the ADR and the migration call, never on a tracker id.
390390
expect(m).not.toMatch(/(?<![#&])#\d{3,5}(?![0-9A-Za-z])/);
391391
});

‎packages/core/src/lite-kernel.ts‎

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -38,14 +38,14 @@ export class LiteKernel extends ObjectKernelBase {
3838
* A plugin object the DECLARED plugin contract refuses is refused here,
3939
* with `PLUGIN_CONTRACT_VIOLATION` — the same check, the same envelope,
4040
* that `ObjectKernel.use()` runs through `PluginLoader` (`plugin-contract.ts`
41-
* is the one statement both kernels call; #16721, maintainer ruling
41+
* is the one statement both kernels call; commit 51ae73123 landed maintainer ruling
4242
* 2026-09-08, option A under #9864's precedent that the kernels converge).
4343
*
4444
* This method used to write the object straight into the registry, so the
4545
* same plugin was accepted by this kernel and refused by `ObjectKernel` —
4646
* and `AGENTS.md` names THIS kernel for tests, so a plugin could be green
4747
* in vitest and refused at production boot. Measured before converging
48-
* (#16721 step 1): of 813 `LiteKernel.use()` calls reachable in this
48+
* (step 1, before commit 51ae73123): of 813 `LiteKernel.use()` calls reachable in this
4949
* repository's suites, 807 were accepted by the schema unchanged and the
5050
* six refusals came from three test-local fixture objects, none of them
5151
* product code.
@@ -69,7 +69,7 @@ export class LiteKernel extends ObjectKernelBase {
6969
use(plugin: Plugin): this {
7070
this.validateIdle();
7171

72-
// Same check, same envelope, as `ObjectKernel.use()` (#16721).
72+
// Same check, same envelope, as `ObjectKernel.use()` (commit 51ae73123).
7373
assertPluginContract(plugin);
7474

7575
registerPluginByName(this.plugins, plugin, this.logger);

‎packages/core/src/metadata-service-contract.ts‎

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -41,7 +41,7 @@
4141
* - `check:meta-type-normalized` (`scripts/check-meta-type-normalized.mjs`)
4242
* is the CI gate whose whole job is to refuse a DECISION made on the
4343
* un-normalized `:type` — its header carries the three authorization
44-
* bypasses (#3984, #5881, #6241) that made the direction a rule. Its scan
44+
* bypasses (#3984, #5881, the one commit 83a3b1f2e closed) that made the direction a rule. Its scan
4545
* surface is `packages/rest/src`; what this module converges with is its
4646
* DIRECTION: normalize once, at the entry, and let every decision — here,
4747
* every store key — read the normalized value;
@@ -65,7 +65,7 @@
6565
* Row 3: a `data` that is not a plain object cannot be a metadata document.
6666
* The pre-ruling `MetadataFacade` accepted such a write and filed it under the
6767
* literal key `undefined` — readable back through no member (silent loss, the
68-
* #6725 family) — and the interim fix coerced it into a `{ name, content }`
68+
* same family as the defect commit 1507ba356 fixed) — and the interim fix coerced it into a `{ name, content }`
6969
* box, which collides with `content` being a REAL authorable field on live
7070
* metadata types (`doc`, `knowledge_document`). The ruling forbids both:
7171
* refuse, do not coerce into storability. `null` and arrays are refused with

‎packages/core/src/plugin-contract-enforcement.test.ts‎

Lines changed: 8 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -2,14 +2,14 @@
22

33
/**
44
* `kernel.use()` enforces the DECLARED plugin contract (#16049) — on BOTH
5-
* published kernels (#16721).
5+
* published kernels (commit 51ae73123).
66
*
77
* WHICH KERNEL. Groups A–F drive `ObjectKernel.use()`, the path #16049 wired
88
* (`PluginLoader.validatePluginContract`). Group G drives `LiteKernel.use()`,
9-
* which #16721 converged onto the SAME check — `assertPluginContract` in
9+
* which commit 51ae73123 converged onto the SAME check — `assertPluginContract` in
1010
* `plugin-contract.ts`, the one statement both kernels call. G is not a copy
1111
* of A–F: it pins the cases whose answer DIFFERED between the kernels before
12-
* #16721, the parity of the envelope for one input, and the two orderings
12+
* commit 51ae73123, the parity of the envelope for one input, and the two orderings
1313
* `LiteKernel.use()` owes (state before contract, contract before registry).
1414
*
1515
* WHY THIS FILE EXISTS. `PluginSchema` (`@objectstack/spec`,
@@ -424,7 +424,7 @@ describe('E — `version` is the NINTH enforced key, and admitting it refused no
424424

425425
describe('G — the SAME contract on LiteKernel.use() (#16721)', () => {
426426
/**
427-
* Before #16721 every refusal above had an accepting twin on this kernel:
427+
* Before commit 51ae73123 every refusal above had an accepting twin on this kernel:
428428
* `LiteKernel.use()` wrote the object straight into its registry, so the
429429
* object group A refuses mounted routes here. `AGENTS.md` names this
430430
* kernel for tests, so "green in vitest, refused at boot" was the shape
@@ -469,7 +469,7 @@ describe('G — the SAME contract on LiteKernel.use() (#16721)', () => {
469469
['staticPath', { name: '@os-fixture/lite-ui-no-static-path', type: 'ui', slug: 'lite-ui-no-static-path' }],
470470
['slug', { name: '@os-fixture/lite-ui-no-slug', type: 'ui', staticPath: UI_STATIC_PATH }],
471471
] as const)('refuses a `ui` plugin with no `%s`, naming the key and the spec code (#16334 reaches this kernel now)', (key, overrides) => {
472-
// The two inputs #16721 was filed on: refused by `ObjectKernel` (group F),
472+
// The two inputs behind commit 51ae73123: refused by `ObjectKernel` (group F),
473473
// and until now stored verbatim here — the hono auto-discovery pin's
474474
// group F carried the accepting readings and was rewritten with this.
475475
const kernel = makeLiteKernel();
@@ -542,7 +542,7 @@ describe('G — the SAME contract on LiteKernel.use() (#16721)', () => {
542542
// was excluded from the schema check it was the ONE declared key this
543543
// kernel did not judge at all: `version: 'v1.0.0'` registered here and
544544
// was refused by `ObjectKernel` at boot — precisely the green-in-vitest,
545-
// refused-in-production split #16721 converged the other eight keys to
545+
// refused-in-production split commit 51ae73123 converged the other eight keys to
546546
// close. It now travels the ordinary envelope.
547547
const kernel = makeLiteKernel();
548548
const bad = fixture({ name: 'com.example.lite-bad-version', version: 'v1.0.0' });
@@ -567,7 +567,7 @@ describe('G — the SAME contract on LiteKernel.use() (#16721)', () => {
567567
// "An author gets ONE refusal, with the same code and message shape,
568568
// from either kernel." `ObjectKernel.use()` re-wraps a failed load as
569569
// `Failed to load plugin: <name> - <message>` for EVERY load failure —
570-
// its existing wrapper, untouched by #16721 — so the parity to pin is
570+
// its existing wrapper, untouched by commit 51ae73123 — so the parity to pin is
571571
// that the LiteKernel message is exactly what follows that prefix.
572572
const make = () => fixture({ name: '@os-fixture/parity', type: 'ui', staticPath: UI_STATIC_PATH, slug: 'Not A Slug' });
573573

@@ -596,7 +596,7 @@ describe('G — the SAME contract on LiteKernel.use() (#16721)', () => {
596596
});
597597

598598
it('ORDER — state is checked before the contract: after bootstrap the refusal is the idle one', async () => {
599-
// `validateIdle()` first, then the contract — the wiring #16721 step 1
599+
// `validateIdle()` first, then the contract — the wiring step 1 (before commit 51ae73123)
600600
// measured with. A kernel that can no longer register plugins says so,
601601
// and does not run the schema over an object it would not store anyway.
602602
const kernel = makeLiteKernel();

‎packages/core/src/plugin-contract.ts‎

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@ import type { Plugin } from './types.js';
77
* The DECLARED plugin contract, enforced at `use()` on BOTH kernels — one
88
* statement, shared by `LiteKernel.use()` and by
99
* `PluginLoader.validatePluginContract` on the `ObjectKernel.use()` path
10-
* (#16721, maintainer ruling 2026-09-08, option A).
10+
* (maintainer ruling 2026-09-08, option A, landed as commit 51ae73123).
1111
*
1212
* ## Why it is written down here rather than in each kernel
1313
*
@@ -113,7 +113,7 @@ import type { Plugin } from './types.js';
113113
* line, and the first violated key is the one to fix.
114114
*
115115
* The code is spelled the ADR-0112 way and is REGISTERED in
116-
* `ERROR_CODE_LEDGER` under `@objectstack/core` (#16649, under the #16404
116+
* `ERROR_CODE_LEDGER` under `@objectstack/core` (commit 613bfbd3d, under the #16404
117117
* door-or-no-door rule), exactly like `SERVICE_NOT_REGISTERED_CODE` one module
118118
* over. `door: 'none'` on this tree — it is raised while the kernel is still
119119
* assembling itself, before any HTTP boundary exists. If a transport ever
@@ -152,7 +152,7 @@ import type { Plugin } from './types.js';
152152
* version` message, not `PLUGIN_CONTRACT_VIOLATION`; that ordering is
153153
* unchanged and is pinned. `LiteKernel` has never run `validatePluginStructure`
154154
* and still does not — so on that kernel a malformed `version` is refused for
155-
* the first time here, by the schema, which is exactly the convergence #16721
155+
* the first time here, by the schema, which is exactly the convergence landed in commit 51ae73123 as
156156
* ruled for the other eight keys.
157157
*/
158158
const PLUGIN_CONTRACT_VIOLATION_CODE = 'PLUGIN_CONTRACT_VIOLATION';

‎packages/core/src/plugin-loader.retired-fields.pin.test.ts‎

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@
1717
// `@objectstack/core` "has no `typecheck` script (type-check DEBT ledger
1818
// entry)", making a `@ts-expect-error` here a phantom pin
1919
// `check:type-check-coverage` refuses. False on this tree in BOTH halves:
20-
// #14613 split a `tsconfig.test.json` out of the build config,
20+
// Commit 81208086a split a `tsconfig.test.json` out of the build config,
2121
// `package.json`'s `typecheck` NAMES it (via `check:test-typecheck
2222
// --project`), and this package holds no DEBT entry. A directive here WOULD be
2323
// evaluated — against `./plugin-loader.ts`, this package's own SOURCE, which

‎packages/core/src/plugin-loader.ts‎

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -418,7 +418,7 @@ export class PluginLoader {
418418
*
419419
* The check itself — `PluginSchema.safeParse` for validation only, the
420420
* nine keys it reaches and the `PLUGIN_CONTRACT_VIOLATION` envelope —
421-
* lives in `plugin-contract.ts`, because since #16721 it is ONE statement
421+
* lives in `plugin-contract.ts`, because since commit 51ae73123 it is ONE statement
422422
* run by BOTH kernels:
423423
* `LiteKernel.use()` calls it directly, and `ObjectKernel.use()` reaches
424424
* it here, through `loadPlugin`. That module's comment is the authority on

‎packages/core/src/plugin-type-closed-set.test.ts‎

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,7 @@
2222
// ⚠️ This used to read as though the split were forced — that
2323
// `@objectstack/core` "has no `typecheck` script (type-check DEBT ledger
2424
// entry)", making a `@ts-expect-error` here a phantom pin
25-
// `check:type-check-coverage` refuses. False on this tree: #14613 split a
25+
// `check:type-check-coverage` refuses. False on this tree: commit 81208086a split a
2626
// `tsconfig.test.json` out of the build config, `package.json`'s `typecheck`
2727
// NAMES it (via `check:test-typecheck --project`), and this package holds no
2828
// DEBT entry. A directive here WOULD be evaluated — against `./types.ts`,

0 commit comments

Comments
 (0)