Skip to content

Commit 4df40e2

Browse files
docs(skills): objectstack-upgrade teaches the stored pass before 18.3 drops the ≤16.x conversions (#28918)
<!-- claude-projects-attribution: {"github_login":"huangyiirene"} --> _Requested by **Irene** · [project thread](https://claude.ai/code/project/chan_01TJXtQ1tVD26ecLDZxFS67x?thread=cmsg_01TJXtQ1tVD26ecLDZxFS67xYEtCvd5esC5k6dbFvWLihm)_ Fixes #26303 Clause-②: no Metadata-protocol: none ## 维护者速读 - **改了什么:** `objectstack-upgrade` 技能不再教「16 时代存下的 `sys_metadata` 行读时会被永远自动改写、不必动」;改为:18.3 去掉 ≤16.x 的转换后这类行不再读时改写,所以要在 18.2 或更早版本上先跑一次 `os migrate meta --stored --apply --yes` 再升级。eval 4 同步改写,新增 eval 5 直接问「18.1 想直升 18.3」。 - **为什么改:** 去掉 ≤16.x 转换的改动已合入 main、随 18.3 发布,它的 changeset 写明此类行「is no longer rewritten at read」;技能原文照做的客户升到 18.3 后,存量行会永远停在旧形状,而 18.3 上的存量迁移也已救不回来。 - **风险与回滚:** 只改对外技能文本、报告模板一行与 eval,不动代码、schema、命令与行为;两份受 token 棘轮约束的文件都在天花板内、上限行未动;回滚即 revert 本 PR。 - **先看:** ① `skills/objectstack-upgrade/SKILL.md` 的 "Stored rows" 一节(两段改写)与 § 3.6 末句;② `evals/protocol-major-upgrade.json` 的 eval 4 改句与新 eval 5;③ `references/examples-upgrade.md` 报告模板「Pending, per deployment」的存量迁移一行。 - **两分钟验证:** `node scripts/check-skills-token-ratchet.mjs && pnpm --filter @objectstack/spec check:skill-docs` 均绿,且 `grep -n "rehydrates in its protocol-17" skills/objectstack-upgrade/SKILL.md` 零命中。 - **需要你做的:** 审批本 PR(`skills/**` 是 Tier H 治理面,批准后由席位落地)。 ## What changes The 18.3 changeset `.changeset/25767-retire-16x-retirement-kits.md` (pending in the Version Packages PR) removes the 50 D2 conversions retired at or below 16.x, and its **Stored rows** bullet says a `sys_metadata` row still in such a shape "is no longer rewritten at read; canonicalize it once with `os migrate meta --stored --apply` on 18.2 or earlier, before moving to 18.3". The published upgrade skill still taught the opposite. This PR is the stored-rows half the card still owes (the floor half fell away under ruling 6434038284 on #25767: `MIGRATION_SUPPORT_FLOOR` stays 16, so `os migrate meta --from 16` and eval 1 are untouched). - **`SKILL.md` § "Stored rows".** Heading and two paragraphs rewritten: `applyConversionsToStoredItem` replays the conversions the installed release still carries (load-path-retired ones included); 18.3 drops those retired at or below 16.x, so such a row is no longer rewritten; ⛔ run the stored pass before you move (on 18.2 or earlier for such a row). The removed sentences are the two the card names: "including entries retired from the load path ... A row written under protocol 16 therefore rehydrates in its protocol-17 shape without anybody editing it" and "To make it durable, run the stored pass". The command block, the `--yes` warning and the `--from` note are unchanged. - **`SKILL.md` § 3.6.** "the read-time rehydration is still the guarantee" becomes "so get `0` before you move" — the same claim in its second place. - **`references/examples-upgrade.md`** report template: the stored-pass checklist line said "rows rehydrate correctly today; this makes it durable"; it now says the pass is owed "before any release that drops their conversions". - **`evals/protocol-major-upgrade.json`.** Eval 4's expected answer says stored rows rehydrate only while the installed release carries their conversions and runs the stored pass before moving past 18.2; its assertions are unchanged. New eval 5 (Chinese prompt, like eval 1): on 18.1, going straight to 18.3, rows from 16 read fine today; the expected answer runs `--stored`, `--stored --apply --yes` and `--stored --json` (exit 0) on 18.1 before the bump, and refuses both hand-editing `sys_metadata` and bumping first. - **Changeset** `.changeset/26303-upgrade-skill-stored-rows-before-18-3.md`, `'@objectstack/skills': patch`, carrying both declaration lines. ## Tests No code path changes, so no unit test applies; the teaching is exercised by eval 4 (amended) and eval 5 (new). The skill gates the card names are green on `3bf0627876`: `check:skill-docs`, `check:skill-refs`, `check:skill-examples` (280 prose examples type-check across 3 surfaces). The full derived set is under Verification. ## Acceptance notes **Line and token readings** (tree `objectstack-ai/objectstack` at `3bf0627876` against base `b15b634c16`; lines by `wc -l`, tokens by the token ratchet's `ceil(utf8 bytes / 4)` over the whole file): | File | Lines before → after | Tokens before → after | |:--|:--|:--| | `skills/objectstack-upgrade/SKILL.md` | 483 → 481 (−2) | 6176 → 6171 (ratchet's priced count after: 6166, ceiling 6188) | | `skills/objectstack-upgrade/references/examples-upgrade.md` | 119 → 119 (0) | 1195 → 1194 (ceiling 1197) | | `skills/objectstack-upgrade/evals/protocol-major-upgrade.json` | 45 → 55 (+10) | 1033 → 1314 (eval fixture, measured, not ratcheted) | | **Package** `skills/objectstack-upgrade/**` (all files) | 647 → 655 (+8, budget +15) | — | | **Catalog** sum of all 11 `skills/*/SKILL.md` | 4554 → 4552 (−2) | — | No ceiling row moves: the new teaching is paid for inside the stale sentences it replaces. **Premise readings.** At tag `@objectstack/spec@18.2.0` (`27f38ada49`) `packages/spec/src` carries 45 conversions with `retiredAfter` 16.x and 5 with 15.x; at `b15b634c16` it carries 0. `packages/spec/package.json` on the base reads `18.2.0`, so the drop ships in the next release, 18.3, per the changeset. **Scope.** The seat's brief named § "Stored rows" and the eval; § 3.6's last sentence and the report-template line state the same claim, so they were corrected in the same stroke (stale lines of the claim this card names, nothing else removed). **Observed, not filed (unrehearsed drift, outside this file surface):** two code headers still state the pre-18.3 policy — `packages/spec/src/conversions/stored.ts` ("D3 keeps every conversion forever precisely so any past major can replay forward") and `packages/metadata-protocol/src/stored-migration.ts` ("a row written under any past protocol is *served* canonical forever"); Prime Directive #12 in `AGENTS.md` says every rehydration seam replays "the full conversion chain — retired entries included". None is published teaching; carrier: none. ## Verification <details><summary>Derived gate set — 46 derived, 45 run with exit 0, 1 NOT MEASURED (head 3bf0627)</summary> `node scripts/pm/dispatch-gates.mjs --repo objectstack-ai/objectstack --ran RECORD` on `3bf0627876`: "✓ dispatch-gates --ran: 46 derived famil(ies) accounted for — 45 run, 1 NOT-MEASURED (1 DERIVED from a recorded exit 3)". - `node scripts/check-skills-token-ratchet.mjs` :: exit 0 — "57 authored bundle file(s) within their ceilings"; "skills/objectstack-upgrade/SKILL.md is 6166 tokens (ceiling 6188; headroom 22)"; "references/examples-upgrade.md is 1194 tokens (ceiling 1197; headroom 3)". - `pnpm --filter @objectstack/spec run check:skill-docs` :: exit 0 — "Skill docs in sync". - `pnpm --filter @objectstack/spec run check:skill-refs` :: exit 0 — "9 generated files in sync with packages/spec". - `pnpm --filter @objectstack/spec run check:skill-examples` :: exit 0 (after building `@objectstack/spec` and the `@objectstack/client-react` closure) — "280 prose examples type-check across 3 surface(s)". - `pnpm check:doc-authoring` :: exit 0; `pnpm check:nul-bytes` :: exit 0; `node scripts/check-empty-changeset.mjs --base origin/main` :: exit 0; `node scripts/check-adr-0087-registration.mjs --base origin/main` :: exit 0; `node scripts/check-changeset-no-major.mjs --base origin/main` :: exit 0; `pnpm check:role-word` :: exit 0; `pnpm check:skill-compatibility` :: exit 0; `pnpm check:skill-frame-sync` :: exit 0; `pnpm check:skill-identifier-liveness` :: exit 0; `pnpm check:published-files` :: exit 0; `pnpm check:pm-governed-merges` :: exit 0; the remaining derived families :: exit 0. - `pnpm check:dts-closure`, `pnpm check:sourcemap-no-sources-content`, `pnpm check:lean-entry-closure`, `pnpm --filter @objectstack/lint run check:doc-formula-expressions` first answered exit 3 (no build); re-run after building the 38-package `@objectstack/client-react` closure plus `@objectstack/formula` and `@objectstack/lint` :: exit 0 each (dts-closure and sourcemap swept the 38 built packages). - **NOT MEASURED:** `pnpm check:dual-build-cjs-loads` :: exit 3, PREREQUISITE NOT MET (reads every package's `dist/`; a repo-wide build is not run locally) — CI's build lane carries it. </details> --- _Generated by [Claude Code](https://claude.ai/code/session_01J8VVAkD2h5o5cmhTRa3bsF)_ --------- Co-authored-by: Claude <noreply@anthropic.com>
1 parent 494c743 commit 4df40e2

4 files changed

Lines changed: 35 additions & 14 deletions

File tree

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
---
2+
'@objectstack/skills': patch
3+
---
4+
5+
docs(skills): objectstack-upgrade says a stored row in a ≤16.x shape stops being rewritten at read on 18.3, and teaches the stored pass on 18.2 or earlier first
6+
7+
Clause-②: no
8+
Metadata-protocol: none
9+
10+
- **Before.** § "Stored rows" said every stored-row rehydration replays the conversion chain including entries retired from the load path, so "a row written under protocol 16 therefore rehydrates in its protocol-17 shape without anybody editing it", and offered `os migrate meta --stored --apply` only as a way to make that durable. § 3.6 called the read-time rehydration "still the guarantee", the report template marked the stored pass optional ("rows rehydrate correctly today"), and eval 4 expected the same answer. On 18.3, which drops every conversion retired at or below 16.x, that advice leaves such a row unconverted for good.
11+
- **Now.** The section says rehydration replays only the conversions the installed release still carries, that 18.3 drops those retired at or below 16.x, and to run the stored pass on the release being left (18.2 or earlier for such a row) before moving; § 3.6 says the `os migrate meta --stored --json` exit `0` counts only on the release being left, because one that dropped a row's conversions answers `0` without recognising the row; the report template's stored-pass line says it is owed before any release that drops the rows' conversions. Eval 4's expected answer says the same, and new eval 5 asks the 18.1 → 18.3 question directly.
12+
- `SKILL.md` and `references/examples-upgrade.md` stay under their token ceilings (no ceiling moves). No schema, key, command or behaviour changes.

‎skills/objectstack-upgrade/SKILL.md‎

Lines changed: 11 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -171,18 +171,17 @@ other with the reason it was not written, never writes a semantic change, and
171171
if re-running the chain over the written files disagrees, restores every file
172172
and exits 1.
173173

174-
### Stored rows: rehydration replays the same conversions
174+
### Stored rows: rehydration replays what the release carries
175175

176-
A deployment's `sys_metadata` rows are the other subject. They are handled for
177-
you at read time — the metadata loader and the ObjectQL plugin both pass each
178-
stored row through `applyConversionsToStoredItem`, which replays the conversion
179-
chain over a single item **including entries retired from the load path**. A row
180-
written under protocol 16 therefore rehydrates in its protocol-17 shape without
181-
anybody editing it.
176+
A deployment's `sys_metadata` rows are the other subject. At read time the
177+
metadata loader and the ObjectQL plugin pass each stored row through
178+
`applyConversionsToStoredItem`, which replays every conversion the release still
179+
carries, **including entries retired from the load path**. 18.3 drops those
180+
retired at or below 16.x, so a row still in such a shape is no longer rewritten.
182181

183182
Rehydration is a read-time projection: the rows on disk keep their old shape,
184-
and you never hand-edit `sys_metadata`. To make it durable, run the stored pass
185-
— read-only by default:
183+
and you never hand-edit `sys_metadata`. ⛔ Run the stored pass before you move
184+
(on 18.2 or earlier for such a row) — read-only by default:
186185

187186
```bash
188187
os migrate meta --stored # preview, writes nothing
@@ -447,9 +446,9 @@ code:
447446
os migrate meta --stored --json # 0 = every row canonical, 1 = work left
448447
```
449448

450-
That is what makes "this deployment is on protocol N" a CI check rather than a
451-
belief. Nothing gates on it having run; the read-time rehydration is still the
452-
guarantee.
449+
That is what makes "this deployment is on protocol N" a CI check — valid only
450+
on the release you are leaving: one that dropped a row's conversions no longer
451+
recognises it and answers `0`. Nothing gates on it having run.
453452

454453
---
455454

‎skills/objectstack-upgrade/evals/protocol-major-upgrade.json‎

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -34,12 +34,22 @@
3434
{
3535
"id": 4,
3636
"prompt": "We bumped @objectstack/spec 16 → 17 and `os validate` is green, so there was nothing to upgrade, right? Production also has `sys_metadata` rows written under 16.",
37-
"expected_output": "No: `validate` green is necessary, not sufficient — migration-chain-only conversions (16 → 17 has `field-required-notnull-explicit`) reject nothing at parse. Replays `os migrate meta --from 17 --json` and reads `applied` (must be `[]`). Stored rows rehydrate through `applyConversionsToStoredItem` at read time; to make it durable runs `os migrate meta --stored` (read-only) then `os migrate meta --stored --apply --yes` (`--yes` is mandatory in a non-TTY), and never hand-edits `sys_metadata`. Any per-deployment data-migration gates the run prints go into the report as pending, by name.",
37+
"expected_output": "No: `validate` green is necessary, not sufficient — migration-chain-only conversions (16 → 17 has `field-required-notnull-explicit`) reject nothing at parse. Replays `os migrate meta --from 17 --json` and reads `applied` (must be `[]`). Stored rows rehydrate through `applyConversionsToStoredItem` only while the installed release carries their conversions (18.3 drops those retired at or below 16.x), so before moving past 18.2 it runs `os migrate meta --stored` (read-only) then `os migrate meta --stored --apply --yes` (`--yes` is mandatory in a non-TTY), and never hand-edits `sys_metadata`. Any per-deployment data-migration gates the run prints go into the report as pending, by name.",
3838
"files": [],
3939
"assertions": {
4040
"must_contain": ["applied", "--stored", "--yes", "field-required-notnull-explicit", "applyConversionsToStoredItem"],
4141
"must_not_contain": ["UPDATE sys_metadata"]
4242
}
43+
},
44+
{
45+
"id": 5,
46+
"prompt": "我们在 @objectstack/spec 18.1,想直接升到 18.3。生产库 sys_metadata 里还有 16 时代存下的行,现在读出来都正常,直接升可以吗?",
47+
"expected_output": "Not yet: those rows read fine today only because `applyConversionsToStoredItem` replays the conversions 18.1 still carries, and 18.3 drops those retired at or below 16.x, so after the bump such a row is no longer rewritten at read. On 18.1, before the bump: `os migrate meta --stored` (read-only preview), then `os migrate meta --stored --apply --yes`, then `os migrate meta --stored --json` must exit 0; only then move to 18.3. Never hand-edits `sys_metadata`, and never bumps first expecting the 18.3 stored pass to repair the rows — the conversions are gone there too, so an 18.3 `--stored --json` exit 0 proves nothing about such a row: nothing recognises it any more.",
48+
"files": [],
49+
"assertions": {
50+
"must_contain": ["--stored --apply --yes", "--stored --json", "18.3", "applyConversionsToStoredItem"],
51+
"must_not_contain": ["UPDATE sys_metadata"]
52+
}
4353
}
4454
]
4555
}

‎skills/objectstack-upgrade/references/examples-upgrade.md‎

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -76,7 +76,7 @@ _N sites, M conversions. Ported into sources from `os migrate meta --out`._
7676

7777
- [ ] `os migrate files-to-references` — media values only warn until it passes.
7878
- [ ] `os migrate value-shapes` — stored reference/JSON values unchecked until it passes.
79-
- [ ] `os migrate meta --stored --apply` — rows rehydrate correctly today; this makes it durable.
79+
- [ ] `os migrate meta --stored --apply` — before any release that drops their conversions.
8080

8181
## 5 · Not changed, and why
8282

0 commit comments

Comments
 (0)