Skip to content

Commit 2da35ae

Browse files
test(cli): pin migrate meta's range rewrite on the --from 17 shape, now that the runtime is protocol 18 (#22539)
Fixes #22219 Clause-②: no The diff adds one test row and publishes nothing. ## What this adds - The `from: 17` row of `SHAPES` in `packages/cli/test/migrate-meta-protocol-range.test.ts`, verbatim as the previous holder's dev quoted it (report comment 6056787854, last `out_of_scope_findings` entry). It is a `'^17'` manifest carrying `dashboards: [{ name: 'ops', label: 'Ops', widgets: [], refreshInterval: 300 }]`, a key the protocol-18 step converts (`dashboard-refresh-interval-to-refresh-interval-seconds`). - With it, cases 1 and 2 of the file (`describe.each(SHAPES)`) run for `--from 17`, the shape this card was filed on: - the control: the load refuses the manifest, and the refusal names this command; - a dry run names the range edit and writes nothing; - `--write` rewrites `'^17'` to `'^18'` beside the rename, and only those bytes change; - the reload is not refused; - a `'^17'` manifest with nothing to convert gets the range edit alone, and then loads. - The two comments that said the 17 → 18 row was still to come now say what the file pins. - No source edit. `packages/cli/test` is outside `@objectstack/cli`'s `files`, so this publishes nothing and carries no changeset (`skip-changeset`). Diff: 1 file, +7 / −4. ## The row's three premises, measured first All readings are at `1cbd8f728`, which is `origin/main` `4e9fe9ff6` plus this test edit. 1. **The conversion id exists.** It is at `packages/spec/src/conversions/registry.ts:11495` with `toMajor: 18` and `retiredFromLoadPath: true`. It is listed in `MAJOR_18_CONVERSIONS` at `:15041` (order 24). 2. **Protocol 18 tombstones the key, so the authored-source load hands it to the chain as written.** - `packages/spec/src/ui/dashboard.zod.ts:1774` declares `refreshInterval: retiredKey(...)`, and its prescription names `os migrate meta --from 17`. - `DashboardSchema` from this worktree's build (`PROTOCOL_VERSION` 18.0.0) refuses the member with `invalid_type` at `refreshInterval`, carrying the tombstone text. The renamed shape parses. - In the test, the control answers `STACK_SCHEMA_INVALID` naming `migrate meta --from 17`. `--write --json` reports `applied` and `written` as exactly that one conversion id. 3. **The member is a valid protocol-17 dashboard.** `DashboardSchema.safeParse` was run against the published npm packages: - `@objectstack/spec@17.0.0` and `@17.3.0` accept it. Both refuse the renamed `refreshIntervalSeconds` as an unrecognized key. - `@17.7.0`, still `PROTOCOL_VERSION` 17.0.0, refuses it at the tombstone, because the rename shipped inside the 17 line (`retiredAfter: '17.3.0'`). - So it is the shape an app authored on 17.0 to 17.3 carries. The member is unchanged from the quoted row. It is the conversion fixture's own shape (`name`, `label`, `widgets`, the key), so nothing smaller is valid. ## Red, then green - **Green as committed** (`1cbd8f728`): the file reports `Test Files 1 passed (1)` and `Tests 19 passed (19)`, which is the 14 earlier cases plus 5 for `--from 17`. - **Red with `planProtocolRange` neutralised.** This was a one-off ablation from the committed state; no file was left behind. - Method: `scripts/ablation-replace.mjs`, wrapped in a bash `trap … EXIT INT TERM` that restores from `HEAD` on an absolute path and proves the restore. - The mutation: the anchor `if (compat.status !== 'incompatible') return undefined;` became `if (true as boolean) return undefined; // ABLATION-22219 …` in `packages/cli/src/commands/migrate/meta.ts`. - Proof it landed on disk: anchor count 1 → 0, marker count 0 → 1, and the blob went `f026976c` → `4bb72fea`. A grep run inside the mutation window read marker 1 and anchor 0. - No rebuild was needed: the test imports `meta.ts` relatively, so it loads from `src`. - Result: `Tests 15 failed | 4 passed (19)`. Every `--from 17` case went red except its control: the dry run, `--write`, the reload, and the nothing-to-convert case. - The `--from 17` reload answered this card's titled refusal: `ProtocolIncompatibleError` `OS_PROTOCOL_INCOMPATIBLE` 422, "package 'com.example.range' targets protocol ^17 (engines.protocol) but this runtime is protocol 18.0.0. This is a major-version break. Run: objectstack migrate meta --from 17". - Restore proven twice, by the tool and by the trap: the blob after restore is `f026976c08cc`, equal to the blob at `HEAD`; `git diff HEAD` was empty and the porcelain was empty. ## Verification, all at `1cbd8f728` - **cli unit layer** (`pnpm --filter @objectstack/cli exec vitest run --project unit --maxWorkers=2`): `Test Files 275 passed (275)`, `Tests 4062 passed (4062)`, `VERDICT command-exit 0`. `vitest list --project unit --filesOnly` lists this file, and the integration list does not. - **`pnpm --filter @objectstack/cli typecheck`**: `VERDICT command-exit 0`. - `check:test-typecheck` reports OK at `3 file(s) / 28 error(s) / 6 pinned signature(s)`, unchanged. - The file is in `tsconfig.test.json`'s program (`--listFilesOnly`: 1 hit) and has no debt-ledger row. - **Lint, as a proven narrowing:** - ① Population, read from eslint's own config: `isPathIgnored` is false, and `calculateConfigForFile` applies 5 rules. - ② Count, read from `eslint --no-inline-config --format json`: 1 file, 0 errors, 0 warnings, 0 fatal. - ③ Invariance: the config enables no type-aware linting. Every `parserOptions` is `{ ecmaVersion, sourceType }`, with no `project` and no `projectService`, as `eslint.config.mjs` itself states. So an edit to one test file cannot move any other file's verdict. - The full `pnpm lint` is declared to CI. - **Derived gates:** - `dispatch-gates --commands`, run with no paths, derived 50 commands, identical to the dispatched list. - `--ran` reports `50 derived, 50 run, 0 NOT-MEASURED, 0 UNRUN`. - `check:dual-build-cjs-loads` first exited 3 (PREREQUISITE NOT MET: dists outside the CLI closure). I built those with turbo (68/68 cached) and re-ran it: exit 0. - **Integration layer and dogfood**: declared to CI. The diff touches no spawn entry and no dogfood input. ## Acceptance notes - `dispatch-gates` warns that the tree is behind `origin/main`, and that `scripts/engine-double-contract.pinned.json` moved in that range. No commit in `4e9fe9ff6..faf6348` touches this file, `packages/cli/src/commands/migrate/**`, the dashboard schema, the conversion registry, the codemod, the config loader or the handshake. So `main` was not merged, per the claim's fence; CI runs on the merge ref. - `check:type-check-debt` (`--re-measure`) rebuilds package dists in the worktree while it runs. A unit run alongside it hit module-not-found errors mid-rebuild, so I discarded that run and re-took it after the gates finished. - The member counts as valid protocol-17 metadata only as published at 17.0.0 to 17.3.0. From 17.7.0, still on protocol 17, the 17-line schema refuses `refreshInterval` itself. This is an observation only. --- _Generated by [Claude Code](https://claude.ai/code/session_01BmsuLyUeuG5CNpZFMH1jzS)_ Co-authored-by: Claude <noreply@anthropic.com>
1 parent 3073b72 commit 2da35ae

1 file changed

Lines changed: 7 additions & 4 deletions

File tree

‎packages/cli/test/migrate-meta-protocol-range.test.ts‎

Lines changed: 7 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -40,8 +40,10 @@
4040
* land is caught by the re-check and restored; the planner refuses a range
4141
* literal it cannot prove, by the same refusal kinds.
4242
*
43-
* The 17 → 18 shape is a second row of {@link SHAPES}, once the runtime
44-
* implements protocol 18.
43+
* {@link SHAPES} pins cases 1 and 2 once per major migrated from: the
44+
* `--from 16` shape the fix was first pinned on, while the runtime implemented
45+
* protocol 17, and the `--from 17` shape the defect was filed on, reachable
46+
* since the runtime implements protocol 18.
4547
*
4648
* In-process over the real command (`MigrateMeta.run`) and the real load seam
4749
* (`AppPlugin.init` with a context double), against temp projects that link
@@ -87,8 +89,8 @@ const RUN_TIMEOUT = 120_000;
8789
* The shapes the load refuses on this runtime, one row per major migrated
8890
* FROM: the major, and one authored member the chain converts out of it — a
8991
* key the current schema tombstones, so the authored-source load hands it to
90-
* the chain as written. The 17 → 18 row joins once this runtime implements
91-
* protocol 18, with a member the protocol-18 step converts.
92+
* the chain as written. The `--from 16` row's member is converted by the
93+
* protocol-17 step, and the `--from 17` row's by the protocol-18 step.
9294
*/
9395
const SHAPES = [
9496
{
@@ -98,6 +100,7 @@ const SHAPES = [
98100
before: ', striped: true',
99101
after: '',
100102
},
103+
{ from: 17, member: "dashboards: [{ name: 'ops', label: 'Ops', widgets: [], refreshInterval: 300 }]", converted: ['dashboard-refresh-interval-to-refresh-interval-seconds'], before: 'refreshInterval: 300', after: 'refreshIntervalSeconds: 300' },
101104
];
102105

103106
/** The range `--write` writes on this build: the scaffold's spelling, at this runtime's major. */

0 commit comments

Comments
 (0)