Repository navigation
docs(platform-objects): re-anchor the dead tracker citations to the commits and ADR that decided them (stage 7 of #20595) - #21477
Conversation
…ommits and ADR that decided them Comment and docblock prose only: 42 sites on 42 lines in 28 files, covering 12 tracker numbers that answer 404, now cite the commit in this repository that decided them (11 numbers) or ADR-0104's 2026-09-05 addendum (1). 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>
…that reach dist Claude-Session: https://claude.ai/code/session_01DDZNkDVwPQnevTFcYE47H3 Co-authored-by: Claude <noreply@anthropic.com>
📓 Docs Drift Check10 anchor(s) derived from 1 changed package(s); no hand-written page names any of them. What this run could not see
Coarse fallback — 3 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 7e6c012508e6aedf1ece4415d172b1a1a19d8dfe && git checkout 7e6c012508e6aedf1ece4415d172b1a1a19d8dfe
# afterwards, rebuild it from the two parents, which stay fetchable
git fetch origin aa4632235ba571ef800b95e6bc18d00a30aa1d57 f45b9e60f69a6edb8a27657e424df92788734fc3 && git checkout -B drift-repro aa4632235ba571ef800b95e6bc18d00a30aa1d57 && git merge --no-ff f45b9e60f69a6edb8a27657e424df92788734fc3
node scripts/docs-audit/affected-docs.mjs --json aa4632235ba571ef800b95e6bc18d00a30aa1d57 |
Part of #20595
Clause-②: no
What changed
Stage 7 of the
domain:enginelane of the dead-citation sweep:packages/platform-objects/**, comment and docblock prose only, per the claim (5961679986). Stages 1 to 6 landed asa7d9768ec,d150c3039,4bf4e7e70,13a24ece2,db0cf2231and85986144c. #20595 stays open: the other half of this lane is the packages this stage does not touch (core40,metadata-core19,drivers/driver-turso14,drivers/driver-mongodb9,formula4,metadata-fs2 on the census after this stage, 88 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 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 42 sites on 42 lines in 28 files, covering 12 numbers:src/): the wholeallocated-but-absentpopulation of the gate's own census in this package at the base;scripts/i18n-extract.config.ts:17([finding]check:i18nverifies key presence, not that an untranslated leaf still matches the source string it was filled from — and the drift is sticky #11671) and:283(Retiresys_scim_provider— consumer sweep first, no data migration (leg 1a of #11632, ruled on #11693) #11757), two//and docblock lines in the package's i18n extraction config, andtsconfig.scripts.json:1([finding] The eight*/scriptsUNCHECKED_SOURCE_DEBTentries are graduation candidates once #10868 lands — and their notes still say "3 x TS2883" #11351), a//line in a JSON-with-comments file. These follow stage 1'stsup.config.ts, stage 5'stsconfig.typecheck.jsonand stage 6'stsup.config.tsprecedents;src(lifecyclettlaccepts no row filter, so atransientobject with terminal rows in-band cannot spare them — givettlanonlyWhenmirroringretention.onlyWhen#10165, driver-sql: the platform-objects schema does not sync onto MySQL — unbounded string fields become TEXT, which MySQL refuses to index #11374, Studio save of a package-declared permission set forks it into a silent, undiscoverable overlay #11513, [finding]check:i18nverifies key presence, not that an untranslated leaf still matches the source string it was filled from — and the drift is sticky #11671, Retiresys_scim_provider— consumer sweep first, no data migration (leg 1a of #11632, ruled on #11693) #11757), 1 it reads as dead elsewhere ([finding] TheApiKeyreference table documents better-auth's apiKey-plugin schema — a plugin this platform does not load and a shapesys_api_keydoes not have #8715, inpackages/spec), and 2 it never judges on this tree because they stand only in test files (Class-level keyed-text-bounds coverage needs a source-scanning gate — lifting the platform-objects pin is blocked by dependency direction (measured on #12059) #12147, sys_user: declare a set_user_manager row action posting the admin set-user-manager endpoint (moved from objectui#9361; objectstack#16678 Phase 2, ruled) #19249), which a single read settles.No comment-id citation stands in the package (see Census).
Anchors: 11 numbers by commit, 1 by ADR, 0 by words alone. 12 distinct shas.
#11374is split by subject:3954fb7df(the identity columns' bounds, the route-A ruleplatform-keyed-text-bounds.test.tsonce pinned, and the deliberately unboundedsys_verification.value, 15 sites) and4805b5619(sys_import_job.created_by, the route's last column, 1 site). 10 numbers reuse the anchor another lane or stage already used for them (for#11374, its 15-site half); 3 anchors were measured here:cb954f170(#11351),74fb2f7a8(#19249) and4805b5619(#11374's one-site half). 0 reused anchors were overridden.Only comments changed. Every file keeps its line count (42 lines out, 42 in, plus the changeset), so no line citation into any of them moves. 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 #3653, #11701, #12069 and #15989, each already on its line and each answering 200).A
patchchangeset: 26 of the 27 rewritten non-test lines are in the publisheddist(the.d.tskeeps JSDoc on exported members, and esbuild keeps the field comments inside the object literals), 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 base7e7e64b13(the before run below),allocated-but-absentper remainingdomain:enginepackage:coreplatform-objectsmetadata-coredrivers/driver-tursodrivers/driver-mongodbformulametadata-fsmetadata-protocol,objectql,metadata,drivers/driver-sql,drivers/driver-memory,drivers/driver-sqlite-wasm,plugins/plugin-pinyin-searchThe lane total goes 115 to 88.
core(40) is larger thanplatform-objects; the claim records the PM's stage-order call (two in-flight cards in this batch writepackages/core), so this stage tookplatform-objects, which the re-measure finds non-empty.Census:
platform-objects, 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/platform-objects/.allocated-but-absent7e7e64b13, run 21:26:33Z to 21:30:05Ze5d9a5d85, run 21:43:18Z to 21:46:37ZThe whole-repo drop is 27, and the two finding sets differ by exactly the 27 rows of this package, removed; none was added.
resolves(35,315),resolves-as-pull-request(2,381) andcross-repo-unjudged(1,229) did not move. The head's later commit is the changeset, outside the census surface.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 (158) and classifies each citation with the gate'sclassifyCitationagainst one board enumerated by the gate'senumerateBoard(193 pages, frontier #21468, 19,289 records, 21:31:03Z to 21:34:29Z), the same board for both readings. Every one of the 12 numbers in the population was then read on its own over the issues endpoint (21:35Z): all 12 answer 404; the lit controls#5286and#12624answer 200, and so do the four numbers that stay on changed lines (#3653, #11701, #12069, #15989).tsconfig.scripts.json7e7e64b13e5d9a5d85The citation count drops by exactly the 42 rewritten sites. The live counts did not move (src comment: 329 resolve, 10 as pull requests, 4 cross-repo; test comment: 273, 18 and 10). A third, raw reading (every
#followed by 2 to 6 digits, whatever surrounds it) counts 1,418 before and 1,376 after: also a drop of 42. The onesrc stringrow is not a citation: it is the hex colour'#475569'atsrc/apps/setup.app.ts:45, which the grammar's six-digit ceiling admits and the classifier reads as never issued; the census blanks strings and never sees it.Comment ids. No comment-id citation stands in the package: every ten-digit run under
packages/platform-objects(itsCHANGELOG.mdaside) is a translation source hash or a phone-number example inside a string, and anissuecomment/discussion_rgrep finds no line (exit 1). The same ten-digit grep overpackages/metadata-protocolfinds 15 lines (control).Per-number table
censuscounts census sites,outsidethe three 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 base7e7e64b13(git merge-base --is-ancestor, exit 0 for all 12; the clone was unshallowed first, see Acceptance notes). The+lines carry exactly these 12 nine-hex spans and no other. Each commit names the number it replaces: 6 in the message and the diff (3954fb7df,4805b5619,d6e80b28b,2c86fe3ea,801296050,74fb2f7a8), 6 in the diff alone (09b4f4e4eon 16 added lines,4d25d22d414,cb954f1709,945e91a136,5529a374e3,e170b0ae51); ADR-0104's addendum names #15041 in its Provenance paragraph.git blameat the base puts 29 of the 42 sites on their anchor; the other 13 were written by a commit that cites the number as an earlier decision (for exampledccbcec2eciting #10165's null predicate,428f9b24aciting the #11513 posture as precedent,945e91a13moving #11374's rule out of a test file), 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).#8676d6e80b28bcf684c98e)sys_account.passwordandprevious_password_hashesinternal#87152c86fe3eaa51920f5f)ApiKeySchema:sys_api_keyhas one declaration, the platform object#10165801296050lifecycle.ttl.onlyWhenwith the canonical null predicate, and the two refines refusing it beside rotation and archive; its message records the maintainer's 2026-08-20 ruling (option A)#11351cb954f170scripts/i18n-extract directories in a tsc program; it wrote thistsconfig.scripts.json#113743954fb7df(15 sites)4dfff176b, for the same route-A sentence)maxLengthbounds on the unbounded keyed identity columns (route A); its message records the 2026-08-24 ruling and thatsys_verification.valuestays deliberately unbounded; it created the package pin that carried route A's rule#113744805b5619(1 site)sys_import_job.created_by(「#11374 route A, last column」)#11513e170b0ae5a186aea99)#1167109b4f4e4e5914040746; the cli lane)#117574d25d22d44d04b6be3)sys_scim_providerplatform object#12147945e91a13*.object.ts, superseding the per-package pins#148175529a374e4edb61449)slots.*as inline locale maps#15041sys_fileid; item 2 of its Sequencing is #15989, the card this sentence also names#1924974fb2f7a8sys_userset_user_managerrow action (「Part of #19249」); it wrote this test fileNo ADR or ruling record decides any of the other 11 numbers:
git grepoverdocs/adrandscripts/adr-anchorsfinds none of them except #11513, which ADR-0126 names only as precedent (「the landed #11513 posture」, the same dead number) rather than recording its ruling;e170b0ae5's message records that ruling verbatim, so the commit is the anchor.Wordings to check
Most rewrites swap a tag in place (
[#N]to[commit SHA],(#N)to(commit SHA),#N's Xtocommit SHA's X,in #N/before #Ntoin commit SHA/before commit SHA). These say more than the tag:check:i18nverifies key presence, not that an untranslated leaf still matches the source string it was filled from — and the drift is sticky #11671 is its counterexample」 became 「… and the defect commit 09b4f4e fixed is its counterexample」 (source-hash.ts:87); 「a different defect from driver-sql: the platform-objects schema does not sync onto MySQL — unbounded string fields become TEXT, which MySQL refuses to index #11374's」 became 「a different defect from the one commit 3954fb7 fixed」 (platform-keyed-text-bounds.test.ts:82). Stage 6's form.check:i18nverifies key presence, not that an untranslated leaf still matches the source string it was filled from — and the drift is sticky #11671 measured that the hole it closes occurs here too」 became 「… until commit 09b4f4e acted on the measurement that the hole it closes occurs here too」 (source-hash.ts:214). The measurement itself is the module note's own reading on fix(audit): declare sys_activity.type as an open, author-extensible vocabulary #11659, which stays where it is; the commit is what brought the generated sections into the module.sys-import-job.object.ts:95), the plugin-audit and plugin-security lanes' spelling for the same tag.sys-verification.object.ts:107).3954fb7df's message is wherevaluewas left deliberately unbounded; #11627 population re-measured after the A half: three additional members of the >768/unboundable keyed-text class (resource_id 1024, sys_verification [value], sys_account [issuer+account_id]) #11701 is live and stays.sys-metadata-activation.object.ts:27,:40,sys-metadata-activation.object.test.ts:63): 「The Studio save of a package-declared permission set forks it into a silent, undiscoverable overlay #11513 deactivation carve-out」 became 「The deactivation carve-out of commit e170b0a」, and 「the landed Studio save of a package-declared permission set forks it into a silent, undiscoverable overlay #11513 posture」 became 「the landed posture of commit e170b0a」 (twice), stage 6's 「landed pin of commit」 form.driver-sqlputs file/image/avatar/video/audio inJSON_COLUMN_TYPES,packages/cligenerate.ts gives themVARCHAR(2048)— and neither side is obviously the one that should move #15041: 「(driver-sql: store the file family (file/image/avatar/video/audio) as the baresys_fileid in a string column — dropFILE_REFERENCE_TYPESfromJSON_COLUMN_TYPES, per-deployment switch on theadr-0104-file-referencesflag (ruling on #15041, step 2) #15989, the ruling on [finding] FILE_REFERENCE_TYPES disagree about their column:driver-sqlputs file/image/avatar/video/audio inJSON_COLUMN_TYPES,packages/cligenerate.ts gives themVARCHAR(2048)— and neither side is obviously the one that should move #15041 step 2)」 became 「(driver-sql: store the file family (file/image/avatar/video/audio) as the baresys_fileid in a string column — dropFILE_REFERENCE_TYPESfromJSON_COLUMN_TYPES, per-deployment switch on theadr-0104-file-referencesflag (ruling on #15041, step 2) #15989, step 2 of ADR-0104's 2026-09-05 addendum)」 (migration-flag.ts:235), stage 4's wording for the same step.set_user_managerrow action …」 became 「Commit 74fb2f7 — theset_user_managerrow action …」 (sys-user-set-manager-action.test.ts:4), capitalised because it opens the block.sys-scim-connection-credential.object.ts:18and:19read 「(which retires under Retiresys_scim_provider— consumer sweep first, no data migration (leg 1a of #11632, ruled on #11693) #11757)」;366f89576wrote them on 2026-08-27 and4d25d22d4retired the object on 2026-08-28. Only:19carries the number, so only it changed: 「(which retires under commit 4d25d22)」. The commit did retire it, so the sentence credits it with nothing it did not do; the present tense on:18is left, because that line carries no number.sys-api-key-single-declaration.test.ts:7andsys-session-lifecycle.test.ts:58are decorated section rules. The tag swap makes them 11 and 10 characters longer; the trailing 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). No line without a number was changed.Sites left
describeandittitles, assertion arguments):#87152 (sys-api-key-single-declaration.test.ts:23,:51),#192492 (sys-user-set-manager-action.test.ts:76,:141),#101651 (sys-session-lifecycle.test.ts:60). Every one of the 3 is in this stage's table. Strings are outside this stage's surface. Non-test strings cite none (the hex colour above is not a citation).*.generated.tsfiles carry no citation at all at the base, andobject-lifecycle-panel-echo-decisions.test.tscarries 22, none dead, so nothing is carried from them.src: the release-ownedCHANGELOG.mdnames dead numbers on 21 sites (16 numbers); left.package.json,tsconfig.json,tsconfig.test.json,test-typecheck-debt.jsonandLICENSEcite no dead number.Mechanical guard: no code token moves
The guard (stages 2 to 6's) compares base
7e7e64b13against the tree ate5d9a5d85over all 28 touched files, with TypeScript 6.0.3;tsconfig.scripts.jsonis parsed withts.parseJsonText: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:
sys-device-code.object.ts): 0 files changed (exit 0).HAND_AUTHORED_SECTIONStoHAND_AUTHORED_SECTIONSX,source-hash.ts): DIFFER on both readings (exit 1).'Provider ID'to'Provider IDX',sys-account.object.ts): DIFFER on both readings (exit 1).maxLength: 64to65,sys-api-key.object.ts): DIFFER on both readings (exit 1)."rootDir": "."to"./",tsconfig.scripts.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 (e98db7d7591b,67b0e306ca60,e5196ab7b57c,e889bb45f2ef,288105dc3e6b), 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 243s), ate5d9a5d85: the workspace was built first (turbo run build --filter='./packages/*' --filter='./packages/*/*' --concurrency=2, 71 of 71 tasks, 14 cached), then the package's ownbuild(tsup pluscheck-dts-emitted) ran three times:distfiles hashed. Of the 27 rewritten non-test lines, 26 appear verbatim indist; the one that does not isidentity/index.ts:48, a comment between two export statements.index.js/.mjs;apps/index.d.ts/.d.mts/.js/.mjs;audit/index.js/.mjs;identity/index.d.ts/.d.mts/.js/.mjs;metadata-translations/index.d.ts/.d.mts;plugin.js/.mjs;system/index.d.ts/.d.mts), andscripts/ablation-dist-preflight.mjsfinds the base marker 「and [finding]check:i18nverifies key presence, not that an untranslated leaf still matches the source string it was filled from — and the drift is sticky #11671 is its」 in 2 built files (apps/index.d.ts,apps/index.d.mts; exit 0).HEADblob,git diff HEADempty, porcelain empty): all 66 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-platform-objects-provenance-anchors.mddeclares apatchfor@objectstack/platform-objects, comment text only, with the claim'sClause-②: noline. The changeset commit touches no file underpackages/platform-objects.Gates (head
f45b9e60f)node scripts/pm/dispatch-gates.mjs --repo objectstack-ai/objectstack --commandsatf45b9e60f(29 paths against merge base7e7e64b13, 100 changed lines) derived 63 commands. All 63 ran, each exit code captured before any pipe: 63 exit 0.--ranreports 「63 derived, 63 run, 0 NOT-MEASURED, 0 UNRUN」 (a derived zero) and exits 0. The PM's lead derivation (49 commands, tree713b0fa7) is a subset: the extra 14 come from the test andtsconfigpaths (6) and the changeset (8).node scripts/check-issue-citations.mjsexits 0 (「every citation this change adds resolves (or is a declared cross-repo reference)」: 2 judged across 18 files, both resolve);pnpm check:issue-citationsexits 0 (self-test, 173 cases, 9 batteries);pnpm check:doc-authoringexits 0 (the sibling-package prose-id baseline holds, no growth);pnpm check:i18nexits 0 (all bundles in sync);pnpm check:nul-bytesexits 0 (9,807 files, no raw control bytes), and a control-byte grep over the 29 changed files finds none (exit 1).f45b9e60f(VERDICT command-exit 0):pnpm --filter @objectstack/platform-objects test: 59 test files pass (59), 949 tests pass (949);pnpm --filter @objectstack/platform-objects typecheck(tsc --noEmit,tsc --noEmit -p tsconfig.scripts.json, thencheck:test-typecheck: 「1 file(s) / 3 error(s) / 2 pinned signature(s) held」) exits 0.tsc --listFilesOnlyputs all 59 tracked test files intsconfig.test.json's program, the 18 changed non-testsrcfiles intsconfig.json's, andscripts/i18n-extract.config.tsintsconfig.scripts.json's..tsfiles plusdist/index.jsas the control: 28 results, 0 errors and 1 warning, the control's ignore notice; none of the 27 is reported ignored.tsconfig.scripts.jsonalone answers 「File ignored because no matching configuration was supplied」 (not an eslint target).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
7e7e64b13and not merged withmain:mainhas since moved two commits (49524f690,packages/rest;aa4632235,packages/spec), neither touchingpackages/platform-objects,check-issue-citations.mjsordispatch-gates.mjs; the queue rebuilds the branch ontomain. The net diff againstmainis the 28 rewritten files (+42/−42) and the changeset (+16).blame,log -Sor ancestry reading, so every exit 0 above is on full history.check:i18nverifies key presence, not that an untranslated leaf still matches the source string it was filled from — and the drift is sticky #11671 (6 lines in 4 files at6210f887) holds on this base: 5 census lines and the one test comment, withsource-hash.ts's third site now at:570(:568in the pointer). A seventh site,scripts/i18n-extract.config.ts:17, is outside the census glob and was in no earlier reading; it is in this stage's population.*/scriptsUNCHECKED_SOURCE_DEBTentries are graduation candidates once #10868 lands — and their notes still say "3 x TS2883" #11351 on the first line of eight other packages'tsconfig.scripts.json(plugin-approvals,plugin-audit,plugin-security,plugin-sharing,plugin-webhooks,service-messaging,service-realtime,service-storage), which the census does not read;cb954f170is their anchor too (service-storage's line came later, fromebb555091). [finding] TheApiKeyreference table documents better-auth's apiKey-plugin schema — a plugin this platform does not load and a shapesys_api_keydoes not have #8715 inpackages/spec/src/identity/identity.zod.ts:230(the spec lane's population). [finding] TheApiKeyreference table documents better-auth's apiKey-plugin schema — a plugin this platform does not load and a shapesys_api_keydoes not have #8715 also stands on two published release pages and Retiresys_scim_provider— consumer sweep first, no data migration (leg 1a of #11632, ruled on #11693) #11757 on one; release pages are never edited.Generated by Claude Code