fix(spec): the protocol 16 → 17 upgrade rationale states each cited decision in words instead of a tracker number (stage 8) - #21674
Conversation
…in words instead of a tracker number (stage 8) Text only: 105 string literals of step17.rationale in packages/spec/src/migrations/registry.ts, plus the migrations.test.ts pin that named the area-walk fix by number, moved onto its rewritten words. Claude-Session: https://claude.ai/code/session_01T9u38rswFp5Rw8DswRUReJ Co-authored-by: Claude <noreply@anthropic.com>
…step-17 rationale Produced by check:generated --fix (gen:upgrade-guide), not hand-edited. Claude-Session: https://claude.ai/code/session_01T9u38rswFp5Rw8DswRUReJ Co-authored-by: Claude <noreply@anthropic.com>
…ewrite Claude-Session: https://claude.ai/code/session_01T9u38rswFp5Rw8DswRUReJ Co-authored-by: Claude <noreply@anthropic.com>
📓 Docs Drift CheckThis PR changes 1 package(s): 1 hand-written doc(s) NAME something this change touched and may need an implementation-accuracy re-verification:
What this run could not see
Coarse fallback — 138 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 c786bc199899bee1971a1ba46e5d4e26f58ffcd2 && git checkout c786bc199899bee1971a1ba46e5d4e26f58ffcd2
# afterwards, rebuild it from the two parents, which stay fetchable
git fetch origin 55e6f14f8d87004c50b0f35eaafba36ac23cf32b 0d9cc19305bb0ee9504872d84d74a74aafb558e6 && git checkout -B drift-repro 55e6f14f8d87004c50b0f35eaafba36ac23cf32b && git merge --no-ff 0d9cc19305bb0ee9504872d84d74a74aafb558e6
node scripts/docs-audit/affected-docs.mjs --json 55e6f14f8d87004c50b0f35eaafba36ac23cf32b
|
Part of #20749
Clause-②: no
Stage 8 of the
domain:speclane's share of the runtime-string burn-down (ruling5902360492, form D): the author-visible tracker ids in step 17's rationale inpackages/spec/src/migrations/registry.ts, per the pointer5968465093. Every cited decision is now stated in words, or the citation is dropped where its sentence already said what was decided. Text only. Step 18 and the test strings are later stages, so this PR closes no card.What changed
step17.rationale: 1 message, 116 tracker ids, 91 distinct records (four of them in sibling repositories: one cloud card, two objectui cards and one objectui PR). The rationale is one[...].join('')array of string literals, and 105 of its literals carried the 116 ids. Exactly those 105 literals changed. The array keeps its element count, and no other literal moved.migrations.test.tspinnedtoMatch(/#4722/)in a test titled after that number. It now pins the rewritten words. See "Readers" below.docs/protocol-upgrade-guide.md, throughcheck:generated --fix(onlygen:upgrade-guidewas stale). Its 57 changed lines are exactly the 57 rewritten paragraphs. Nothing else prints this rationale:spec-changes.jsondoes not carry step rationales and stayed up to date.@objectstack/specpatch changeset,Clause-②: no. The rationale ships indistandos migrate metaprints it per hop. The new text is indist/migrations/index.jsandindex.mjs, and 0 dist files carry the five replaced fragments I probed.Census at the base (A1)
Base
eea82af677, the worktree before any edit, which is the claim's stamp. I reused stage 7's instrument, byte-identical (census.cjs, md56e42a45a926d375013c32d62f16a296e), and held it to the same reference stage 7 used. That reference ischeck-doc-authoring.mjs --census, run from a scratch copy whosePACKAGES_PROSE_ROOT/PACKAGES_PROSE_EXCLUDEDpoint atpackages/spec/srcand at nothing (md58edc9a4064f55d2766c1eb0d3e8d889f, the same two-line diff stage 7 used). Result: 201 = 201 ids, 0 differences per (line, id).migrations/registry.tsconst step17, lines 100–4976)STEP18_RATIONALE, lines 5025–20862)151a8ce4ed; main has since added two step-18 messages (+3 ids).:111(full, one id) and:470/:475(the area-walk fix) count in the step-17 message. Step 18's 85 stay lit after the rewrite, so the after-zero is not blindness.:1153, the// #4001 …block at:1802–:1833, and more. Those 18 read 0. 134 − 18 = 116. The header docblock ids (:19,:32,:40,:62) read 0 as well.Delivered (A2): each cited record, the decision as read, the words now in the text
I read every cited card, all its comments included, through REST GETs: 87 objectstack records and three objectui records (3829, 3818 and PR 3289). The record column names where each decision was read. A card with no comments was read from its body and its closing PR (from the timeline). Card numbers are written bare here, so this body creates no cross-references.
full, since no mainstream platform lets a bulk sharing rule grant delete or transfer (analysis 5105498900)agent.tools[]removed (PR body)agentToolsToSkillsdocblock in this repoconfigSchemawith what its executor reads;wait,connector_actionandmapwere the findings (close-out 5138487536)priorityvoid (release notes 17.0); the close-out sweep retired fourteen inert keys (changeset 12a19a8); the earlier removal of the plugin-runtime discovery and sandbox config left the five operation contracts for a later design call (spec CHANGELOG)AnalyticsQuery, validated, malformed answers 400 (5105665093)maxRetries, andstrategy: 'retry'states its count (closing PR 4266)api.requireAuth; anonymous data access denied unconditionally; an auth-less stack fails at boot (body)QueryASTstops declaring members no executor runs;havingenforced,cursor/distinctremoved with their SDK producers (closing PRs 4294, 4307)QueryASTliveness sweep"; "That sweep's close-out"; "theQueryASTsweep"timeoutMs/onTimeout:waitnever had a timeout (closing PR 4198)readReplicas(5150771330)packages/specparsedatasource.configand each replica entry (5150601668)datasource-config-driver-key-aliasesconversion; the factory's??fallbacks deleted (ACCEPT 5157922838)scriptconverges to a pure function call; five keys tombstoned (5151704360)parse()their config (title)findStream, no tombstone (ACCEPT 5158609619)system, the new value namedsystem-data(5157022965)importleaves thesystem-datadefault, opt-in per object (maintainer ruling 5163044848)filterAppForUserwalks every area's navigation; area-level keys stay retired (ACCEPT 5161835765)data.field.changed(5159280649)object+matched(ruling 5158990896, correction 5159177633)data.records.*events did"enable.trash/enable.mru(ruling 5156966571), the last slice of the 11.0 dead-property removals (5051634768)openApi31(ACCEPT 5162291403)activationEventskeys (ACCEPT 5164681566)activationEvents, converge on the kernel's structured shape (ruling 5158525266)plugin-runtime.zodshapes (ruling 5165851511)plugin-runtime.zodshape"crypto.hash(5165929011)widgets[].responsive, mirroringview.responsive(ruling 5169512655)page.components[].responsive(ruling 5380752244)compareTotakes the executor's own shape (ACCEPT 5175336061)apis:loudly at publish, vocabulary kept (ruling 5173142024)customVars(ACCEPT 5181527150)./uinotification shapes are deleted (dual-source C3, ACCEPT 5157937351)session.roles(ACCEPT 5197117072)provenance(closing PR 3749)provenancewas for schedule-triggered runs"list(prefix)(ruling 5194631234)typeandpartial(ruling 5199336983); 4943 closed as its duplicatejsexpression dialect (closing PR 3291)error, with a producer (PR body)labelFielddeclared, dead keys retired (ruling 5202137085)sectionsdeclared in the object form pages author (ruling 5199158856)record:detailssections rule"page:tabs.type→tabStyle(ACCEPT 5229693342)RecordDetailsProps.layout(ruling 5230006799)array_agg/string_aggretire,count_distinctenforced (ruling 5219849918)distinct(ruling 5229991324)count_distinctimplemented in the SQL family (dev report 5228634411)isAsync(ACCEPT 5229281891)supportsPauseat runtime; measureisAsync(claim 5226271238)loadingblock (ruling 5173235317)global_nav(ruling 5229990375)pdfremoved (ACCEPT 5276376886)Each rewrite was applied by a script whose 105 anchors each had to hit exactly once on its own base line. Each base literal had to carry an id, and each new literal had to carry none. The script read every literal back from disk afterwards: 105 new strings present, 105 anchors gone. A first application put an unescaped apostrophe into one literal. The proof below caught it (8 parse diagnostics), and the edit list was corrected and re-applied from the base copy.
Readers (A3)
#4722pin (migrations.test.ts, formerlynames #4722 and the two trees an item gate is now enforced in). It is nownames the server-side fix in words and the two trees an item gate is now enforced in, and it assertswas CLOSED by a server-side fix inside this same 17\.0\.0 windowplus`filterAppForUser` now runs the SAME `filterNav` over everyin place of/#4722/. TheBOTH treesandareas[].navigationassertions are unchanged. The sibling pins (not /does not walk/i,/was CLOSED by/,/stay retired/,/no gate of its own/,client-side ONLY,FAIL-OPEN access gates) hold verbatim. The rewrite kept every word they read, so no other test moved.scripts/ablation-replace.mjsput the number back (anchorwas CLOSED by a server-side fix inside this same, hit 1 → 0, blob355bf645cc94→2612fa163a05). The file then read 1 failed | 168 passed, the failure being exactly the moved pin, as predicted. The restore was proven: blob355bf645cc94= HEAD, andgit diff HEADempty.git grep -F. The search excluded the edited file, the regenerated guide, theCHANGELOG.mdfiles andcontent/docs/releases/(history the release owns). The hits are 48 lines in 32 files, all comments, docblocks, ledger notes or other entries' own prose that share a phrase. None is an assertion, a gate or a quotation of this rationale.#4722, so test strings go 1804 / 1920 → 1803 / 1919. The other test titles and comments that mention 4722, 4651 or 5337 are untouched (class (e), and comments belong to the sibling form-C lane).Text only (A5)
I reused stage 7's AST-skeleton plus string-text tool, byte-identical (
skeleton.cjs, md5a43a72c63f55c883da7a54b6f600ca08). Leg 1 is an AST skeleton with every string masked: a+chain's adjacent strings read as one, while array elements stay separate. Leg 2 is the text of every string group. A changed group must carry an id before and none after; every other group must be byte-identical.registry.ts, base copy vs committed head: SAME, 22125 skeleton tokens, 3487 string groups, 105 changed (each id-bearing before, id-free after), diagnostics 0/0, exit 0. Every step id,toMajor,conversionIdsentry, semantic entry, retired key and retired def, and their order, is therefore unchanged. The array's element count is part of the skeleton.Controls, on scratch copies of the head file. Each mutation was counted on disk: anchor hits 1, replacement present 1, anchor left 0, differs from head.
step17renamed.reverse()on step 18'sconversionIds+literal re-split into two operandsNo repo file was mutated for the controls.
Census after (head): step 17 0 / 0. Step 18 stays at 46 / 85, untouched, and the gate's per-literal leg agrees (78 literals, 85 ids, all
STEP18_RATIONALE; 0 per-(line, id) differences).Gates
All builds and tests ran through
scripts/pm/os-verify-lock.sh(slotdev-20749-s8). Every exit code was written to a file before it was read.pnpm --filter @objectstack/spec build: exit 0, "38/38 declared declaration file(s) present". The closure filter is empty, since spec has no workspace dependencies.pnpm --filter @objectstack/spec check:generated: exit 1 before regeneration ("1 of 15 artifact(s) stale":check:upgrade-guide). Then--fix: exit 0 ("re-checking the 1 artifact(s) just written … ✓ check:upgrade-guide"). Re-run in the gate union: exit 0.pnpm --filter @objectstack/spec exec vitest run --maxWorkers=2 --reporter=verbose src/migrations/migrations.test.ts: 169 / 169.pnpm --filter @objectstack/spec test: "Test Files 609 passed (609) / Tests 18059 passed | 1 todo (18060)".pnpm --filter @objectstack/spec run typecheck: exit 0, "52 file(s) / 246 error(s) / 135 pinned signature(s) held".pnpm turbo run build --concurrency=2over every package: 71 / 71. This feeds the dist-reading gates.node scripts/pm/dispatch-gates.mjs --commands --repo objectstack-ai/objectstack(no paths) derived 90 commands for 4 paths vs merge baseeea82af67. 90 of 90 exit 0 at0d9cc19305.--ran: "90 derived famil(ies) accounted for — 90 run, 0 NOT-MEASURED (a DERIVED zero — all 90 recorded an exit code and none of them is 3)". The union includescheck:doc-authoring,check:nul-bytes,check:upgrade-guide,check:spec-changes,check:migration-registry,check:issue-citationsandcheck:api-surface.node --stack-size=4000 node_modules/eslint/bin/eslint.js --no-inline-config --format jsonover the 2 changed TS files read 2 files, 0 errors, 0 warnings. The population comes from ESLint's own config:calculateConfigForFilereturns a config for each, andisPathIgnoredis false. Invariance:parserOptions.project/projectServiceare null for both, so no type-aware linting runs and a string-text edit cannot move an untouched file's verdict. Repo-widepnpm lintis CI's.Acceptance notes
agent.tools. This repo records the same fact in theagentToolsToSkillsdocblock (conversions/registry.ts). So the number is dropped and the sentence keeps that claim, now attributed to "the cloud runtime".priorityvoid (17.0 release notes); the close-out sweep that retired fourteen inert authoring keys (changeset12a19a8); and the earlier removal of the plugin-runtime module's discovery and sandbox config, which left the five operation contracts for a later design call (spec CHANGELOG). The text names each act.max-lenrule, and the joined text, which is what authors read, is unaffected.origin/mainmoved five commits after the base (55e6f14f8dis the tip): pm tooling and skills docs. None touches this PR's four paths orpackages/spec, so main was not merged; the merge queue rebuilds onto currentmain. Card 21464's stage 5 (claim5975220557) has no open PR yet, so nothing landed to merge. Of the nine open PRs, one touchesmigrations/registry.ts: PR 21668 (card 20281 stage 3). Its hunks sit at lines 8793 and 8817, inside step 18, and are disjoint from lines 111–1077 here. The changesets PR (changeset-release/main) only lists earlier stages' changesets..claude/**,skills/**, ADR, NORTH-STAR or AGENTS.md path.Line budget
345 changed lines (+181 / −164) over 4 files vs merge base
eea82af677(git diff --shortstat):registry.ts+105 / −105, the generated guide +57 / −57,migrations.test.ts+3 / −2, and the changeset +16.Generated by Claude Code