Skip to content

os migrate meta never rewrites the authored sources that 144 shipped retirement messages promise it will #9529

Description

@os-zhuang

Found while implementing #9418 (the load-refusal half). Filed unassigned for triage — deliberately out of that card's scope and not fixed there.

Blocked-by: #9418 — a source rewriter cannot be built on a load path that refuses to open those sources. That half has landed; this one is downstream of it and was pre-existing.

The gap

Every retiredKey() prescription whose surface an ADR-0087 conversion covers closes with a sentence whose wording is maintainer-ruled (2026-08-09, #6856) and pinned class-wide by packages/spec/src/shared/retired-key-migrate-sentence.test.ts:

Run os migrate meta --from N to rewrite existing sources automatically.

The rule that fixed that wording is explicit about what the sentence claims — quoting packages/spec/src/shared/retired-key.ts:

The sentence states a property of the TOOL — it rewrites your source files — never the fate of the key.

It ships 144 times across 39 files under packages/spec/src.

The command does not rewrite source files. Measured on origin/main @ 6ce8feb72, packages/cli/src/commands/migrate/meta.ts writes in exactly two places, both guarded by --out, both writing the same artifact:

347: if (flags.out) writeFileSync(resolve(flags.out), JSON.stringify(result.stack, null, 2));
395: writeFileSync(resolve(flags.out), JSON.stringify(result.stack, null, 2));

That is a JSON snapshot of the migrated stack at a path the operator names, and the flag's own description says exactly that: Write the migrated stack as a JSON snapshot to this path. There is no --write / --fix / in-place flag; objectstack.config.ts and the per-artifact modules under src/ are never touched. os lint --fix is not the missing half either — its own description reads Show what would be fixed (dry-run).

So an author who follows the prescription gets the chain replayed, a printed diff, and optionally a JSON document — and then still edits every .ts file by hand. For a project that authors metadata across per-artifact modules (defineView / defineAgent / defineFlow — the shape the example apps use), the JSON snapshot is not even in the shape the sources are written in.

Reproduction

With #9418's fix in place, in a project whose config carries a retired key:

os migrate meta --from 16 --out migrated.json
# exit 0, "Applied 2 mechanical change(s)", migrated.json written
git status # objectstack.config.ts: unmodified

The two honest resolutions — triage's call, not the finder's

  1. Implement the promise. An in-place rewrite of authored TypeScript means an AST codemod; ts-morph is already a packages/cli dependency. The chain's semantic TODOs must stay manual either way, so the rewrite covers the mechanical applied set only.
  2. Reword the promise. 144 messages across 39 files, plus the class-wide pin and the maintainer ruling that produced the current wording. Cheaper, but it withdraws the automatic-fix claim from the v17 upgrade path — which is the claim that makes the retirement audible.

Option 2 edits a maintainer-ruled sentence, so neither option is an implementer's scope call.

Metadata

Metadata

Assignees

Type

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions