Skip to content

[finding][devx] cli.doctor-deprecation-scan calls os migrate meta "the codemod that actually exists" — it is a chain replayer that prints edits and writes no source #10418

Description

@os-zhuang

Found while rewriting the sibling item cli.migrate-meta-codemod for #9733 (PR #10412). Filed unassigned; deliberately not fixed in that PR — see the scope note below.

The finding

docs/qa/platform-checklist/areas/cli.json, item cli.doctor-deprecation-scan (added 2026-08-20, revision 1, P2), describes os migrate meta twice as a codemod:

  • in an acceptance clause: "The real metadata codemod is os migrate meta (cli.migrate-meta-codemod)"
  • in source: "sibling items … and cli.migrate-meta-codemod (the codemod that actually exists)"

os migrate meta is not a codemod. It declares exactly from · to · step · out · stored · database-url · apply · yes · force · type · json — no --write/--fix/in-place flag — and on the authored-source arm its only file write is the --out JSON snapshot (both writeFileSync calls are if (flags.out)-guarded). packages/cli/src/commands/migrate/meta.ts states it in its own header:

The command does not silently rewrite TS config source (that AST rewrite is unsafe and lossy); --out writes the canonicalized stack as a JSON snapshot

The in-place AST codemod is commissioned as #9591 for v18 and has not been built.

Why this is worth a card rather than a typo fix

The load-bearing assertion of that item is unaffected and correct: os doctor's remediation hint prescribes objectstack codemod v2-to-v3, which is registered nowhere, and the item records that as an expected-fail. The contrast it draws — unlike that command, os migrate meta is real — is also true. Only the word "codemod" is wrong.

It matters because PR #10412 rewrites the sibling item's title to say os migrate meta "rewrites no source file". Once that lands, the same file asserts both things, and a reader hitting the cli.doctor-deprecation-scan clause first gets the same wrong idea the #9733 card exists to remove — that there is a working metadata codemod to be pointed at.

Why #10412 did not fix it in passing

It fails the bounded in-place exemption on two of the four conditions:

  1. Not the same defect class. The QA checklist item cli.migrate-meta-codemod is active P1 for a capability that does not exist — it asserts os migrate meta rewrites authored sources #9733 residue is an active P1 whose title and acceptance clauses assert a capability that does not exist. This is a loose descriptor in another item's parenthetical, where the surrounding assertion is true.
  2. The correct form is not mechanically pinned. Replacing "codemod" means choosing how that item wants to characterise os migrate meta — a framing call belonging to that item's author, not a substitution fixed by evidence.

It also needs its own revision bump and history entry (README lifecycle), in an item one day old.

Suggested dispositions (triage's call)

  • A — reword both descriptors to what the command is (e.g. "the metadata migration command that does exist, os migrate meta — which lists mechanical edits rather than applying them"), bump cli.doctor-deprecation-scan to revision 2 with a history entry. Keeps the contrast the clause is drawing while dropping the false noun.
  • B — leave it. The item's own verdict does not depend on the word, and the sibling item now states the contract precisely. Costs nothing, and leaves the contradiction inside one file for the next reader to re-derive.

Refs: docs/qa/platform-checklist/areas/cli.json (cli.doctor-deprecation-scan) · packages/cli/src/commands/migrate/meta.ts · #9591 (the v18 codemod, pm:on-hold) · #9733 / #10412 (where this surfaced).


Generated by Claude Code

Metadata

Metadata

Assignees

No one assigned

    Type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions