Repository navigation
Commit fbec216
Fixes #20646
Clause-②: yes (narrowing — the ADR-0087 migration chain and
change-manifest names, 17 values and 16 types, leave the package root
`@objectstack/spec` for the new `@objectstack/spec/migrations` entry;
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:spec` seat ruled on the card (comment 5891704646, option A),
under the claim amendment that allows exactly one change to
`migrations/registry.ts`: the generated D3 block for this narrowing's
own ADR-0087 entry.
## Why the root carried the text
`sideEffects: false` was already declared, so it was not the cause. Each
entry ships as one flat module (tsup `splitting: 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 the `os migrate meta` guidance 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: `defineStack` and
`normalizeStackInput` call `applyConversions`, which reads
`ALL_CONVERSIONS` at 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.
| artifact | before (raw / gzip) | after (raw / gzip) |
| --- | --- | --- |
| `dist/index.js` (CommonJS root) | 3,780,033 / 1,067,061 | 2,009,810 /
565,386 (-46.8% raw) |
| `dist/index.mjs` | 3,766,221 / 1,065,949 | 1,996,676 / 564,356 |
| `dist/browser/index.mjs` (the ESM root a browser bundler pulls) |
3,764,293 / 1,065,388 | 1,994,748 / 563,787 |
| console-root probe: rolldown 1.0.3, platform browser, minified; the
entry imports the 10 names objectui's non-test code imports from the
root at the pinned `.objectui-sha` | 2,261,622 / 700,884 | 1,024,463 /
301,287 |
| light-consumer probe: rolldown, the entry imports only
`findClosestMatches` | 2,203,744 / 681,199 | 966,581 / 282,176 |
- **Source-map attribution of the root `index.mjs`:**
`migrations/registry.ts` went from 1,761,987 bytes to 0.
`conversions/registry.ts` stays at 321,050.
- **The new entry:** `dist/migrations/index.js` is 2,280,591 raw /
616,800 gzip. It carries the chain plus the conversion registry it
reads.
- **Console acceptance:** on the console-root probe the payback is
399,597 bytes gzip, against objectui#11088's 413.8 KB overage.
objectui's own eager-closure budget reading is objectui's to take once
its pin moves.
## What changed
- **Root entry:** `packages/spec/src/index.ts` stops re-exporting
`./migrations/index.js`. `packages/spec/package.json` gains the
`./migrations` export (import/require/types, no `browser` condition),
and `tsup.config.ts` gains the entry. `check:browser-reachable-entries`
measured the entry as linking no Node builtin and no server-only
package, so no browser condition is needed.
`browser-reachable-entries.json` lists it under `unjudged`.
- **ADR-0087 D3 entry:** `entries/semantic/18.migrations-entry-split.ts`
(form D, no tracker number), concatenated by `gen:migration-registry`.
The registry diff against the merge base is that block only: 52
insertions, 0 deletions. `conversions/registry.ts` is byte-identical.
`gen:spec-changes` and `gen:upgrade-guide` produce no diff, because
major 18 is not yet in their window.
- **Importers moved to the subpath:**
- the one runtime importer, `packages/cli/src/commands/migrate/meta.ts`;
- four tests: `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`, and
`packages/services/service-automation/src/builtin/decision-overlapping-edge-conditions.pin.test.ts`
(only `applyMetaMigrations` moves; `ALL_CONVERSIONS` stays on the root
import).
- This is the complete list: a TypeScript-AST census of every file
naming one of the 53 exports of the two `index.ts` files, 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; `cloud` was not measured.
- **Generated artifacts:** `api-surface/` and `export-origins/` have a
new `migrations.json` shard, and 33 names leave `root.json` in each.
- **Pin:** `packages/spec/src/root-entry-migrations-split.pin.test.ts`
checks four things, each negative with a positive control:
- the root module exports none of the 17 moved values;
- `./migrations` exports all of them, and nothing it exports is on the
root;
- the root api-surface shard lists none of the 33 names, while the
`migrations` shard lists all of them;
- the root's static value-import graph does not reach `migrations/` at
all (the edge a bundler follows), and the exports map publishes
`./migrations` to the built files.
No new gate, no byte ceiling.
- **Riders the gates forced** (details in Acceptance notes):
- `content/docs/deployment/troubleshooting.mdx`'s ordered subpath
sentence gains `migrations` (`check:docs-spec-enumerations`).
- `CATEGORY_TITLES.migrations` becomes `Migrations Entry`, following the
`api-assembled` precedent, so the migrations subpath is counted as a
subpath and not as a 16th protocol namespace; the `schema-closure` pin
and its docblock follow.
- `scripts/export-origins.test.ts`'s entry list gains `./migrations`.
- Stale comments are updated in the `build-migration-registry.ts` header
and the `tsup.config.ts` entry-count note.
- **Changesets:** `@objectstack/spec` `minor` with a BREAKING banner,
the FROM to TO table and the `registered migrations-entry-split`
disposition; `@objectstack/cli` `patch`.
## Verification record
Heads named per reading. The final head is `8558334ab5`, merged with
`origin/main` `1a75e39d4a`.
- **Reverse verification of the pin**, committed first, mutated through
`scripts/ablation-replace.mjs`, at `c4fdf1105e`:
- Mutation: the root re-export was re-added ('mutation landed: anchor 1
to 0').
- Result: the pin went red as predicted, 3 failed / 5 passed of 8. The
failures were: the root exports none of the moved values; nothing
`./migrations` exports is on the root; the root graph does not reach the
registry.
- Restore: 'blob == HEAD (36e34ad) and git diff HEAD is empty'. The
pin is green again, 8/8.
- **Tests:**
| suite | head | result |
| --- | --- | --- |
| `@objectstack/spec` local project, full | `c4fdf1105e` | 575 files,
16926 tests passed |
| `@objectstack/spec` repo project, 42 of 43 files | `c4fdf1105e` | 674
tests passed |
| `@objectstack/spec` `build-schemas-check-mode.test.ts`, the four
registry-copying blocks | `c4fdf1105e` | 24 passed |
| pin, `src/migrations`, `export-origins` and `schema-closure` tests |
`8558334ab5` | 206 passed |
| `@objectstack/cli` unit project, full | `c4fdf1105e` | 234 files, 3347
tests passed |
| `@objectstack/cli` integration: the two touched `migrate-meta` files |
`c4fdf1105e` | 10 passed, 1 skipped |
| `@objectstack/metadata-protocol` stored-migration test | `c4fdf1105e`
| 39 passed |
| `@objectstack/service-automation` decision pin | `c4fdf1105e` | 22
passed |
| `@objectstack/runtime` spec-subpath alias-coverage pin | `c4fdf1105e`
| 6 passed |
NOT 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/spec` passed at `c1dcebf255`.
`@objectstack/cli`, `@objectstack/metadata-protocol` and
`@objectstack/service-automation` passed at `c4fdf1105e`.
- **Gates:**
- Derived: `node scripts/pm/dispatch-gates.mjs --commands` derives 132
families on the final head. `--ran` reconciles them as 131 run and 1 NOT
MEASURED, with exit codes recorded.
- Heads: gates 1 to 72 of the first derivation ran at `5936236fb7`, 73
to 110 at `c1dcebf255`, and on `8558334ab5` the ratchet and
generated-artifact set was re-run together with the 22 docs families the
docs rider added.
- The four named gates, all exit 0: `check:api-surface`,
`check:published-files`, `check:dual-build-cjs-loads` (105 require entry
points across 66 packages load) and `check:entry-nameability` (494 call
probes across 19 public entries).
- Also exit 0: `check:generated` (all 15 artifacts current),
`check:adr-0087-registration` ('registered migrations-entry-split (new
here)') and `check:browser-reachable-entries`.
- Two reds, both fixed and re-run green: `check:docs-spec-enumerations`
(fixed by the docs rider) and `check:dual-build-cjs-loads` (PREREQUISITE
NOT MET, cleared by a full build).
- NOT MEASURED: `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 touch `dispatch-gates.mjs`.
- **Lint:** narrowed and proven, at `8558334ab5`:
- Scope: `eslint --no-inline-config --format json` over the 16 changed
`.ts`/`.mjs` files, which is every changed file in eslint's population
(`**/*.{ts,tsx,mts,cts,js,jsx,mjs,cjs}` minus `NEVER_LINTED`).
- Result: 16 files, 0 errors, 0 warnings.
- Why the narrowing excludes nothing: `eslint.config.mjs` enables no
type-aware linting (no `parserOptions.project`, no typed rules), so this
diff cannot move any untouched file's verdict. The full-tree `pnpm lint`
is CI's.
## Acceptance notes
- **The docs rider is a classification call the reviewer may want to
see.** Keeping `migrations: 'Migrations Protocol'` would have required
listing Migrations as a 16th protocol namespace in the glossary,
`plugins/packages.mdx` and four count claims. I followed the
`api-assembled` precedent instead: a published entry that is not a
metadata protocol domain is titled `Entry`. `schema-closure.test.ts` had
pinned `CATEGORY_TITLES.migrations` to contain `Protocol` as
corroboration that migrations is NOT declared schema-free. That
assertion now pins `toBe('Migrations Entry')` and
`not.toContain('Vocabulary')`. The substantive half,
`schemaClosureAbsenceIsDeclared('migrations') === false`, is untouched.
- **Conversions stay on the root, and they still ride in every root
bundle.** `ALL_CONVERSIONS` is 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
calls `defineStack` or `normalizeStackInput`. 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.
- **Upgrade guide:** the D3 entry lands in major 18's `semantic` list.
`spec-changes.json` and 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](https://claude.ai/code/session_014EJ1ED8X4MMrT18BhVx4tx)_
---------
Co-authored-by: Claude <noreply@anthropic.com>
1 parent f927864 commit fbec216
26 files changed
Lines changed: 505 additions & 98 deletions
File tree
- .changeset
- content/docs/deployment
- packages
- cli
- src/commands/migrate
- test
- metadata-protocol/src
- services/service-automation/src/builtin
- spec
- api-surface
- export-origins
- scripts
- lib
- src
- migrations
- entries/semantic
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
| 1 | + | |
| 2 | + | |
| 3 | + | |
| 4 | + | |
| 5 | + | |
| 6 | + | |
| 7 | + | |
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
| 1 | + | |
| 2 | + | |
| 3 | + | |
| 4 | + | |
| 5 | + | |
| 6 | + | |
| 7 | + | |
| 8 | + | |
| 9 | + | |
| 10 | + | |
| 11 | + | |
| 12 | + | |
| 13 | + | |
| 14 | + | |
| 15 | + | |
| 16 | + | |
| 17 | + | |
| 18 | + | |
| 19 | + | |
| 20 | + | |
| 21 | + | |
| 22 | + | |
| 23 | + | |
| 24 | + | |
| 25 | + | |
| 26 | + | |
| 27 | + | |
| 28 | + | |
| 29 | + | |
| 30 | + | |
| 31 | + | |
| 32 | + | |
| 33 | + | |
| 34 | + | |
| 35 | + | |
| 36 | + | |
| 37 | + | |
| 38 | + | |
| 39 | + | |
| 40 | + | |
| 41 | + | |
| 42 | + | |
| 43 | + | |
| 44 | + | |
| 45 | + | |
| 46 | + | |
| 47 | + | |
| 48 | + | |
| 49 | + | |
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
345 | 345 | | |
346 | 346 | | |
347 | 347 | | |
348 | | - | |
| 348 | + | |
349 | 349 | | |
350 | 350 | | |
351 | 351 | | |
| |||
Lines changed: 2 additions & 4 deletions
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
35 | 35 | | |
36 | 36 | | |
37 | 37 | | |
| 38 | + | |
38 | 39 | | |
39 | | - | |
40 | 40 | | |
41 | | - | |
42 | | - | |
43 | 41 | | |
44 | 42 | | |
45 | 43 | | |
46 | | - | |
| 44 | + | |
47 | 45 | | |
48 | 46 | | |
49 | 47 | | |
| |||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
5 | 5 | | |
6 | 6 | | |
7 | 7 | | |
| 8 | + | |
8 | 9 | | |
9 | | - | |
10 | 10 | | |
11 | 11 | | |
12 | | - | |
13 | | - | |
14 | 12 | | |
15 | 13 | | |
16 | 14 | | |
17 | 15 | | |
18 | | - | |
| 16 | + | |
19 | 17 | | |
20 | 18 | | |
21 | 19 | | |
| |||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
51 | 51 | | |
52 | 52 | | |
53 | 53 | | |
54 | | - | |
| 54 | + | |
55 | 55 | | |
56 | 56 | | |
57 | 57 | | |
| |||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
59 | 59 | | |
60 | 60 | | |
61 | 61 | | |
62 | | - | |
| 62 | + | |
63 | 63 | | |
64 | 64 | | |
65 | 65 | | |
| |||
Lines changed: 1 addition & 1 deletion
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
26 | 26 | | |
27 | 27 | | |
28 | 28 | | |
29 | | - | |
| 29 | + | |
30 | 30 | | |
31 | 31 | | |
32 | 32 | | |
| |||
Lines changed: 2 additions & 1 deletion
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
1 | 1 | | |
2 | 2 | | |
3 | 3 | | |
4 | | - | |
| 4 | + | |
| 5 | + | |
5 | 6 | | |
6 | 7 | | |
7 | 8 | | |
| |||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
| 1 | + | |
| 2 | + | |
| 3 | + | |
| 4 | + | |
| 5 | + | |
| 6 | + | |
| 7 | + | |
| 8 | + | |
| 9 | + | |
| 10 | + | |
| 11 | + | |
| 12 | + | |
| 13 | + | |
| 14 | + | |
| 15 | + | |
| 16 | + | |
| 17 | + | |
| 18 | + | |
| 19 | + | |
| 20 | + | |
| 21 | + | |
| 22 | + | |
| 23 | + | |
| 24 | + | |
| 25 | + | |
| 26 | + | |
| 27 | + | |
| 28 | + | |
| 29 | + | |
| 30 | + | |
| 31 | + | |
| 32 | + | |
| 33 | + | |
| 34 | + | |
| 35 | + | |
| 36 | + | |
| 37 | + | |
| 38 | + | |
| 39 | + | |
0 commit comments