Repository navigation
Commit 3b47a69
fix(cli): os migrate meta leads with the verdict and the refusals, then the applied edits, then the semantic notices (#20691)
Part of #20620
Clause-②: no
Direction 1 of the card's triage (order). Direction 2 (pairing an
applied conversion with the semantic entry that judges it) needs a
structured link on `SemanticMigration` in `packages/spec`, so it stays
on the card. Direction 3 (write-back) is out, per triage.
## What changed
`os migrate meta --from N` (the authored-source report, human output
only) now prints three groups, in the order an upgrader acts on them.
Each group opens with one header line that counts it:
1. **The verdict and the refusals.** Either `✓ Migrated stack is
schema-valid (Nms)`, or `⚠ Migrated stack does not yet pass schema
validation — N refusals left after the chain. Resolve them, then run `os
validate`:` followed by one `✗ path: message` line per issue of the
migrated stack's parse. The lines are rendered by `formatZodIssue`, the
same renderer behind the loader's `defineX() validation failed` block.
2. **`Applied N mechanical change(s):`**, unchanged.
3. **`N manual change(s) require your judgment:`**, unchanged.
The human branch of `run()` is now one exported function,
`printMigrationReport`, so the order can be pinned in process. `--step`
checkpoints stay between groups 2 and 3, and the `--out` line and the
data-migration advice stay after group 3. A range that holds no step
also leads with the verdict, which now lists the source's refusals, and
the range note follows it.
**Unchanged:**
- Every applied-edit line and every semantic-notice line, byte for byte
and in chain order. No notice is dropped, filtered, merged or reworded
(ADR-0087 D3, "never silence").
- `--json`: same keys in the same order, same values, same array order.
- Exit codes. A schema-invalid run still exits 0.
- The loader's stderr output.
`--json`'s `applied` and `todos` arrays are in chain order, and a
consumer could rely on that order. It is left as it is.
## Measurements
Each "before" run used the `bin/run.js` of a worktree at `6981abfd26`
(this branch's base). Each "after" run used the build of `7c484d891f`.
Both runs used the same `@objectstack/spec` (`6981abfd26`). The merge of
`main` since then does not touch `packages/cli`. Stacks:
- `examples/app-crm` at `6981abfd26`;
- **h1**, a scratch `defineStack` config: two currency fields carrying
`scale` (refused, no conversion), two `dashboard.refreshInterval`, two
`action.aria`, and a two-branch flow decision with no `mode`;
- **dm**, a scratch config with an image and a location field and one
`refreshInterval`, run `--from 16` so the data-migration advice prints.
stdout line where each group starts:
| run | before: applied / semantic / verdict | after: verdict / applied
/ semantic |
|:--|:--|:--|
| h1 `--from 17` (5 applied, 242 notices, 2 refusals left) | 9 / 16 /
**780 (last line)** | **9** (+2 refusal lines) / 13 / 20 |
| app-crm `--from 17` (0 applied, 242 notices, valid) | none / 9 /
**773** | **9** / none / 11 |
| dm `--from 16` (1 applied, 319 notices, valid) | 9 / 12 / **1044**,
after the data-migration advice | **9** / 11 / 14, with the advice last
|
- **H0 (the refusals print after the catalogue): partly false.** The
verdict was the last line. The printer never listed a refusal. The only
refusal list was the loader's `[authored-source] defineStack()` warning
on stderr, printed during load, before any chain output. That list
describes the stack as authored: 6 issues on h1, 4 of which the chain
goes on to convert. The 2 refusals that remain after the chain were
printed nowhere.
- **H1: holds, with one addition by design.** The order is verdict and
refusals, then applied edits, then notices, with one header line per
group. Applied-edit lines match in number and in order: 5=5 (h1), 0=0
(crm), 1=1 (dm). Notice lines match in number and in order: 744=744,
744=744, 996=996. The preamble lines are equal. The same holds for
`--step` and `--out`, with the snapshot path normalised. The only lines
added are the refusal list: 2 on h1, 0 on the valid stacks. That is the
content direction 1 asks for, and the printer had none of it before. The
only lines reworded are the two schema-invalid verdict sentences: the
old one pointed at "the manual changes above", which are now below.
- **H2: holds.** The exit code was 0 before and after in all 11
invocations. `--json` is identical once `duration` is removed, in the
same key order (h1, h1 empty range, crm, dm). The `--out` snapshot is
byte-identical. stderr is byte-identical in every run.
- **H3 (ablation): holds.** The mutation restores the old order and
nothing else: the body runs first, the verdict prints last. It went
through `scripts/ablation-replace.mjs` (anchor 1 → 0, blob `1a002a9b` →
`d80c2332`) under a trap-guarded restore. Result: exactly the 3 ORDER
pins red, e.g. `the verdict is the first line the report prints:
expected 1030 to be +0`. The header-count pin and the 4 SET pins stayed
green. Restore proven: blob `1a002a9b` equals the `HEAD` blob, `git diff
HEAD` is empty, and the marker count is 0. The subject is `./meta.js`,
resolved to `src` by vitest (a relative import), so no `dist` was
involved.
## Verification
At `8304fb9e13` (final head: `main` merged in, then `pnpm install
--frozen-lockfile` and the CLI closure rebuilt):
- `pnpm --filter @objectstack/cli typecheck`: exit 0. The new test is in
the `tsc --noEmit` program (`--listFiles` count 1).
- `pnpm --filter @objectstack/cli exec vitest run --project unit
--maxWorkers=2`: 233 files passed, 2 failed (5 tests). The 2 are
`test/published-subpath-console.pin.test.ts` and
`test/published-subpath-hook-body.pin.test.ts`. They fail the same way
on a clean `6981abfd26` worktree: a macOS `/var` vs `/private/var`
realpath difference. See the acceptance notes.
- `node scripts/pm/dispatch-gates.mjs --repo objectstack-ai/objectstack
--ran` over the 62 derived commands, each with its exit code: 62 run,
all exit 0, 0 NOT-MEASURED. `check:dual-build-cjs-loads` and
`check:i18n-coverage` first answered `PREREQUISITE NOT MET` (exit 3).
They were re-run after a full `turbo run build` and exited 0.
- The artifact-roster rows that could apply, all exit 0:
- `check-changeset-fixed`, `check:authz-resolver`,
`check:error-code-casing` and `check:filter-alias-parity` (all marked
⛔);
- `release-pending-publish --self-test`, `check:cli-examples-parity` and
`check-platform-checklist-watchdog`;
- `check-published-list-mirrors` and `check:commit-card-trailers`.
- Three PR-context gates exit 2 without a PR payload and are NOT
MEASURED locally: `check-single-claim-paths`,
`check-partof-closing-keyword` and `check-closing-target-claim`.
- `pnpm lint` (the full `eslint .`): exit 0. Both touched files are
linted, with 0 errors and 0 warnings (`--format json`).
- `node scripts/check-issue-citations.mjs --base origin/main`: exit 0, 3
citations resolve.
At `7c484d891f` (before the merge, same `packages/cli`):
- The two queue-tier spawned tests that quote this printer's text,
`test/migrate-meta-default-range.test.ts` and
`test/migrate-meta-engine-guidance.test.ts` (`--project integration`):
10 passed, 1 skipped (a registry-selected skip, by design).
- `test/migrate-meta.e2e.test.ts` (nightly tier): 19 passed.
**Declared narrowing — verification ran UNLOCKED.**
`scripts/pm/os-verify-lock.sh`
could not take the shared verify lock on this host: no usable `flock`.
The shared
verify lock is declared Linux-only (`flock` is util-linux, and a stock
macOS does
not ship it), so the command below was run directly, without the lock —
a declared narrowing, not a silent one. No serialization guarantee held
for this
run, nor for any sibling agent in this container while it ran.
pnpm exec turbo run build --filter='@objectstack/cli...' --concurrency=2
pnpm exec turbo run build --filter='!@objectstack/docs' --concurrency=2
pnpm --filter @objectstack/cli build
pnpm --filter @objectstack/cli typecheck
pnpm --filter @objectstack/cli exec vitest run --project unit
--maxWorkers=2
pnpm --filter @objectstack/cli exec vitest run --project integration
--maxWorkers=2 test/migrate-meta-default-range.test.ts
test/migrate-meta-engine-guidance.test.ts
pnpm --filter @objectstack/cli exec vitest run --project integration
--maxWorkers=2 test/migrate-meta.e2e.test.ts
pnpm lint
## Acceptance notes
- **The refusal group is new content, and the only content this PR
adds.** The printer never had the migrated stack's refusals. The only
list was the loader's, of the authored stack, on stderr. That loader
warning is unchanged and still prints first during load. On h1 it names
6 issues, and the report's group names the 2 left after the chain. The
two counts measure different stacks.
- **A published checklist step now quotes a stale sentence.**
`docs/qa/platform-checklist/areas/cli.json`, item
`cli.migrate-meta-codemod` (revision 3), quotes the old invalid-verdict
sentence verbatim ("resolve the manual changes above"). Its acceptance
clause (the verdict agrees with `schemaValid`) still holds. The quoted
step is now stale. It is not edited here: it needs a revision bump and a
history entry by the checklist's author.
- **The upgrade skill lists the groups in the old order.**
`skills/objectstack-upgrade/SKILL.md` lists the printed groups as
applied, manual, verdict. It claims no order, and every string it quotes
is still printed. It is a governed surface, not edited here.
- **`pnpm check:platform-checklist` is red on `main`.** The failure is
`areas/identity-auth.json: ABSENT SYMBOL … auth-plugin.ts#twoFactor`,
red on `6981abfd26` as well. The gate is maintainer-run and deliberately
out of per-PR CI.
- **Two published-subpath pins are red on macOS only.**
`published-subpath-console.pin.test.ts` and
`published-subpath-hook-body.pin.test.ts` compare a `/var/folders/…`
path with its `/private/var/folders/…` realpath. They are red on a clean
base worktree too, so the failure comes from the host, not from this
diff.
- **Reported for the seat to file (class a): `os migrate meta` cannot
open an object built with `ObjectSchema.create` that carries a retired
key.** The load-time tolerance wraps only the `define*` exports, and
`ObjectSchema.create(` is used 35 times across `examples/`, as well as
by HotCRM.
- Repro: one object, `ObjectSchema.create({ …, tenancy: { enabled: true,
organizationField: 'organization_id' } })` inside `defineStack`.
- Result: `os migrate meta --from 17` exits 1 at load with the raw
ZodError array. The array's own message prescribes "Run `os migrate meta
--from 17` …".
- Control: the same object as a plain literal loads,
`object-tenancy-organization-field-removed` applies, and `schemaValid`
is true.
- **Exit code 0 on a schema-invalid run is unchanged**, as
`test/migrate-meta-default-range.test.ts` records.
---
_Generated by [Claude
Code](https://claude.ai/code/session_local_1d2a197c-c20e-4e90-9be8-413d4d432289)_
---------
Co-authored-by: Jack Zhuang <50353452+hotlong@users.noreply.github.com>
Co-authored-by: Claude <noreply@anthropic.com>1 parent 0be8984 commit 3b47a69
3 files changed
Lines changed: 462 additions & 78 deletions
File tree
- .changeset
- packages/cli/src/commands/migrate
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
| 1 | + | |
| 2 | + | |
| 3 | + | |
| 4 | + | |
| 5 | + | |
| 6 | + | |
| 7 | + | |
| 8 | + | |
| 9 | + | |
| 10 | + | |
| 11 | + | |
| 12 | + | |
| 13 | + | |
| 14 | + | |
| 15 | + | |
| 16 | + | |
| 17 | + | |
| 18 | + | |
| 19 | + | |
| 20 | + | |
| 21 | + | |
| 22 | + | |
| 23 | + | |
| 24 | + | |
| 25 | + | |
| 26 | + | |
| 27 | + | |
| 28 | + | |
| 29 | + | |
| 30 | + | |
| 31 | + | |
| 32 | + | |
| 33 | + | |
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
| 1 | + | |
| 2 | + | |
| 3 | + | |
| 4 | + | |
| 5 | + | |
| 6 | + | |
| 7 | + | |
| 8 | + | |
| 9 | + | |
| 10 | + | |
| 11 | + | |
| 12 | + | |
| 13 | + | |
| 14 | + | |
| 15 | + | |
| 16 | + | |
| 17 | + | |
| 18 | + | |
| 19 | + | |
| 20 | + | |
| 21 | + | |
| 22 | + | |
| 23 | + | |
| 24 | + | |
| 25 | + | |
| 26 | + | |
| 27 | + | |
| 28 | + | |
| 29 | + | |
| 30 | + | |
| 31 | + | |
| 32 | + | |
| 33 | + | |
| 34 | + | |
| 35 | + | |
| 36 | + | |
| 37 | + | |
| 38 | + | |
| 39 | + | |
| 40 | + | |
| 41 | + | |
| 42 | + | |
| 43 | + | |
| 44 | + | |
| 45 | + | |
| 46 | + | |
| 47 | + | |
| 48 | + | |
| 49 | + | |
| 50 | + | |
| 51 | + | |
| 52 | + | |
| 53 | + | |
| 54 | + | |
| 55 | + | |
| 56 | + | |
| 57 | + | |
| 58 | + | |
| 59 | + | |
| 60 | + | |
| 61 | + | |
| 62 | + | |
| 63 | + | |
| 64 | + | |
| 65 | + | |
| 66 | + | |
| 67 | + | |
| 68 | + | |
| 69 | + | |
| 70 | + | |
| 71 | + | |
| 72 | + | |
| 73 | + | |
| 74 | + | |
| 75 | + | |
| 76 | + | |
| 77 | + | |
| 78 | + | |
| 79 | + | |
| 80 | + | |
| 81 | + | |
| 82 | + | |
| 83 | + | |
| 84 | + | |
| 85 | + | |
| 86 | + | |
| 87 | + | |
| 88 | + | |
| 89 | + | |
| 90 | + | |
| 91 | + | |
| 92 | + | |
| 93 | + | |
| 94 | + | |
| 95 | + | |
| 96 | + | |
| 97 | + | |
| 98 | + | |
| 99 | + | |
| 100 | + | |
| 101 | + | |
| 102 | + | |
| 103 | + | |
| 104 | + | |
| 105 | + | |
| 106 | + | |
| 107 | + | |
| 108 | + | |
| 109 | + | |
| 110 | + | |
| 111 | + | |
| 112 | + | |
| 113 | + | |
| 114 | + | |
| 115 | + | |
| 116 | + | |
| 117 | + | |
| 118 | + | |
| 119 | + | |
| 120 | + | |
| 121 | + | |
| 122 | + | |
| 123 | + | |
| 124 | + | |
| 125 | + | |
| 126 | + | |
| 127 | + | |
| 128 | + | |
| 129 | + | |
| 130 | + | |
| 131 | + | |
| 132 | + | |
| 133 | + | |
| 134 | + | |
| 135 | + | |
| 136 | + | |
| 137 | + | |
| 138 | + | |
| 139 | + | |
| 140 | + | |
| 141 | + | |
| 142 | + | |
| 143 | + | |
| 144 | + | |
| 145 | + | |
| 146 | + | |
| 147 | + | |
| 148 | + | |
| 149 | + | |
| 150 | + | |
| 151 | + | |
| 152 | + | |
| 153 | + | |
| 154 | + | |
| 155 | + | |
| 156 | + | |
| 157 | + | |
| 158 | + | |
| 159 | + | |
| 160 | + | |
| 161 | + | |
| 162 | + | |
| 163 | + | |
| 164 | + | |
| 165 | + | |
| 166 | + | |
| 167 | + | |
| 168 | + | |
| 169 | + | |
| 170 | + | |
| 171 | + | |
| 172 | + | |
| 173 | + | |
| 174 | + | |
| 175 | + | |
| 176 | + | |
| 177 | + | |
| 178 | + | |
| 179 | + | |
| 180 | + | |
| 181 | + | |
| 182 | + | |
| 183 | + | |
| 184 | + | |
| 185 | + | |
| 186 | + | |
| 187 | + | |
| 188 | + | |
| 189 | + | |
| 190 | + | |
| 191 | + | |
| 192 | + | |
| 193 | + | |
| 194 | + | |
| 195 | + | |
| 196 | + | |
| 197 | + | |
| 198 | + | |
| 199 | + | |
| 200 | + | |
| 201 | + | |
| 202 | + | |
| 203 | + | |
| 204 | + | |
| 205 | + | |
| 206 | + | |
| 207 | + | |
| 208 | + | |
| 209 | + | |
| 210 | + | |
| 211 | + | |
| 212 | + | |
| 213 | + | |
| 214 | + | |
| 215 | + | |
| 216 | + | |
| 217 | + | |
| 218 | + | |
| 219 | + | |
| 220 | + | |
| 221 | + | |
| 222 | + | |
| 223 | + | |
| 224 | + | |
| 225 | + | |
| 226 | + | |
| 227 | + | |
| 228 | + | |
| 229 | + | |
| 230 | + | |
| 231 | + | |
| 232 | + | |
| 233 | + | |
| 234 | + | |
| 235 | + | |
| 236 | + | |
| 237 | + | |
| 238 | + | |
| 239 | + | |
| 240 | + | |
| 241 | + | |
| 242 | + | |
| 243 | + | |
| 244 | + | |
| 245 | + | |
| 246 | + | |
| 247 | + | |
| 248 | + | |
| 249 | + | |
| 250 | + | |
| 251 | + | |
| 252 | + | |
| 253 | + | |
| 254 | + | |
| 255 | + | |
| 256 | + | |
| 257 | + | |
| 258 | + | |
| 259 | + | |
| 260 | + | |
| 261 | + | |
0 commit comments