Repository navigation
Commit 57a2612
skills(objectstack-upgrade): the §3.3 acceptance replay names the last ported hop and can fail (#29751)
domain:skills#1 · huangyiirene · session_01J8VVAnMUWA9rufXzFaEh4J
<!-- claude-projects-attribution: {"github_login":"huangyiirene"} -->
_Requested by **Irene** · [project
thread](https://claude.ai/code/project/chan_01TJXtQ1tVD26ecLDZxFS67x?thread=cmsg_01TJXtQ1tVD26ecLDZxFS67xDjK2kTDLPATyrvGTNpN73K)_
Fixes #29063
Clause-②: no
Metadata-protocol: none
## 维护者速读
- 改了什么:`objectstack-upgrade` §3.3 的验收回放不再从目标主版本起跑(在最高主版本上那是空区间,`applied`
永远是 `[]`,检查永远过)。改为回放整段移植区间 `--from <authored-major> --to <target-major>
--json`(与 quickstart 第 1 步同一区间),要求 `applied: []` 且 JSON 里没有
`replayedNothing`(#29045 合入后,没跑任何一步时 `--json` 会带这个键)。quickstart 第 74
行与文内另三处同一回放的提法改成一致;两条练这项检查的 eval 的期望同步。提示框里举的
`field-required-notnull-explicit` 已在 conversions registry 撤回,提示框不再点名任何
conversion;报告模板(examples-upgrade.md)的示例行改用 registry 真有的
`sharing-rule-access-level-full-to-edit`,其 Verified 行改为全区间回放「replay 16 →
18」。
- 为什么改:按原文执行的 agent 会记录一条从未检查任何东西的「元数据已规范」验收。
- 风险与回滚:只改技能文本与其 eval;无代码、无门禁变动。回滚即 revert。
- 先看:`SKILL.md` L74、L388–411;`evals/protocol-major-upgrade.json` 第 1、4
条;`references/examples-upgrade.md` L48、L54。
- 棘轮:token 棘轮就地付账,无 re-wrap。SKILL.md 删了两处同文件复述(见下),6185 → 6160
tokens,天花板 6188 未动;examples-upgrade.md 1194 → 1189 / 1197。
- 需要你做的:Tier H,等维护者的字。
## What changes
1. **§3.3 Validate** (`skills/objectstack-upgrade/SKILL.md` L397–411).
The replay that closes the gap after a green `validate` is now `os
migrate meta --from <authored-major> --to <target-major> --json`, the
whole range the sources were ported through (the `--from` of §0, the
range quickstart step 1 replays), and the criterion is `applied` must be
`[]` **and** `replayedNothing` absent. `composeMigrationChain` keeps `m
> fromMajor && m <= toMajor`, so a replay from the major below the
target would leave out every earlier hop; the whole range is non-empty
whenever the crossing has a step and sees every hop. The paragraph that
followed, which said `--to` defaults to one past the installed major so
only `todos` carries the next major's residue, is replaced: it explains
that `--from <target-major>` proves nothing, because `--to` defaults to
the highest major this build carries a step for, so the range is empty
(no step runs, `applied` is `[]` whatever the metadata holds, and the
JSON says so with `replayedNothing`, whose `widestRange` is `null` there
because no wider range exists from that `--from`) or holds only the next
major's step. `todos` stays Layer 2's business, not a failure. `--to` is
in the command listing at L143 already.
2. **Quickstart L74** now reads `os migrate meta --from 16 --to 18
--json # \`applied\` [] and no \`replayedNothing\` (see §3.3)`, which is
§3.3's command for the quickstart's 16 → 18 crossing (step 1 replays
`--from 16`). The card read L74 as unaffected; `--to 18` pins the range
so the two lines say the same thing on a build that already carries a
later step.
3. **The callout's example** (L388–394).
`field-required-notnull-explicit` is withdrawn from
`packages/spec/src/conversions/registry.ts` (its docblock exists to stop
it being re-added), and every conversion this build ships is
`retiredFromLoadPath` with its old shape refused at parse, so no
migration-chain-only conversion exists on this head. The callout keeps
the class and its reason, says this build ships none and a later one
can, and names no conversion. The report template's example row
(`references/examples-upgrade.md` L54, surface widened by the seat in
6594782842) named the same withdrawn id; it now shows the step-17
conversion `sharing-rule-access-level-full-to-edit` at the site shape
the chain prints, `sharingRules[0].accessLevel` `'full'` → `'edit'`
(`mapCollection` spells array sites by index; the conversion's own
fixture is a `sharingRules` entry). No `notnull-explicit` mention
remains under `skills/`. The same template's **Verified** line (L48,
surface widened again in 6594814065) said "replay-from-17 applies 0
mechanical changes" under "Chain: 16 → 18", the last-hop form M1
retired; it now says "replay 16 → 18 applies 0 mechanical changes".
4. **Three other mentions of the same replay** in the file, so no line
still says "from the target major": the §3.5 evidence row ("Only the
acceptance replay sees this class."), the failure-mode row for `--write`
("then replay the ported range to confirm 0 changes") and the row
"Replay from the target major still applies changes" → "The acceptance
replay still applies changes".
5. **Evals 1 and 4** (`evals/protocol-major-upgrade.json`) expect `os
migrate meta --from 16 --to 17 --json` (a one-hop crossing, where the
ported range is that hop) with `applied: []` and no `replayedNothing`,
and say why `--from 17` alone checks nothing. Eval 4's `must_contain`
gains `replayedNothing` and drops `field-required-notnull-explicit`; its
`expected_output` no longer names a conversion. Eval fixtures are
measured, not ratcheted.
The `replayedNothing` reading is taken from the merged CLI,
`packages/cli/src/commands/migrate/meta.ts`: `readReplayedNothing`
returns `null` when `result.hops.length > 0`, else `{ reason:
'empty-range' | 'inverted-range', widestRange: { from, to, applied,
manual } | null }`; `--json` spreads it into the payload only in that
case, next to `applied`, `todos` and `absentTodos`.
`composeMigrationChain` keeps the majors `m > fromMajor && m <=
toMajor`, so `--from 18` on this build (steps to 17 and 18,
`CHAIN_TERMINUS_MAJOR` 18) composes zero steps.
### Token ratchet (paid in place, no re-wrap)
`skills/objectstack-upgrade/SKILL.md`: 6185 → 6160 tokens, ceiling 6188
(headroom 3 → 28). `references/examples-upgrade.md`: 1194 → 1189 tokens,
ceiling 1197 (headroom 3 → 8), one row replaced by a shorter one and one
line reworded in place (+2 bytes), no re-wrap. The ceiling row in
`scripts/check-skills-token-ratchet.mjs` is not touched (second file,
out of surface). Two genuine deletions of same-file restatement pay for
the added text:
| deleted | home |
|:--|:--|
| §1 bullet "**Pending data migrations**, when the chain crosses into a
major with per-deployment data gates — see below." (2 lines) | the §1
subsection "Data migrations are not metadata migrations", directly
below, which says what the run prints and what to carry into the report
|
| failure-mode row "`validate` green from the start, so 'there was
nothing to upgrade' … `validate` green is necessary, not sufficient; see
3.3" (1 line) | §3.3's own callout, titled "A green `validate` does NOT
mean the chain has nothing left to do", which the row restated and
pointed back to |
Every other block is byte-identical to `main`. Line counts: SKILL.md 482
→ 482, examples-upgrade.md unchanged.
## Why
Card #29063 (filed from the #28947 dev, PR #29045): when the target is
the highest major this build carries a step for, `os migrate meta --from
<target-major> --json` is an empty range, so an agent following §3.3
records a canonical-metadata acceptance that never examined anything.
Now that `--json` carries `replayedNothing` when no step ran, the skill
can name a range that can fail and a key whose presence means the check
never ran.
## Verification
On head 55e64c9 (2063a6b is the contract-review delta for 6594719416:
M1, S1 and the withdrawn-example point; 701f463 and 55e64c9 are the
two template lines the seat widened the surface to, L54 and L48):
- `node scripts/check-skills-token-ratchet.mjs`: exit 0 (SKILL.md 6160 /
6188, examples-upgrade.md 1189 / 1197), and its `--self-test`: exit 0.
- `pnpm check:pm-skill-id-lint`, `@objectstack/spec check:skill-docs`,
`check:skill-frame-sync`, `check:skill-frame-freshness`,
`check:skill-compatibility`, `check:skill-identifier-liveness`,
`check-doc-route-spelling --advisory`, `check:doc-authoring`,
`check:role-word`, `check:corpus-claim-drift`: each exit 0.
- `node scripts/check-commit-card-trailers.mjs --range
origin/main..HEAD`: exit 0 (four commits).
- Full derived list on 55e64c9, `node scripts/pm/dispatch-gates.mjs
--commands` → 35 families for the three paths, all run with a 900 s
timeout each after `pnpm install --frozen-lockfile` (exit 0), exit codes
recorded before any pipe (record in the project files as
`gates-55e64c92.txt`):
- 33 exit 0: `check-closing-keyword-parity` (+ self-test),
`check-comment-mask-corpus`, `check-doc-route-spelling --advisory` (+
self-test), `check-dts-emitted --self-test`,
`check-skills-token-ratchet` (+ self-test), the three `scripts/ci/*`
self-tests, `@objectstack/lint check:doc-formula-expressions` (after
`turbo run build --filter=@objectstack/formula
--filter=@objectstack/lint`), `@objectstack/spec check:skill-docs`,
`check:agent-test-spelling`, `check:ci-filter-parity`,
`check:corpus-claim-drift`, `check:cross-package-test-inputs`,
`check:doc-authoring`, `check:driver-memory-census`, `check:dts-closure`
and `check:sourcemap-no-sources-content` (both swept the 4 packages that
build left in `dist`), `check:gitlink-declared`, `check:merge-driver`,
`check:nul-bytes`, `check:pm-governed-merges`, `check:pm-skill-id-lint`,
`check:refd-timer-probe`, `check:role-word`,
`check:skill-compatibility`, `check:skill-frame-sync`,
`check:skill-identifier-liveness`, `check:watch-hint-literal`.
- 2 exit 3 (prerequisite, not a finding): `check:dual-build-cjs-loads`
and `check:lean-entry-closure` want a full `pnpm build` of ~72 packages;
the diff touches no `packages/**`, so CI's Build Core is their reading.
- `dispatch-gates --ran`: `35 derived famil(ies) accounted for — 33 run,
2 NOT-MEASURED (2 DERIVED from a recorded exit 3)`, exit 0.
On head 1cb7088 (first head):
- `node scripts/check-skills-token-ratchet.mjs`: exit 0 (SKILL.md 6147 /
6188).
- `node scripts/pm/check-skill-id-lint.mjs` (with `--self-test`): exit
0, 108 files clean.
- `node scripts/pm/check-skill-line-ratchet.mjs`: exit 0 (its roots do
not include `skills/**`; run because the order named the line ratchet).
- `node scripts/check-commit-card-trailers.mjs --range
origin/main..HEAD`: exit 0.
- `evals/protocol-major-upgrade.json` parses.
<details><summary>Local gates on 1cb7088: 34 derived, 30 run exit 0, 4
NOT MEASURED (`dispatch-gates --ran`)</summary>
- `node scripts/pm/dispatch-gates.mjs --commands` on this head derived
34 commands for the two paths. All 34 ran with a 900 s timeout each
after `pnpm install --frozen-lockfile`; exit codes were recorded before
any pipe.
- 30 exited 0, including `check-skills-token-ratchet` (and its
self-test), `check:pm-skill-id-lint`, `check:skill-frame-sync`,
`check:skill-identifier-liveness`, `check:skill-compatibility`,
`@objectstack/spec check:skill-docs`, `check-comment-mask-corpus` and
`check-doc-route-spelling`. `@objectstack/lint
check:doc-formula-expressions` first exited 3 in the fresh tree and
exited 0 after `turbo run build --filter=@objectstack/formula
--filter=@objectstack/lint`.
- 4 exited 3 (prerequisite, not a finding): `check:dts-closure`,
`check:dual-build-cjs-loads`, `check:lean-entry-closure`,
`check:sourcemap-no-sources-content` each want a full `pnpm build` of
~72 packages. The diff touches no `packages/**`; CI's Build Core is the
reading for them.
- `--ran` printed: `34 derived famil(ies) accounted for — 30 run, 4
NOT-MEASURED (4 DERIVED from a recorded exit 3)`, exit 0.
- Not derived for these paths and not run locally: the type-check lanes,
the whole-tree artifact rosters, and the main-only push battery
(dogfood, temporal conformance).
</details>
## Human Minimum
- [x] 1. Schemas start as Zod; `packages/spec` holds no runtime logic.
(not touched)
- [x] 2. Every name I added uses the casing for its kind. (no names
added)
- [ ] 3. No formatter ran; `pnpm lint` not run locally (docs-only diff;
the derived gate families above are what ran). CI's Lint & Repo Gates is
the reading.
- [x] 4. One issue, one branch off an up-to-date `main`, one pull
request.
- [x] 5. A change that publishes carries a changeset, and both
declaration lines are filled in here and in the changeset. (skills docs
only, `skip-changeset`)
- [x] 6. `packages/spec` touched: its generated artifacts are
regenerated and committed. (not touched)
- [x] 7. No hand edits to `content/docs/references/`,
`packages/*/CHANGELOG.md` or `content/docs/releases/`.
- [x] 8. Title, body and comments are in English.
- [ ] The *Before Submitting* list in CONTRIBUTING.md: the gate families
derived for these paths ran (above); nothing else on the list applies to
a two-file skills diff.
🤖 Generated with [Claude Code](https://claude.com/claude-code)
https://claude.ai/code/session_01J8VVAoGi31QpTx8NiZpBWm
---------
Co-authored-by: Claude <noreply@anthropic.com>1 parent 2c91a55 commit 57a2612
3 files changed
Lines changed: 22 additions & 22 deletions
File tree
- skills/objectstack-upgrade
- evals
- references
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
71 | 71 | | |
72 | 72 | | |
73 | 73 | | |
74 | | - | |
| 74 | + | |
75 | 75 | | |
76 | 76 | | |
77 | 77 | | |
| |||
159 | 159 | | |
160 | 160 | | |
161 | 161 | | |
162 | | - | |
163 | | - | |
164 | 162 | | |
165 | 163 | | |
166 | 164 | | |
| |||
391 | 389 | | |
392 | 390 | | |
393 | 391 | | |
394 | | - | |
395 | | - | |
396 | | - | |
| 392 | + | |
| 393 | + | |
| 394 | + | |
397 | 395 | | |
398 | | - | |
| 396 | + | |
399 | 397 | | |
400 | | - | |
| 398 | + | |
401 | 399 | | |
402 | 400 | | |
403 | | - | |
| 401 | + | |
| 402 | + | |
404 | 403 | | |
405 | 404 | | |
406 | | - | |
407 | | - | |
408 | | - | |
409 | | - | |
| 405 | + | |
| 406 | + | |
| 407 | + | |
| 408 | + | |
| 409 | + | |
| 410 | + | |
410 | 411 | | |
411 | 412 | | |
412 | 413 | | |
| |||
434 | 435 | | |
435 | 436 | | |
436 | 437 | | |
437 | | - | |
| 438 | + | |
438 | 439 | | |
439 | 440 | | |
440 | 441 | | |
| |||
460 | 461 | | |
461 | 462 | | |
462 | 463 | | |
463 | | - | |
464 | | - | |
| 464 | + | |
| 465 | + | |
465 | 466 | | |
466 | | - | |
467 | 467 | | |
468 | 468 | | |
469 | 469 | | |
| |||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
4 | 4 | | |
5 | 5 | | |
6 | 6 | | |
7 | | - | |
| 7 | + | |
8 | 8 | | |
9 | 9 | | |
10 | 10 | | |
| |||
34 | 34 | | |
35 | 35 | | |
36 | 36 | | |
37 | | - | |
| 37 | + | |
38 | 38 | | |
39 | 39 | | |
40 | | - | |
| 40 | + | |
41 | 41 | | |
42 | 42 | | |
43 | 43 | | |
| |||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
45 | 45 | | |
46 | 46 | | |
47 | 47 | | |
48 | | - | |
| 48 | + | |
49 | 49 | | |
50 | 50 | | |
51 | 51 | | |
52 | 52 | | |
53 | 53 | | |
54 | | - | |
| 54 | + | |
55 | 55 | | |
56 | 56 | | |
57 | 57 | | |
| |||
0 commit comments