feat(spec)!: the ADR-0087 migration chain leaves the root entry for @objectstack/spec/migrations (#20646) - #20695
Conversation
…objectstack/spec/migrations (wip: entry + exports) Claude-Session: https://claude.ai/code/session_014EJ1ED8X4MMrT18BhVx4tx Co-authored-by: Claude <noreply@anthropic.com>
…ve the migration importers to @objectstack/spec/migrations Claude-Session: https://claude.ai/code/session_014EJ1ED8X4MMrT18BhVx4tx Co-authored-by: Claude <noreply@anthropic.com>
…ations entry Claude-Session: https://claude.ai/code/session_014EJ1ED8X4MMrT18BhVx4tx Co-authored-by: Claude <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_014EJ1ED8X4MMrT18BhVx4tx Co-authored-by: Claude <noreply@anthropic.com>
…ec-registries-subpath
…y as an entry, not a protocol namespace Claude-Session: https://claude.ai/code/session_014EJ1ED8X4MMrT18BhVx4tx Co-authored-by: Claude <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_014EJ1ED8X4MMrT18BhVx4tx Co-authored-by: Claude <noreply@anthropic.com>
…ec-registries-subpath
Claude-Session: https://claude.ai/code/session_014EJ1ED8X4MMrT18BhVx4tx Co-authored-by: Claude <noreply@anthropic.com>
📓 Docs Drift CheckThis PR changes 2 package(s): 13 hand-written doc(s) NAME something this change touched and may need an implementation-accuracy re-verification:
⛔ 6 release-owned page(s) also name something this change touched. These are read-only:
What this run could not see
Coarse fallback — 143 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 24c1006eaa73c1df2ed353cf2a0a9c8dfd208bca && git checkout 24c1006eaa73c1df2ed353cf2a0a9c8dfd208bca
# afterwards, rebuild it from the two parents, which stay fetchable
git fetch origin d2820876f7452e44620db6a1810a847613a46f67 6ce9c2b349ef86efb0cebdb50eb9bd04ce54be94 && git checkout -B drift-repro d2820876f7452e44620db6a1810a847613a46f67 && git merge --no-ff 6ce9c2b349ef86efb0cebdb50eb9bd04ce54be94
node scripts/docs-audit/affected-docs.mjs --json d2820876f7452e44620db6a1810a847613a46f67
|
Contract reviewServed-tier: Inputs: card #20646 (body, claim ① Derived judgments
② Semver level
③ Boundary flags
Implemented-by: VERDICT: PASS Generated by Claude Code |
…ec-registries-subpath # Conflicts: # packages/cli/src/commands/migrate/meta.ts
⛔ merge queue 构建失败 — 先分诊,再决定要不要重排队列构建 36645820047 红了。队列跑的是全量套件(PR 侧 CI 只跑 affected 子集), 失败的 job(日志抽取,best effort):
跨 PR 相同签名(24h,按失败测试文件聚合):
历史信号:
分诊清单:
Generated by Claude Code · merge-queue-triage workflow (#4859) |
|
The merge queue build failed on
Generated by Claude Code |
Fixes #20646
Clause-②: yes (narrowing — the ADR-0087 migration chain and change-manifest names, 17 values and 16 types, leave the package root
@objectstack/specfor the new@objectstack/spec/migrationsentry; the conversion layer stays on the root)This is the source-side payback of the maintainer's ruling on objectui#11088 (decision 1, letter A: raise the console first-screen ceiling now, pay it back at the source). It builds the shape the
domain:specseat ruled on the card (comment 5891704646, option A), under the claim amendment that allows exactly one change tomigrations/registry.ts: the generated D3 block for this narrowing's own ADR-0087 entry.Why the root carried the text
sideEffects: falsewas already declared, so it was not the cause. Each entry ships as one flat module (tsupsplitting: false). Inside it, a consumer's bundler has to keep every top-level call it cannot prove pure, and the migration registry computes things when its module loads: the list of majors, each step's rationale and step 18's conversion ids. So the whole registry (mostly theos migrate metaguidance text) rode in every bundle of the root, whatever the consumer imported. Rolldown (Vite 8's bundler, which the console uses), esbuild and rollup all agree.The conversion layer cannot leave the root chunk:
defineStackandnormalizeStackInputcallapplyConversions, which readsALL_CONVERSIONSat run time. Measured on the round-1 base 0cb72cf, dropping the conversions re-export as well moved the root by 1,828 bytes. It stays.Byte table
Before is the merge base
1a75e39d4a, built in a separate worktree; after is this head. Both are tsup JS builds, gzip -9.dist/index.js(CommonJS root)dist/index.mjsdist/browser/index.mjs(the ESM root a browser bundler pulls).objectui-shafindClosestMatchesindex.mjs:migrations/registry.tswent from 1,761,987 bytes to 0.conversions/registry.tsstays at 321,050.dist/migrations/index.jsis 2,280,591 raw / 616,800 gzip. It carries the chain plus the conversion registry it reads.What changed
packages/spec/src/index.tsstops re-exporting./migrations/index.js.packages/spec/package.jsongains the./migrationsexport (import/require/types, nobrowsercondition), andtsup.config.tsgains the entry.check:browser-reachable-entriesmeasured the entry as linking no Node builtin and no server-only package, so no browser condition is needed.browser-reachable-entries.jsonlists it underunjudged.entries/semantic/18.migrations-entry-split.ts(form D, no tracker number), concatenated bygen:migration-registry. The registry diff against the merge base is that block only: 52 insertions, 0 deletions.conversions/registry.tsis byte-identical.gen:spec-changesandgen:upgrade-guideproduce no diff, because major 18 is not yet in their window.packages/cli/src/commands/migrate/meta.ts;packages/cli/test/migrate-meta-default-range.test.ts,packages/cli/test/migrate-meta-engine-guidance.test.ts,packages/metadata-protocol/src/protocol.stored-migration.test.ts, andpackages/services/service-automation/src/builtin/decision-overlapping-edge-conditions.pin.test.ts(onlyapplyMetaMigrationsmoves;ALL_CONVERSIONSstays on the root import).index.tsfiles, covering static, dynamic, namespace and type imports. Repo gates import the registry modules by relative path, so none moves. objectui at the pin imports none of the moved names;cloudwas not measured.api-surface/andexport-origins/have a newmigrations.jsonshard, and 33 names leaveroot.jsonin each.packages/spec/src/root-entry-migrations-split.pin.test.tschecks four things, each negative with a positive control:./migrationsexports all of them, and nothing it exports is on the root;migrationsshard lists all of them;migrations/at all (the edge a bundler follows), and the exports map publishes./migrationsto the built files.No new gate, no byte ceiling.
content/docs/deployment/troubleshooting.mdx's ordered subpath sentence gainsmigrations(check:docs-spec-enumerations).CATEGORY_TITLES.migrationsbecomesMigrations Entry, following theapi-assembledprecedent, so the migrations subpath is counted as a subpath and not as a 16th protocol namespace; theschema-closurepin and its docblock follow.scripts/export-origins.test.ts's entry list gains./migrations.build-migration-registry.tsheader and thetsup.config.tsentry-count note.@objectstack/specminorwith a BREAKING banner, the FROM to TO table and theregistered migrations-entry-splitdisposition;@objectstack/clipatch.Verification record
Heads named per reading. The final head is
8558334ab5, merged withorigin/main1a75e39d4a.Reverse verification of the pin, committed first, mutated through
scripts/ablation-replace.mjs, atc4fdf1105e:./migrationsexports is on the root; the root graph does not reach the registry.Tests:
@objectstack/speclocal project, fullc4fdf1105e@objectstack/specrepo project, 42 of 43 filesc4fdf1105e@objectstack/specbuild-schemas-check-mode.test.ts, the four registry-copying blocksc4fdf1105esrc/migrations,export-originsandschema-closuretests8558334ab5@objectstack/cliunit project, fullc4fdf1105e@objectstack/cliintegration: the two touchedmigrate-metafilesc4fdf1105e@objectstack/metadata-protocolstored-migration testc4fdf1105e@objectstack/service-automationdecision pinc4fdf1105e@objectstack/runtimespec-subpath alias-coverage pinc4fdf1105eNOT MEASURED locally: the other 63 tests of
build-schemas-check-mode.test.ts(the file alone runs about 14 minutes, past the foreground cap); CI runs it.Typecheck:
@objectstack/specpassed atc1dcebf255.@objectstack/cli,@objectstack/metadata-protocoland@objectstack/service-automationpassed atc4fdf1105e.Gates:
node scripts/pm/dispatch-gates.mjs --commandsderives 132 families on the final head.--ranreconciles them as 131 run and 1 NOT MEASURED, with exit codes recorded.5936236fb7, 73 to 110 atc1dcebf255, and on8558334ab5the ratchet and generated-artifact set was re-run together with the 22 docs families the docs rider added.check:api-surface,check:published-files,check:dual-build-cjs-loads(105 require entry points across 66 packages load) andcheck:entry-nameability(494 call probes across 19 public entries).check:generated(all 15 artifacts current),check:adr-0087-registration('registered migrations-entry-split (new here)') andcheck:browser-reachable-entries.check:docs-spec-enumerations(fixed by the docs rider) andcheck:dual-build-cjs-loads(PREREQUISITE NOT MET, cleared by a full build).check:pm-dispatch-gates. Its self-test alone outran the 590-second foreground cap twice on the shared box, and every case it printed passed. The diff does not touchdispatch-gates.mjs.Lint: narrowed and proven, at
8558334ab5:eslint --no-inline-config --format jsonover the 16 changed.ts/.mjsfiles, which is every changed file in eslint's population (**/*.{ts,tsx,mts,cts,js,jsx,mjs,cjs}minusNEVER_LINTED).eslint.config.mjsenables no type-aware linting (noparserOptions.project, no typed rules), so this diff cannot move any untouched file's verdict. The full-treepnpm lintis CI's.Acceptance notes
migrations: 'Migrations Protocol'would have required listing Migrations as a 16th protocol namespace in the glossary,plugins/packages.mdxand four count claims. I followed theapi-assembledprecedent instead: a published entry that is not a metadata protocol domain is titledEntry.schema-closure.test.tshad pinnedCATEGORY_TITLES.migrationsto containProtocolas corroboration that migrations is NOT declared schema-free. That assertion now pinstoBe('Migrations Entry')andnot.toContain('Vocabulary'). The substantive half,schemaClosureAbsenceIsDeclared('migrations') === false, is untouched.ALL_CONVERSIONSis computed at import time (conversions/registry.ts), so the conversion registry (321,050 bytes of the root) stays in every root bundle, even for a consumer that never callsdefineStackornormalizeStackInput. On the light-consumer probe that is about 40 KB gzip. That would need an edit to the conversion registry, which this card excluded. Carrier: objectui#11101's seat. Noted, not filed.semanticlist.spec-changes.jsonand the upgrade guide do not project major 18 yet, so they are unchanged; they pick the entry up when the protocol major moves.Generated by Claude Code