Skip to content

Commit 59fb299

Browse files
fix(cli): os migrate meta runs on a composeStacks project and migrates its package bodies (#22326)
Fixes #22289 Clause-②: no `os migrate meta` now runs on a project whose config exports `composeStacks([defineStack({ … }), …], { manifest: 'preserve' })`, and it converts the retired spellings inside the package bodies. The one-package path is unchanged. Every change is in `packages/cli`. There is no `packages/spec` change, and nothing in `packages/cli` writes the provenance mark: the producer marks its own output. ## What changed 1. **A refused composed input is produced again by the producer** (`src/utils/config.ts`, the authored-source shim). The shim records each stack it hands through for a refused `defineStack` call, with the options it was called with. A generated `composeStacks` wrap maps only those recorded inputs through the real `defineStack(input, { ...options, strict: false })`, then calls the real `composeStacks`. Every other input reaches the real `composeStacks` untouched, including a plain object the author never wrapped, so that one is still refused. The one-package path keeps handing the authored argument through raw (H3 below says why). The record is one bundled module that every shim module imports, so a stack handed through by one `@objectstack/spec` entrypoint is recognised by another, and a record lasts for one load only. 2. **The chain runs over each package body** (`src/commands/migrate/meta.ts`, `applyMetaMigrationsToPackages`, used at all three chain call sites: the main run, the `--write` re-run and the empty-range probe). An option-B artifact keeps each definition only under `packages[i].manifest`, and the conversions walk a stack's own collections. So the chain now also runs over each body as a stack, and lists each body edit under the body's own path (`packages[0].manifest.objects[0].fields.starts_at.defaultValue`). `applied` keeps hop order, `todos` is the stack's own list, and `absentTodos` keeps an entry only when every run names it. A stack with no `packages` list gets the plain chain result back. 3. **`--write` traces a body edit to the input that authored it** (`src/utils/authored-source-codemod.ts`). The walk now follows `composeStacks([…])`, but only into `packages[i].manifest.KEY`, and only when every input up to i is a stack literal with a `manifest` and no `packages` of its own. Then entry i is input i's body. `KEY` is read the way composition assembles a body: from the input when it is a package-owned collection the input writes, otherwise from the input's `manifest`. Any other composed key is refused as `helper` and listed. 4. `src/utils/stack-collections.ts`: `packageOwnedCollectionKeys()` is exported, unchanged, so the codemod reads the CLI's one derivation of that key set instead of writing a second one. `main` exported it too, for the enumeration pin (PR #22321). After the merge it is one export, and one doc paragraph names both readers. 5. `test/normalized-call-sites.test.ts`: the ledger row for the renamed call site moves from `top-level` to `packages`, with the measurement named. 6. **The `--write` condition, stated where authors read it.** The changeset and the `--write` paragraph of `content/docs/upgrading.mdx` both say exactly when a package-body change is written: input i and every input before it must be a stack literal that writes its own `manifest` and no `packages`. Otherwise package i is not one input's body, and the change is listed. The docs paragraph keeps its list true: the clause that a value built by a function call is listed now reads "any other function call". The docs edit is prose only, and the seat declared it to `domain:devx`. ## Round 2: the seat's REWORK `6065347099` 1. **Merged `main`** with a merge commit, `82f398833` (parents `122ae3bd9` and `28bff18d0c`). There was no rebase and no force-push. `src/utils/stack-collections.ts` conflicted, because both sides exported `packageOwnedCollectionKeys` and each added a paragraph naming its own reader. The resolution keeps the export and writes one paragraph naming both. The `meta.ts` auto-merge (main folds `pendingDataMigrations` onto the union stack) is clean. The second enumeration `main` added to `test/normalized-call-sites.test.ts` (every top-level read of a package-owned key in `packages/cli/src`) is green over this PR's code. Its "no read is unclassified" test names nothing new, so there was nothing to classify. 2. **The changeset** states the condition above, and the code did not change. 3. **`content/docs/upgrading.mdx`**: the `--write` paragraph is edited as described in item 6. ## PM readings, measured Measured with the built CLI against temp projects that link this worktree's built `@objectstack/spec`. "Before" is `origin/main` `4e4111ca0`. - **H1, reproduced.** The composed project (every input wrapped in `defineStack`, a `time` default `'10:00Z'` in the service package) gave `--from 17 --json` exit 1 with `"code":"STACK_PROVENANCE_MISSING"` and the message `composeStacks provenance check failed (1 input): 'com.probe.svc' (stack #0) was not built by \`defineStack\`. … Wrap each input: …`. The one-package control gave exit 0 with `applied` = `[time-default-utc-suffix-dropped @ objects[0].fields.starts_at.defaultValue]`. - **H2, confirmed.** The shim hands back `authored[0]` unmarked, `composeStacks` is not wrapped, and its step 0 refuses the unmarked input. The composed project is refused **only when a body's `defineStack` refused**: the same project with `'10:00'` gave exit 0, `applied: []`, `schemaValid: true`. - **H3, measured. The plain route changes the control, so it was not taken.** Variant A, a `strict: false` fallback for every refused `defineStack` (applied to the built dist for the measurement only, then restored by md5), was run on two one-package controls at `--from 16` and `--from 17`: - c1, the refused stack: unchanged. - c2, the refused stack plus `datasources[0].driver: 'mongo'`, at `--from 16`: before, `applied` = `[datasource-driver-mongo-to-mongodb @ datasources[0].driver, time-default-utc-suffix-dropped @ objects[0]…]` and `write.files` = `[{ objectstack.config.ts, sites: 2 }]`, with the source written to `'mongodb'`. Under variant A, `applied` = `[time-default-utc-suffix-dropped]` only, `sites: 1`, and the source keeps `'mongo'`. So the one-package path keeps the raw hand-back, and the route applies only where `composeStacks` needs a marked input (change 1). Measured after the change: c1 and c2 at both majors give a `--json` summary (`applied`, `schemaValid`, the whole `write` object) and written source bytes **identical by md5** to the baseline. - **H4, confirmed, and fixed in `packages/cli`.** After change 1 alone, the composed project gave exit 0, but `applied: []` and `schemaValid: false`, with the schema refusing `packages.0.manifest.objects.0.fields.starts_at.defaultValue`. The artifact's top level held only `manifest` and `packages`. After change 2: `applied` = `[time-default-utc-suffix-dropped @ packages[0].manifest.objects[0].fields.starts_at.defaultValue]` and `schemaValid: true`. With `--write`, the authored literal is rewritten, `verification.ok` is true, and a second run applies nothing. The walker is unchanged. - **H5, holds.** A truly unwrapped input (a plain object beside a wrapped one) is still refused with `STACK_PROVENANCE_MISSING`, and the refusal names only `'com.probe.app' (stack #1)`. The refusal text is unchanged. - **Real project.** `examples/app-multi-package` (composed, preserve, valid) under `--from 17 --json` gives exit 0, `applied: []`, `schemaValid: true`. ## Pins — `test/migrate-meta-composed.test.ts`, unit tier The test runs in-process over `MigrateMeta.run` against temp projects that link the real spec. It spawns no process and boots no kernel, so it runs in `Test Core` with the rest of the CLI unit tier. 8 tests: - **The fix.** A two-file composed project (the service stack in `src/service.stack.ts`) loads, and `applied` is exactly the body site above, with `schemaValid: true`. - **`--write`.** `write.files` = `[{ src/service.stack.ts, sites: 1 }]`. The tree equals its old bytes with only that literal edited. The re-run gives `applied: []`, and a strict `loadConfig` (no shim) accepts the sources and reports `stackProvenance: true`. - **`--write` on a body it cannot trace.** For an input built by a local function, the change is listed as `helper` and every byte is left alone. - **Control.** For both one-package stacks above at `--from 16`, `applied` (conversion, path, from, to) and `write.files` equal the values measured on `4e4111ca0`, and so do the written bytes. - **Boundary.** The unwrapped input is refused with `STACK_PROVENANCE_MISSING`, naming `'com.probe.app'` and not `'com.probe.svc'`. - **Merge contracts.** With no `packages`, the result equals `applyMetaMigrations`. With bodies: copy-on-write (the input is unmutated, and an untouched body keeps its identity), `applied` equals the hops' concatenation, and each `absentTodos` is a subset of its `todos` by identity. ## Ablations Each ablation used `scripts/ablation-replace.mjs`: the anchor hit once, the mutation was proven on disk, and the restore was proven (blob equals HEAD, `git diff HEAD` empty). The suite imports `src` directly, so no dist is involved. The runs were at `fb129c3e1`, when the file had 7 tests. 1. **The raw hand-back restored on the composed path** (`__composable` returns its input). 3 red, 4 green. The two composed pins went red with the original false `STACK_PROVENANCE_MISSING`. The boundary pin also went red, because the refusal then names `'com.probe.svc'` too (2 inputs). The controls and the merge pins stayed green. Restored: blob `982786a6180d`. 2. **The body pass removed** (`applyMetaMigrationsToPackages` returns the plain result). 3 red (both composed pins and the merge pin, `applied` `[]`), 4 green. Restored: blob `e1aa2f776836`. 3. **The codemod's `composeStacks` walk disabled.** 1 red (the `--write` pin: `write.files` `[]`), 6 green. Restored: blob `359b722e7b4c`. ## Local verification at `122ae3bd9` (round 1) - **CLI unit tier** (`pnpm --filter @objectstack/cli exec vitest run --project unit`): 267 files and 3936 tests pass. `vitest list --project unit` lists `test/migrate-meta-composed.test.ts`, and `--project integration` does not. The integration tier is CI's: this diff touches no integration file and no spawn entry. - **Typecheck** (`pnpm --filter @objectstack/cli typecheck`, which is `tsc --noEmit` plus `check:test-typecheck`): exit 0. - **Gates.** `dispatch-gates.mjs --commands`, re-derived over this diff, gives the same 65 commands the order listed. All 65 exit 0, and `dispatch-gates --ran` reports 65 derived, 65 run, 0 NOT-MEASURED, 0 UNRUN. On an earlier pass with only the CLI closure built, `check:dual-build-cjs-loads` and `check:i18n-coverage` exited 3 (prerequisite not met). After a full `turbo run build` both pass: `106 published require entry point(s) across 66 package(s) load` and `13 config(s) … none new`. - **Lint** (`pnpm lint`, which is `eslint . --no-inline-config`): exit 0, no findings. ## Local verification at `db3e20d1c` (round 2, merged head) - **CLI unit tier**: 268 files and 3951 tests pass. - **CLI integration tier** (`--project integration`): 97 files pass, with 922 tests passed and 2 skipped. - **Typecheck** (`pnpm --filter @objectstack/cli typecheck`): exit 0. - **Gates.** `dispatch-gates.mjs --commands`, re-derived over the final diff, gives 95 commands: the 65 from round 1 plus 30 docs-family gates that `content/docs` adds. All 95 exit 0, after a full `turbo run build`. `dispatch-gates --ran` reports 95 derived, 95 run, 0 NOT-MEASURED, 0 UNRUN. Among them: `check:doc-authoring` ✓, `check:doc-anchors` ("466 internal #fragment link(s) … all resolve"), `check:docs-single-h1` ✓, spec `check:docs` ("225 generated files in sync") and `check:nul-bytes` OK. - **Lint** (`pnpm lint`): exit 0, no findings. ## Acceptance notes - **The route's one cost is #22256's class, now also reached on a composed project.** For a refused composed input, `strict: false` still runs the load-time D2 pass. Measured: a composed body carrying both `'10:00Z'` and `driver: 'mongo'` lists and writes the time default, while `'mongo'` is applied at load, is not listed, and is not written. That is the same as for any input the current schema accepts. #22256 remains open, and its fix will need to cover this path as well as the one-package one. The changeset states the limit. - **A body authored in map form** (`objects: { probe_slot: { … } }`) is converted and listed. `--write` lists it as `mismatch` ("an object where the loaded value is an array") and writes nothing, because `strict: false` has already normalized the body to an array. Measured. The one composed example in this repo uses array form. Carrier: none. - **`absentTodos`.** On today's registry the intersection agrees with the top-level verdict: every relevance question is `stack-declares`, which already reads `packages[]`, and the two entries that judge a conversion both ask about `agents`. No fixture separates the two, so no pin claims to. The intersection is kept because a body's own applications are visible only to that body's run. - **Manifest-level conversions.** One exists (`manifest-permissions-string-list-removed`), and it already walks `packages[].manifest`. A body run finds no `manifest` key, so nothing is applied twice. - **Not measured.** `planProtocolRange` still reads only the top-level `manifest`'s declared range. Whether a package body's own declared range needs the same rewrite was not measured here. - **File surface.** `src/utils/stack-collections.ts`, `test/normalized-call-sites.test.ts` and the one `content/docs/upgrading.mdx` paragraph were added to the claim's file surface at review. Nothing else moves. - **Docs.** The `--write` paragraph of `content/docs/upgrading.mdx` would have gone false with this change, so it is edited here (round 2, prose only). The seat declared the edit to `domain:devx`. - **The docs-drift advisory** (comment `6065243708`) lists 18 hand-written pages; its list is omitted above 15 rows. I re-derived it on this tree with `node scripts/docs-audit/affected-docs.mjs --json 28bff18`, which gave the same 18 pages plus 9 release-owned ones. I read each page for a statement about `--write` tracing, `STACK_PROVENANCE_MISSING` or the authored-source load. Only the `upgrading.mdx` paragraph above goes false, and it is edited here. `deployment/cli.mdx` line 1433 ("writes the ones it can trace to one literal") and line 1896 (`os validate`'s provenance refusal) stay true. Written by session `session_01RWZbGvPFcRKvUqASZtunCU`, rounds 1 and 2; body refreshed 2026-10-08T18:14Z. --------- Co-authored-by: Claude <noreply@anthropic.com>
1 parent 2f70c22 commit 59fb299

8 files changed

Lines changed: 687 additions & 18 deletions

File tree

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
---
2+
'@objectstack/cli': patch
3+
---
4+
5+
fix(cli): `os migrate meta` runs on a project built with `composeStacks`, and converts the retired spellings inside its package bodies (#22289)
6+
7+
Clause-②: no
8+
9+
- **What changed.** On a project whose config exports `composeStacks([defineStack({ … }), …], { manifest: 'preserve' })`, `os migrate meta --from N` used to exit 1 with `STACK_PROVENANCE_MISSING`, telling the author to wrap each input in `defineStack`, as soon as any input carried a spelling the current schema refuses. Every input already was wrapped. The command now loads such a project: an input whose `defineStack` call the current schema refuses is handed to `composeStacks` as `defineStack(input, { strict: false })` returns it, and composition runs as it does at build time.
10+
- **The package bodies are migrated.** A composed artifact keeps each definition under the package that owns it (`packages[i].manifest`), and the migration chain used to reach only the stack's own top level. It now also runs over each package body, and lists each change under the body's path, such as `packages[0].manifest.objects[0].fields.starts_at.defaultValue`. `--write` writes a change in package i into the file that authored input i only when input i and every input before it in the `composeStacks([…])` list is a stack literal (a `defineStack({ … })` call on an object literal, written in place or reached through a `const` or an import) that writes its own `manifest` and no `packages`. Only then is package i that one input's body. Otherwise `--write` lists the change with the reason, as it does for any site it cannot trace.
11+
- **What did not change.** A one-package project loads, migrates and writes exactly as before. An input that was never built by `defineStack` (a plain object, or a spread of a built stack) is still refused with `STACK_PROVENANCE_MISSING`.
12+
- **Known limit.** Inside a composed project, a conversion the load still applies (for example `datasources[].driver: 'mongo'`) is applied while the input is composed. So the chain does not list it and `--write` does not write it, the same as for an input the current schema accepts.

‎content/docs/upgrading.mdx‎

Lines changed: 9 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -237,11 +237,15 @@ against, never as the file you ship.
237237
it can prove the site.** A change is written when it traces to one object or
238238
array literal in one project file: through `define*` calls and `.create`
239239
factories, `const` bindings, relative imports and re-exports, and
240-
`Object.values()` over a namespace import. Only that site's bytes change; a
241-
renamed key keeps its value and its comments. Every other change — a value
242-
built by a function call or an expression, a key a spread supplies, a binding
243-
something else also uses, a file in a package — is listed with the reason it was
244-
not written, for you to port by hand. The command then re-runs the chain over
240+
`Object.values()` over a namespace import. A change inside a package body of a
241+
`composeStacks([…])` project (a path under `packages[i].manifest`) traces into
242+
input i, but only when input i and every input before it is a stack literal
243+
that writes its own `manifest` and no `packages`: only then is package i that
244+
one input's body. Only that site's bytes change; a renamed key keeps its value
245+
and its comments. Every other change — a value built by any other function call
246+
or an expression, a key a spread supplies, a binding something else also uses,
247+
a file in a package — is listed with the reason it was not written, for you to
248+
port by hand. The command then re-runs the chain over
245249
the written files and restores them all unless it comes back with exactly the
246250
changes it left. Commit first, and review the diff like any other change.
247251
</Callout>

‎packages/cli/src/commands/migrate/meta.ts‎

Lines changed: 108 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,9 @@ import {
1212
MigrationFloorError,
1313
MIGRATION_MAJORS,
1414
MIGRATION_SUPPORT_FLOOR,
15+
type MigrationApplication,
1516
type MigrationChainResult,
17+
type MigrationHopResult,
1618
type MigrationTodo,
1719
} from '@objectstack/spec/migrations';
1820
import { PROTOCOL_MAJOR, PROTOCOL_VERSION } from '@objectstack/spec/kernel';
@@ -103,6 +105,109 @@ const VALUE_SHAPE_GATE_MAJOR = 17;
103105
*/
104106
const CHAIN_TERMINUS_MAJOR = Math.max(PROTOCOL_MAJOR, ...MIGRATION_MAJORS);
105107

108+
const isRecord = (value: unknown): value is Record<string, unknown> =>
109+
value !== null && typeof value === 'object' && !Array.isArray(value);
110+
111+
/**
112+
* The migration chain over a stack AND each package body it carries — what
113+
* `applyMetaMigrations` is for this command, at every call site.
114+
*
115+
* ## Why the bodies need their own run
116+
*
117+
* The conversions walk a stack's own collections (`objects[]`, `views[]`,
118+
* `pages[]`, …) and do not descend into `packages[]`. A multi-package
119+
* artifact built by `composeStacks(…, { manifest: 'preserve' })` carries each
120+
* definition ONCE, under the package that owns it (ADR-0130 D4 addendum): its
121+
* top level holds `manifest` and `packages` and no flattened copy. So a
122+
* retired spelling inside a package was reached by no conversion — `applied`
123+
* came back empty and the schema verdict refused the very spelling the chain
124+
* exists to convert.
125+
*
126+
* A body (`packages[i].manifest`) is a stack-shaped bag — manifest fields and
127+
* collections side by side — so the chain runs over each body as a stack, and
128+
* each of its applications is listed under the body's own path
129+
* (`packages[0].manifest.objects[0]…`), which names the package and is the
130+
* path `--write` traces to the input that authored it. A conversion whose
131+
* reach already includes `packages[].manifest` (the manifest's permission
132+
* list) runs in the stack's own run and finds no `manifest` key in a body,
133+
* so nothing is applied twice.
134+
*
135+
* ## The merged result
136+
*
137+
* - `applied` keeps application order hop by hop: the stack's own edits of a
138+
* hop, then each body's, in package order.
139+
* - `todos` is the stack's own list — every semantic entry of every hop
140+
* crossed is in it whatever the stack holds, so a body's run lists the same
141+
* entries again.
142+
* - `absentTodos` keeps an entry only when every run names it — the stack's
143+
* own and each body's — matched by hop and id. The relevance question
144+
* already reads `packages[]` itself; what a body's run adds is its own
145+
* applications, and an entry that judges a conversion which applied an
146+
* edit is never named absent.
147+
* - A stack without a `packages` list, which is every one-package project,
148+
* gets the plain chain result back unchanged.
149+
*/
150+
export function applyMetaMigrationsToPackages(
151+
stack: Record<string, unknown>,
152+
fromMajor: number,
153+
toMajor: number,
154+
): MigrationChainResult {
155+
const own = applyMetaMigrations(stack, fromMajor, toMajor);
156+
const entries = own.stack.packages;
157+
if (!Array.isArray(entries)) return own;
158+
159+
const bodies: Array<{ index: number; prefix: string; run: MigrationChainResult }> = [];
160+
for (const [index, entry] of entries.entries()) {
161+
if (!isRecord(entry) || !isRecord(entry.manifest)) continue;
162+
bodies.push({
163+
index,
164+
prefix: `packages[${index}].manifest`,
165+
run: applyMetaMigrations(entry.manifest, fromMajor, toMajor),
166+
});
167+
}
168+
if (bodies.length === 0) return own;
169+
170+
const located = (prefix: string) => (application: MigrationApplication): MigrationApplication => ({
171+
...application,
172+
path: application.path ? `${prefix}.${application.path}` : prefix,
173+
});
174+
const todoKey = (todo: MigrationTodo) => `${todo.toMajor}:${todo.id}`;
175+
const absentEverywhere = (absent: readonly MigrationTodo[], bodyAbsent: (run: MigrationChainResult) => readonly MigrationTodo[]) => {
176+
const bodySets = bodies.map(({ run }) => new Set(bodyAbsent(run).map(todoKey)));
177+
return absent.filter((todo) => bodySets.every((set) => set.has(todoKey(todo))));
178+
};
179+
/** `base` with each body replaced by its stack from `pick`, copied only where one changed. */
180+
const withBodies = (base: Record<string, unknown>, pick: (run: MigrationChainResult) => Record<string, unknown>) => {
181+
const list = base.packages;
182+
if (!Array.isArray(list)) return base;
183+
let changed = false;
184+
const next = list.slice();
185+
for (const { index, run } of bodies) {
186+
const entry = next[index];
187+
const body = pick(run);
188+
if (!isRecord(entry) || entry.manifest === body) continue;
189+
next[index] = { ...entry, manifest: body };
190+
changed = true;
191+
}
192+
return changed ? { ...base, packages: next } : base;
193+
};
194+
195+
const hops: MigrationHopResult[] = own.hops.map((hop, k) => ({
196+
...hop,
197+
stack: withBodies(hop.stack, (run) => run.hops[k]!.stack),
198+
applied: [...hop.applied, ...bodies.flatMap(({ prefix, run }) => run.hops[k]!.applied.map(located(prefix)))],
199+
absentTodos: absentEverywhere(hop.absentTodos, (run) => run.hops[k]!.absentTodos),
200+
}));
201+
202+
return {
203+
...own,
204+
stack: withBodies(own.stack, (run) => run.stack),
205+
applied: hops.flatMap((hop) => hop.applied),
206+
absentTodos: absentEverywhere(own.absentTodos, (run) => run.absentTodos),
207+
hops,
208+
};
209+
}
210+
106211
/** Flags that mean something only in `--stored` mode (#4327). */
107212
const STORED_ONLY_FLAGS = ['apply', 'yes', 'force', 'type', 'database-url'] as const;
108213

@@ -222,7 +327,7 @@ function printEmptyRangeAnswer(
222327
return;
223328
}
224329

225-
const wider = applyMetaMigrations(stack, fromMajor, CHAIN_TERMINUS_MAJOR);
330+
const wider = applyMetaMigrationsToPackages(stack, fromMajor, CHAIN_TERMINUS_MAJOR);
226331
const widerListed = listedTodos(wider.todos, wider.absentTodos);
227332
if (wider.applied.length === 0 && widerListed.length === 0) {
228333
printInfo(
@@ -1060,7 +1165,7 @@ export default class MigrateMeta extends Command {
10601165
const normalized = normalizeStackInput(config as Record<string, unknown>, { convert: false });
10611166

10621167
if (!flags.json) printStep(`Replaying chain: protocol ${fromMajor} → ${toMajor}…`);
1063-
const result = applyMetaMigrations(normalized, fromMajor, toMajor);
1168+
const result = applyMetaMigrationsToPackages(normalized, fromMajor, toMajor);
10641169

10651170
// Prove the migrated stack is schema-valid — the "generated, provably valid
10661171
// diff" the consumer agent reviews (ADR-0087 D3/D5).
@@ -1237,7 +1342,7 @@ export default class MigrateMeta extends Command {
12371342
try {
12381343
const reloaded = await loadConfig(input.configArg, { authoredSource: true });
12391344
const rerunInput = normalizeStackInput(reloaded.config as Record<string, unknown>, { convert: false });
1240-
const rerun = applyMetaMigrations(rerunInput, result.fromMajor, result.toMajor);
1345+
const rerun = applyMetaMigrationsToPackages(rerunInput, result.fromMajor, result.toMajor);
12411346
// The range the written sources still owe, judged as it was before the write.
12421347
const rerunRange = planProtocolRange(rerunInput, result.fromMajor, result.toMajor);
12431348
verification = verifyAuthoredSourceWrite(

0 commit comments

Comments
 (0)