Skip to content
15 changes: 15 additions & 0 deletions .changeset/9591-migrate-meta-write.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
---
"@objectstack/cli": minor
---

`os migrate meta --write` writes the chain's mechanical changes into the authored source files, in place, at every site it can prove

Clause-②: yes (widening)

- A new flag on the authored-source mode: `os migrate meta --from N --write`. Without it nothing changes: the dry run, its report and its `--json` payload are what they were, and `--out` still writes its snapshot.
- What it writes: each mechanical change the chain applied (`applied`), at a site it traces to one object or array literal in one project file — through `define*` calls and the `.create(…)` factories `@objectstack/spec` exports, module-level `const` bindings, relative imports and re-exports, and `Object.values()` over a namespace import — when the loaded value matches that literal and nothing else references the bindings on the way. Only that site's bytes change: a renamed key keeps its value and its comments, a removed key takes its own line(s), and every other byte (comments, formatting, key order) stays as it was.
- What it refuses, each change listed with the reason (`--json`: `write.manual[].kind`): `computed`, `helper`, `spread`, `shared`, `outside-project`, `mismatch`, `injected`, `unspellable`, `layout` and `unattributed`; and `entangled`, because a conversion's edits are written whole or not at all.
- What it never writes: the semantic changes (`todos`), which stay listed exactly as before, and a site a conversion declines, for which no mechanical change exists.
- After writing it re-runs the chain over the written sources. Unless the re-run applies exactly the changes it left, it restores every file it wrote and exits 1.
- `--json` gains a `write` key, only with `--write`: `status`, `files`, `written`, `manual`, `unexplained` and `verification`.
- `--write` is exclusive with `--stored`; `--stored --apply` is unchanged.
3 changes: 2 additions & 1 deletion content/docs/deployment/cli.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -1430,7 +1430,8 @@ an old dialect this pass can convert exits `1`. So "my metadata is on protocol N
becomes a check rather than a belief.

Note the division of labour with the default mode: `os migrate meta --from N`
lists the edits **an author's source** needs and reads no database; `--stored`
lists the edits **an author's source** needs — with `--write`, it also writes the
ones it can trace to one literal into the source files — and reads no database; `--stored`
rewrites **one deployment's rows** and reads no config. Same chain, opposite
ends of the contract — which is why the two modes are mutually exclusive.

Expand Down
27 changes: 20 additions & 7 deletions content/docs/upgrading.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -215,7 +215,8 @@ Useful flags:
| Flag | What it does |
| :--- | :--- |
| `--step` | Report each major's hop separately, so a failure bisects to the exact major |
| `--out migrated.stack.json` | Also write the migrated stack as a JSON snapshot — the only file the command writes |
| `--out migrated.stack.json` | Also write the migrated stack as a JSON snapshot |
| `--write` | Write the mechanical changes into your source files, where each can be traced to one literal; list the rest with the reason (see below) |
| `--to 17` | Stop at an intermediate major instead of this runtime's |
| `--json` | Machine-readable output, for CI or an agent |

Expand All @@ -226,11 +227,22 @@ stored metadata rows and reads no config. The two are mutually exclusive.)
### What it does not do — read the output

<Callout type="warn">
**`os migrate meta` does not rewrite your source files.** It replays the chain
over the loaded stack *in memory* and reports the diff; the only file it writes
is `--out`, a JSON snapshot. Porting the listed edits into your own `.ts`
sources is your work — use `--out` as the oracle you diff against, never as the
file you ship.
**Without `--write`, `os migrate meta` does not rewrite your source files.** It
replays the chain over the loaded stack *in memory* and reports the diff; the
only file it writes is `--out`, a JSON snapshot — use it as the oracle you diff
against, never as the file you ship.

**`--write` writes the mechanical changes into your `.ts` sources — only where
it can prove the site.** A change is written when it traces to one object or
array literal in one project file: through `define*` calls and `.create`
factories, `const` bindings, relative imports and re-exports, and
`Object.values()` over a namespace import. Only that site's bytes change; a
renamed key keeps its value and its comments. Every other change — a value
built by a function call or an expression, a key a spread supplies, a binding
something else also uses, a file in a package — is listed with the reason it was
not written, for you to port by hand. The command then re-runs the chain over
the written files and restores them all unless it comes back with exactly the
changes it left. Commit first, and review the diff like any other change.
</Callout>

<Callout type="warn">
Expand Down Expand Up @@ -274,7 +286,8 @@ has already done.

```bash
os migrate meta --from 16 # 1. read the mechanical change list and the to-dos
# 2. apply the edits by hand; resolve the to-dos
# 2. apply the edits (--write writes the ones it can
# trace and lists the rest); resolve the to-dos
# and the checklist items below
os validate # 3. the gate — schema, CEL predicates, widget bindings
os build # 4. compile to dist/objectstack.json
Expand Down
Loading
Loading