Skip to content

Commit 0bddffd

Browse files
docs(spec): nine migration-step rationale passages and two registry comments drop their deleted tracker numbers (stage 11) (#21578)
Part of #20234 Clause-②: no Stage 11 of the dead-citation sweep: the hand-written parts of `packages/spec/src/migrations/registry.ts`, under ruling C+D (record `5749154545` on #19123). At base, those parts carried 13 sites citing deleted tracker numbers: 2 in source comments and 11 in step rationale text that authors read. A step `rationale` is author-shown: `os migrate meta` prints it per hop, and step 17's is projected into `docs/protocol-upgrade-guide.md`. Text only. No step, fragment id, fragment order, generated entry, conversion or code token moves. - **Form C, the 2 comments.** Each dead number now cites the commit that decided it (verified against the commit's own text), and the sentence says what that commit did. - **Form D, the 11 rationale sites.** They sit in 9 rationale units: step 17's `mongodb` paragraph and 8 step-18 fragments (a fragment is "one retirement's sentences"). Each of those 9 units now carries no number at all. The 11 dead numbers go, and so do the 11 live numbers in the same units, because form D removes every number from author-visible text. Each sentence states the cited decision in words, read from its decision record, not its title. - **Regenerated, never hand-edited:** `docs/protocol-upgrade-guide.md` line 68. `check:generated --fix` proved it the only stale artifact of 15. `gen:migration-registry` has nothing to do, because no generated region mirrors a rationale. - One `@objectstack/spec` **patch** changeset. ## What changes Line numbers are at base `e909aa0a23`. "Dead" means `GET issues/N` answers 404, with no redirect followed. | line | number(s) | decision, as read, and its record | now reads | |---|---|---|---| | 344 | #6345 (dead), #4410 (live) | `mongo` → `mongodb` became the canonical driver id under one shared driver vocabulary (commit e2798fa). #4410: `datasource.config` is parsed against the declared driver's contract, and `mongo` and `mongodb` both map to the mongo contract (commit cdf4d9a) | "renamed to `mongodb`. The two spellings have both been accepted since `datasource.config` was first parsed against its driver's own contract" | | 5180 | #14676 (dead) | retire `connector.errorMapping`, ADR-0049 (commit 13c48c2) | the number dropped; the fragment already states the decision | | 5601–5608 | #12868 (dead); objectui#6263 ×2, #7246, PR #7388 (live) | narrow per-option `default` out of the form-view vocabulary only, disposition 甲 (commit c459da6, whose diff added this fragment). objectui#6263: the console's form controls never read the key, and the ruling closed that card. #7246 / #7388: maintainer ruling of 2026-08-10, "enforce" on the object-field face (`applyFieldDefaults`) | "maintainer ruling 2026-08-28 on the console form renderer's analysis"; "enforced there by a maintainer ruling of 2026-08-10"; "measured against the console's form controls, none of which reads the key" | | 5703–5704 | #10329 (dead), #4509 (live) | retire the `lookup` steering params (commit 15d58db). #4509: 17.0.0 retired the keys the lint could never warn about, the mapping trio among them (commit 5966c2a) | "the sub-walk half of the 17.0.0 mapping cleanup that retired `extractQuery` / `errorPolicy` / `batchSize`" | | 5718, 5721 | #8336 (live), #8495 (dead) | refuse `${…}` in memory `persistence.path` / `persistence.key` at publish (commit 4bfe1a5). #8336: the 2026-08-13 ruling refusing placeholders in datasource connection config at publish (the protocol-17 entry `datasource-config-placeholder-refused`) | "extends the publish-time refusal of unresolved placeholders, which protocol 17 applied to datasource connection config, to the memory driver's …"; "(#8495)" dropped | | 5732–5733 | #13135 (dead), #12057 (live) | retire the paper customization protocol with its full coupling set; the maintainer adopted retirement 2026-08-29 (commit 9e0ba21, whose diff carries the number) | "(ADR-0049 enforce-or-remove, maintainer ruling 2026-08-29)" | | 5963, 5966, 5973, 5975 | #10724, #10627, #10726 (dead); #11169 (live) | retire nine dead `contributes` members; a controlled three-repo census found one non-test read (commit be21955). #10726: `routes` later retired too, ruled Option B (commit bc56e18, whose diff carries the number). #11169: retire `kinds[].globs`, maintainer ruling 2026-08-24 (commit be21955) | "A census of all three repos, with controls, measured …"; "`routes` was left to a ruling of its own, which retired it as well (the `plugin-manifest-contributes-routes-retired` entry)" | | 6020 | #10485 (dead) | retire stack `themes` and `ThemeSchema`, ruled B (commit 35ad101) | the number dropped | | 6049, 6052, 6058 | #10926 (dead); #9249 ×2 (live) | retire the `submitLabel` copy key, Option A (commit d173125). #9249: `element:form` retired whole (the `element-form-retired` fragment, which renders earlier) | "retired whole above"; "nothing read it once `element:form` was retired" | | 6301 (comment) | #8495 (dead) | as above (commit 4bfe1a5) | "(commit 4bfe1a5, PR #8666: `${…}` refused at publish in `persistence.path` / `persistence.key`)" | | 24935 (comment) | #6239 (dead) | the 2026-08-08 sweep retired the viewId-addressed `ViewProtocol` as whole defs (commit f549a0d, whose subject names the number) | "(commit f549a0d, D3 `view-management-protocol-retired`)" | Where a commit message does not name its number, the anchor was confirmed from the files that commit added: c459da6, 9e0ba21 and bc56e18 each carry their number in their own diff. Both sha anchors added to comments are unambiguous: `rev-parse --disambiguate` count 1, and `GET commits/SHA` returns the full sha (a 4-character control returns 422). `merge-base --is-ancestor` answers 0 for all 11 anchors. The checkout is shallow, with a boundary of 2026-06-28. Every anchor is later than that, and exit 0 proves ancestry on its own. ## What stays, and why (counts left on #20234) - **Live numbers in comments: 46 sites (plus 1 cross-repo).** The rule applies to dead citations in comments, so these stay. - **Live numbers in author-visible rationale text outside the 9 units: 192 sites** (175 in-repo, 17 cross-repo; 142 distinct in-repo numbers). Step 17 holds 116 of them and step 18 holds 76. Form D would remove them too, but they are not dead citations, and they lie outside this stage's claimed surface. Note that #20749 (the runtime-string burn-down) counts migration-registry text as its share, yet both of its stage claims (`5965785560`, `5966674486`) exclude `migrations/registry.ts` as "#20234's stage 11". So no stage currently covers them. `migrations.test.ts` pins one of them, the live #4722 in step 17, so whichever stage takes them moves that pin. This is reported as the open question. - The 6 dead numbers from census pointer `5923089344` are outside this stage, as dispatched. ## Verification **Deadness.** A TypeScript 6.0.3 walker runs the citation gate's own `extractCitations` over two projections of the file (comment-only and string-only, line structure kept). It classes each site by kind and by region; the generated regions are the 6 `os-generated` pairs. At base, the hand-written parts hold 262 sites: 48 in comments (1 cross-repo) and 214 in rationale strings (19 cross-repo), over 177 distinct in-repo numbers. A REST probe of all 177 (`issues/N`, no redirect followed; lit control #20234 and dead control #8710 at the start, after every 50 and at the end): 165 answer 200, 12 answer 404, and 0 answer 301. Controls behaved 5/5 lit and 5/5 dead. The 12 numbers sit on exactly the 13 sites stage 10 named (`5902947213`). At head, the 162 distinct numbers all answer 200 (controls 5/5 and 5/5), and 0 dead sites remain. Site-set difference: 24 removed (13 dead and 11 live, all inside the 9 units) and 1 added (#8666, live, the PR link beside commit 4bfe1a5 in a comment, which form C allows). The 911 sites in generated regions do not change. **Text only.** A second instrument over TypeScript 6.0.3 evaluates the step-17 `rationale` and every step-18 fragment `text` (72 owners). It masks each of those initializers to one token that names its owner and cuts every comment, JSDoc included. The base and head leaf-token streams are IDENTICAL: 37,526 tokens, sha256 prefix `647bc09580ac619e` on both sides. Evaluated values changed for exactly 9 owners, the units listed above, and each word diff is the citation and its replacement words only. Controls mutate the head in memory: a comment insertion stays IDENTICAL, and each of these DIFFERS: a fragment `order` change, a fragment `id` change, an unmasked string edit, a conversion-id string edit, and an appended declaration (6/6). **Regeneration.** Before regeneration, `check:migration-registry` and `check:spec-changes` exit 0, and `check:upgrade-guide` exits 1. `check:generated --fix` regenerated only the guide. Its word diff on line 68 shows `mongodb` (#6345). becoming `mongodb`. and #4410 becoming the decision in words. After the `origin/main` merge (`6dd99b82c3`, through `os-regen-merge.sh`, which touched none of these paths), a rebuild plus `check:generated` reports "All 15 generated artifacts are up to date". No regeneration commit was owed. **Pins and quotes.** No test asserts a changed phrase. `content/docs/**` and `skills/**` quote none of them. The other hits for the old spellings are independent comments in other files (live numbers), release-owned CHANGELOGs and one test title, all left alone. **Tests and gates** (at head `64bbd3693e`; all builds and tests through `scripts/pm/os-verify-lock.sh`, each VERDICT command-exit 0): - `pnpm --filter @objectstack/spec build`, and a full `turbo run build --concurrency=2` over `./packages/*` and `./packages/*/*` (71/71). - spec local project: Test Files 606 passed, Tests 17952 passed, 1 todo. - spec repo project, 47 of its 51 files by name: 47 passed, 750 tests, including `scripts/step18-rationale-merge.test.ts`. - `pnpm --filter @objectstack/spec typecheck`: `check:test-typecheck` OK. - `node scripts/pm/dispatch-gates.mjs --repo objectstack-ai/objectstack`: 85 families derived, 85 run, all exit 0, reconciled with `--ran` ("0 NOT-MEASURED, 0 UNRUN"). That includes `check:doc-authoring` (self-test and run), `check:issue-citations`, `check:nul-bytes`, `check:generated`, `check:migration-registry`, `check:upgrade-guide` and the changeset gates. Three of them first exited 3 (prerequisite: unbuilt dist) and were rerun green after the full build. - Lint, as a proven narrowing: `eslint --no-inline-config --format json` over the one touched `.ts` file reports 1 file, 0 errors, 0 warnings, and `isPathIgnored` is false. `eslint.config.mjs:327-328` states that type-aware linting is never enabled, so a text edit cannot move an untouched file's verdict. The repo-wide `pnpm lint` is CI's run. - NOT MEASURED, declared to CI as in stages 8 to 10: `scripts/build-schemas-check-mode.test.ts` (it overran the foreground cap on its own in stage 10; it parses this file's source, whose code tokens the text-only proof shows unchanged), plus `def-key-collisions` and the two `publish-smoke-*` files (temp-tree rebuild or server boot). **Changeset.** `packages/spec` `files[]` ships `dist`. In the built dist, the new phrases appear in 2 files (`dist/migrations/index.js`, `.mjs`), the old spellings in 0, and an unchanged control phrase in the same 2. Hence `patch`. ## Acceptance notes - **Open, for the seat:** whether the 192 live author-visible numbers become a stage, and on which card (#20234, or #20749 whose stages currently exclude this file). They are not filed. - **Gate coverage boundary (carrier: none; noted, not filed):** the citation gate reads comment prose only, so these 11 dead rationale sites were never in its census. Stage 9 recorded the same boundary for conversion summaries. --- _Generated by [Claude Code](https://claude.ai/code/session_01YDt3PzwfrkuFzUBF89WPmM)_ --------- Co-authored-by: Claude <noreply@anthropic.com>
1 parent 1777a9b commit 0bddffd

3 files changed

Lines changed: 58 additions & 30 deletions

File tree

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
---
2+
'@objectstack/spec': patch
3+
---
4+
5+
Nine migration-step rationale passages state their decisions in words instead of tracker numbers, and two registry comments cite the commit that decided them
6+
7+
Clause-②: no
8+
9+
The protocol 17 and protocol 18 step rationales are what `os migrate meta` shows per hop
10+
and what the protocol upgrade guide prints. Nine of their passages named GitHub issues
11+
that no longer exist, so an upgrading author met a number with nothing behind it. Each of
12+
those passages now carries no number at all and says what was decided: why `mongo` and
13+
`mongodb` are both accepted, why the form-view option `default` and `connector.errorMapping`
14+
were retired, which earlier cleanup the import mapping `lookup` params finish, what the
15+
memory driver's placeholder refusal extends, how the plugin manifest's `contributes`
16+
members and `routes` were retired, and why the stack `themes` carrier and the
17+
component-translation `submitLabel` key went. Two source comments of the migration
18+
registry now cite the commit behind them. Text only: no migration step, entry, retired key
19+
or def, conversion, schema, export or runtime behaviour changes.

‎docs/protocol-upgrade-guide.md‎

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -65,7 +65,7 @@ Closing the same audit on the data side, `datasource.readReplicas` is removed (#
6565

6666
The datasource close-out also graduates the four legacy `datasource.config` spellings the shared driver factory still tolerated via undeclared read-side `??` fallbacks (#4456, the #4410 follow-up): sqlite `file`/`database` (use `filename`), postgres/mysql `connectionString` (use `url`) and `user` (use `username`), and mongo `uri` (use `url`) and `user` (use `username`). #4410 made the authoring gate reject each with a rename hint, but a runtime datasource persisted in `sys_metadata` before the gate kept working only because the factory read leniently — and deleting that tolerance without a conversion would have silently moved data (a stored sqlite `file:` row falls back to `:memory:`). The `datasource-config-driver-key-aliases` conversion rewrites the stored shape to the canonical keys at every rehydration seam, the factory now reads exactly one spelling per key, and the four `??` chains are deleted. Driver-aware by construction: `database` renames only under sqlite, where it aliased the file path — for every other driver it is a canonical key and is untouched. Retired from the load path not for lying but because the authoring gate already rejects the spellings loudly; the chain and the stored-row replay are the seams that accept them.
6767

68-
Finishing the same datasource surface, the canonical driver id `mongo` is renamed to `mongodb` (#6345). The two spellings have both been accepted since #4410 and both still are, so no boot breaks and no data moves — what changed is which one is CANONICAL, and that string is published as `DRIVER_CATALOG.id` and is what the Studio connection form writes into `datasource.driver`. Every row written before the rename therefore carries `mongo` while the form now emits `mongodb`, leaving one deployment with two spellings of one driver and any reader that matches a stored driver against the published catalog id silently missing the older rows. The `datasource-driver-mongo-to-mongodb` conversion converges the stored value at every rehydration seam; it stays on the LIVE load path (unlike the config-key aliases beside it) precisely because `mongo` is still legal — there is no loud rejection for it to pre-empt, and nothing to lose by converging early. The rename is what let the driver-selection id and the config-contract id become one string: `packages/spec`'s driver vocabulary is now a single table both boot hosts read, which closed the last fork where `OS_DATABASE_DRIVER=pg` booted under `os start` and was refused by `os migrate`. `turso`/libSQL joins the same table with a real config contract, so a libSQL `config` is validated instead of waved through.
68+
Finishing the same datasource surface, the canonical driver id `mongo` is renamed to `mongodb`. The two spellings have both been accepted since `datasource.config` was first parsed against its driver's own contract, and both still are, so no boot breaks and no data moves — what changed is which one is CANONICAL, and that string is published as `DRIVER_CATALOG.id` and is what the Studio connection form writes into `datasource.driver`. Every row written before the rename therefore carries `mongo` while the form now emits `mongodb`, leaving one deployment with two spellings of one driver and any reader that matches a stored driver against the published catalog id silently missing the older rows. The `datasource-driver-mongo-to-mongodb` conversion converges the stored value at every rehydration seam; it stays on the LIVE load path (unlike the config-key aliases beside it) precisely because `mongo` is still legal — there is no loud rejection for it to pre-empt, and nothing to lose by converging early. The rename is what let the driver-selection id and the config-contract id become one string: `packages/spec`'s driver vocabulary is now a single table both boot hosts read, which closed the last fork where `OS_DATABASE_DRIVER=pg` booted under `os start` and was refused by `os migrate`. `turso`/libSQL joins the same table with a real config contract, so a libSQL `config` is validated instead of waved through.
6969

7070
The `script` flow node converges on its one real path (#4343). It had four ways to name what it ran and only one of them ran anything: `config.actionType: 'email' | 'slack'` were logger-backed stubs that wrote a line, reported success and delivered nothing under any configuration — with `config.template` / `.recipients` / `.variables` feeding a message no channel ever sent; inline `config.script` was recognized and never executed (the built-in runtime has no server-side JS sandbox), so the node warned and no-op'd; and every other `actionType` value was shorthand for a registered-function name, a second spelling of `config.function`. All five keys are retired and `function` becomes required, which is also what finally made the contract PARSEABLE: while the legal key set depended on `actionType`, a flat parse would either reject valid shapes or wave everything through, so `script` (with `subflow`) now runs through the same execute-time contract parse #4277 gave the flat builtins. A shorthand `actionType` CONVERTS into `function` — that is what it meant — unless `function` is already set, in which case it was dead metadata the executor never reached. The other four are dropped outright: nothing read them, so there is no value to preserve, and rebuilding the intent is an authoring decision the tombstones prescribe per branch (a `notify` node for mail — it delivers through the messaging service, the in-app inbox by default and real email once `@objectstack/plugin-email` is installed; a `connector_action` with the Slack connector, or an `http` node posting to a webhook, for Slack; a registered function for an inline body). Retired from the load path for the same reason as the rest: absorbing `actionType: 'email'` silently would let an author keep believing the flow sends mail.
7171

‎packages/spec/src/migrations/registry.ts‎

Lines changed: 38 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -341,7 +341,8 @@ const step17: MigrationStep = {
341341
'but because the authoring gate already rejects the spellings loudly; the chain and the ',
342342
'stored-row replay are the seams that accept them.\n\n',
343343
'Finishing the same datasource surface, the canonical driver id `mongo` is renamed to ',
344-
'`mongodb` (#6345). The two spellings have both been accepted since #4410 and both still ',
344+
'`mongodb`. The two spellings have both been accepted since `datasource.config` was first ',
345+
'parsed against its driver\'s own contract, and both still ',
345346
'are, so no boot breaks and no data moves — what changed is which one is CANONICAL, and ',
346347
'that string is published as `DRIVER_CATALOG.id` and is what the Studio connection form ',
347348
'writes into `datasource.driver`. Every row written before the rename therefore carries ',
@@ -5177,7 +5178,7 @@ const STEP18_RATIONALE: readonly RationaleFragment[] = [
51775178
id: 'connector-error-mapping-retired',
51785179
order: 22,
51795180
text:
5180-
'It also retires `connector.errorMapping` (#14676, ADR-0049 enforce-or-remove; triage '
5181+
'It also retires `connector.errorMapping` (ADR-0049 enforce-or-remove; triage '
51815182
+ 'ruling 2026-09-02): `ErrorMappingConfig` (4 keys) and its `ErrorMappingRule[]` (7 keys) '
51825183
+ 'were authorable through `ConnectorSchema` — and, via `DeclarativeConnectorEntrySchema`, '
51835184
+ 'through `stack.connectors[]` and the `/meta/connector` door — and read by nothing: no '
@@ -5598,14 +5599,16 @@ const STEP18_RATIONALE: readonly RationaleFragment[] = [
55985599
order: 19,
55995600
text:
56005601
'Finally, it narrows the per-option `default` key OUT of the form-view options '
5601-
+ 'vocabulary (#12868, ADR-0049 declared-but-unenforced; maintainer ruling 2026-08-28 '
5602-
+ 'on the objectui#6263 analysis, disposition 甲): `SelectOptionSchema` serves two '
5603-
+ 'surfaces and only the OBJECT-field face reads `default` (#7246 / PR #7388 — '
5604-
+ '`applyFieldDefaults` falls back to the option marked `default: true`; that face, its '
5605-
+ 'alias rows and its precedence pin are untouched). On a form-view field\'s option list '
5602+
+ 'vocabulary (ADR-0049 declared-but-unenforced; maintainer ruling 2026-08-28 '
5603+
+ 'on the console form renderer\'s analysis, disposition 甲): `SelectOptionSchema` serves '
5604+
+ 'two surfaces and only the OBJECT-field face reads `default` (enforced there by a '
5605+
+ 'maintainer ruling of 2026-08-10 — `applyFieldDefaults` falls back to the option marked '
5606+
+ '`default: true`; that face, its alias rows and its precedence pin are untouched). On a '
5607+
+ 'form-view field\'s option list '
56065608
+ 'the key parsed clean and nothing read it — the insert-path fallback consults the '
56075609
+ 'object definition\'s options, never a form view\'s, and no form renderer seeds a value '
5608-
+ 'from it (measured on objectui#6263; the ruled census found ZERO authored occurrences '
5610+
+ 'from it (measured against the console\'s form controls, none of which reads the key; '
5611+
+ 'the ruled census found ZERO authored occurrences '
56095612
+ 'across the tree, the example apps and the published *.form.ts corpus). The FormView '
56105613
+ 'vocabulary\'s own option shape (`FormSelectOptionSchema`, ui/view.zod.ts) now refuses '
56115614
+ 'the key with the prescription; the mechanical conversion strips it from stored '
@@ -5700,8 +5703,9 @@ const STEP18_RATIONALE: readonly RationaleFragment[] = [
57005703
id: 'mapping-lookup-params-retired',
57015704
order: 13,
57025705
text:
5703-
'It also retires the import mapping `lookup` transform\'s steering params (#10329, '
5704-
+ 'ADR-0049 enforce-or-remove — the sub-walk half of 17.0.0\'s #4509 mapping cleanup): '
5706+
'It also retires the import mapping `lookup` transform\'s steering params (ADR-0049 '
5707+
+ 'enforce-or-remove — the sub-walk half of the 17.0.0 mapping cleanup that retired '
5708+
+ '`extractQuery` / `errorPolicy` / `batchSize`): '
57055709
+ '`fieldMapping[].params.object` / `.fromField` / `.toField` / `.autoCreate` declared a '
57065710
+ 'per-entry reference-resolution dialect the import path never implemented — `lookup` '
57075711
+ 'copies the cell through and resolution runs off the target field\'s own metadata — '
@@ -5715,10 +5719,11 @@ const STEP18_RATIONALE: readonly RationaleFragment[] = [
57155719
id: 'memory-persistence-placeholder-refused',
57165720
order: 1,
57175721
text:
5718-
'Protocol 18 extends the #8336 unresolved-placeholder refusal to the memory '
5722+
'Protocol 18 extends the publish-time refusal of unresolved placeholders, which protocol '
5723+
+ '17 applied to datasource connection config, to the memory '
57195724
+ 'driver\'s config-material persistence keys: `persistence.path` (file persistence '
57205725
+ 'and the `auto` override) and `persistence.key` (localStorage and the `auto` '
5721-
+ 'override) refuse `${…}` placeholder syntax at publish (#8495). Nothing resolves a '
5726+
+ 'override) refuse `${…}` placeholder syntax at publish. Nothing resolves a '
57225727
+ 'placeholder there — the driver would create a literal `./${DATA_DIR}/…` path or '
57235728
+ 'write under the literal localStorage key — the same authored-under-a-false-belief '
57245729
+ 'shape, one surface over. The memory driver\'s `initialData` stays deliberately '
@@ -5729,8 +5734,8 @@ const STEP18_RATIONALE: readonly RationaleFragment[] = [
57295734
id: 'metadata-customization-protocol-retired',
57305735
order: 20,
57315736
text:
5732-
'It also retires the paper metadata-customization protocol whole (#13135, re-charter '
5733-
+ 'of #12057; ADR-0049 enforce-or-remove, maintainer ruling 2026-08-29): '
5737+
'It also retires the paper metadata-customization protocol whole (ADR-0049 '
5738+
+ 'enforce-or-remove, maintainer ruling 2026-08-29): '
57345739
+ '`kernel/metadata-customization.zod.ts` — the three-layer platform/user patch-overlay '
57355740
+ 'model with field-level change tracking and a 3-way-merge story — was exported, '
57365741
+ 'documented as the customization architecture, and implemented ONLY by an unreachable '
@@ -5960,20 +5965,22 @@ const STEP18_RATIONALE: readonly RationaleFragment[] = [
59605965
order: 16,
59615966
text:
59625967
'Finally, it retires nine of the eleven members of the plugin manifest\'s '
5963-
+ '`contributes` block (#10724, ADR-0049 enforce-or-remove; triage graded 2026-08-21, '
5968+
+ '`contributes` block (ADR-0049 enforce-or-remove; triage graded 2026-08-21, '
59645969
+ 'cloud census leg discharged clean 2026-08-24): `events`, `menus`, `themes`, '
59655970
+ '`translations`, `actions`, `drivers`, `fieldTypes`, `functions` and `commands`. '
5966-
+ '#10627 measured — three repos, controlled — that the whole monorepo contains exactly '
5967-
+ 'one non-test read of `manifest.contributes`, and it reads `kinds`; the other nine '
5971+
+ 'A census of all three repos, with controls, measured that the whole monorepo '
5972+
+ 'contains exactly one non-test read of `manifest.contributes`, and it reads `kinds`; '
5973+
+ 'the other nine '
59685974
+ 'members parsed, entered the manifest, and changed nothing, while published docs and '
59695975
+ 'the schema\'s own JSDoc kept teaching them (`commands` documented Commander.js '
59705976
+ 'resolution the CLI dropped for oclif; `fieldTypes` advertised a registration seam '
59715977
+ 'that never existed). All nine are retiredKey tombstones mirroring `loading`; '
5972-
+ '`kinds` survives (live reader) and `routes` is untouched pending its own fork '
5973-
+ '(#10726). D3 semantic, no D2 conversion: a manifest is not a stack collection '
5978+
+ '`kinds` survives (live reader), and `routes` was left to a ruling of its own, which '
5979+
+ 'retired it as well (the `plugin-manifest-contributes-routes-retired` entry). D3 '
5980+
+ 'semantic, no D2 conversion: a manifest is not a stack collection '
59745981
+ 'member, so a conversion would be a transform with no seam that ever runs. '
5975-
+ 'On the surviving `kinds` bucket it also retires the `globs` sub-field (#11169, '
5976-
+ 'ADR-0049 enforce-or-remove; maintainer ruling 2026-08-24): the schema promised '
5982+
+ 'On the surviving `kinds` bucket it also retires the `globs` sub-field (ADR-0049 '
5983+
+ 'enforce-or-remove; maintainer ruling 2026-08-24): the schema promised '
59775984
+ 'that declaring `globs` enables file-type discovery, but discovery globs '
59785985
+ '`filePatterns` off the metadata type registry — which `contributes.kinds` does '
59795986
+ 'not extend, as `metadata-plugin.zod.ts` records outright — so an authored '
@@ -6017,8 +6024,8 @@ const STEP18_RATIONALE: readonly RationaleFragment[] = [
60176024
id: 'stack-themes-carrier-retired',
60186025
order: 11,
60196026
text:
6020-
'Finally, it retires the stack `themes` carrier and `ThemeSchema` whole (#10485, '
6021-
+ 'ADR-0049 enforce-or-remove; maintainer ruling 2026-08-21, disposition B: 退役授权面): '
6027+
'Finally, it retires the stack `themes` carrier and `ThemeSchema` whole (ADR-0049 '
6028+
+ 'enforce-or-remove; maintainer ruling 2026-08-21, disposition B: 退役授权面): '
60226029
+ 'the pipeline was live from the authoring gate through artifact ingest and stopped '
60236030
+ 'there — zero non-test readers of stored `theme` items, `theme` never a registered '
60246031
+ 'metadata type, no first-party app mounting the spec-aware provider, nothing '
@@ -6046,16 +6053,17 @@ const STEP18_RATIONALE: readonly RationaleFragment[] = [
60466053
order: 14,
60476054
text:
60486055
'Finally, it retires the component-translation copy key '
6049-
+ '`pages.<name>.components.<id>.submitLabel` and its `submit` alias (#10926, ADR-0049; '
6056+
+ '`pages.<name>.components.<id>.submitLabel` and its `submit` alias (ADR-0049; '
60506057
+ 'maintainer ruling 2026-08-22): the face is measured, not mirrored — each copy key '
60516058
+ 'exists because some component in `ComponentPropsMap` declares it — and '
6052-
+ '`submitLabel`\'s only declarer was `element:form`, retired whole above (#9249), so '
6059+
+ '`submitLabel`\'s only declarer was `element:form`, retired whole above, so '
60536060
+ 'the key had no declared component left to translate and the resolver overlay was '
60546061
+ 'its only reader. Retire won over re-anchor because the live form surface '
60556062
+ '(`object-form`) speaks `submitText` (`I18nLabelSchema`), localizable at its own '
60566063
+ 'authoring site; re-anchoring would have widened the face for one word. The '
60576064
+ 'mechanical conversion strips the key from stored bundles and items (pure lossless '
6058-
+ 'delete — nothing read it since #9249), at the acknowledged cost of dropping the '
6065+
+ 'delete — nothing read it once `element:form` was retired), at the acknowledged cost '
6066+
+ 'of dropping the '
60596067
+ 'bespoke-component route for that one word.',
60606068
},
60616069
{
@@ -6298,8 +6306,9 @@ const STEP18_RATIONALE: readonly RationaleFragment[] = [
62986306
* could act on, so removing it is behaviour-preserving; retired from the
62996307
* load path (the schema refuses live authors), replayed by `migrate meta`
63006308
* and the stored-row rehydration seam. Semantic: the memory-driver
6301-
* persistence placeholder refusal (#8495) — the #8336 parent adjudication
6302-
* applied to the two config-material memory keys its deliberate
6309+
* persistence placeholder refusal (commit 4bfe1a539, PR #8666: `${…}` refused
6310+
* at publish in `persistence.path` / `persistence.key`) — the #8336 parent
6311+
* adjudication applied to the two config-material memory keys its deliberate
63036312
* `initialData` exclusion never covered — the
63046313
* `MetadataPluginConfig.additionalTypes` retirement (#8586, ADR-0049): the
63056314
* inert plugin kind-declaration key, tombstoned on the 17.x line, with no D2
@@ -24932,7 +24941,7 @@ export const RETIRED_DEFS_BY_MAJOR: Readonly<Record<number, readonly string[]>>
2493224941
// The 2026-08-08 ADR-0049 sweep (#6486) adds twenty-three more across three
2493324942
// members (4 + 10 + 9), all route 3 and all whole-def: `system/http-server.zod.ts`'s
2493424943
// runtime vocabulary (#5295, D3 `http-server-runtime-vocabulary-retired`),
24935-
// `api/protocol.zod.ts`'s viewId-addressed view CRUD (#6239, D3
24944+
// `api/protocol.zod.ts`'s viewId-addressed view CRUD (commit f549a0d4a, D3
2493624945
// `view-management-protocol-retired`) and the whole L2 ETL layer (#6414, D3
2493724946
// `etl-pipeline-layer-retired`). None had a carrier key and none was ever
2493824947
// parsed outside its own unit tests, so again there is no tombstone and no D2

0 commit comments

Comments
 (0)