diff --git a/.changeset/26303-upgrade-skill-stored-rows-before-18-3.md b/.changeset/26303-upgrade-skill-stored-rows-before-18-3.md new file mode 100644 index 00000000000..223bc3926ff --- /dev/null +++ b/.changeset/26303-upgrade-skill-stored-rows-before-18-3.md @@ -0,0 +1,12 @@ +--- +'@objectstack/skills': patch +--- + +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 + +Clause-②: no +Metadata-protocol: none + +- **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. +- **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. +- `SKILL.md` and `references/examples-upgrade.md` stay under their token ceilings (no ceiling moves). No schema, key, command or behaviour changes. diff --git a/skills/objectstack-upgrade/SKILL.md b/skills/objectstack-upgrade/SKILL.md index aef545defb0..62fdb16754f 100644 --- a/skills/objectstack-upgrade/SKILL.md +++ b/skills/objectstack-upgrade/SKILL.md @@ -171,18 +171,17 @@ other with the reason it was not written, never writes a semantic change, and if re-running the chain over the written files disagrees, restores every file and exits 1. -### Stored rows: rehydration replays the same conversions +### Stored rows: rehydration replays what the release carries -A deployment's `sys_metadata` rows are the other subject. They are handled for -you at read time — the metadata loader and the ObjectQL plugin both pass each -stored row through `applyConversionsToStoredItem`, which replays the conversion -chain over a single item **including entries retired from the load path**. A row -written under protocol 16 therefore rehydrates in its protocol-17 shape without -anybody editing it. +A deployment's `sys_metadata` rows are the other subject. At read time the +metadata loader and the ObjectQL plugin pass each stored row through +`applyConversionsToStoredItem`, which replays every conversion the release still +carries, **including entries retired from the load path**. 18.3 drops those +retired at or below 16.x, so a row still in such a shape is no longer rewritten. Rehydration is a read-time projection: the rows on disk keep their old shape, -and you never hand-edit `sys_metadata`. To make it durable, run the stored pass -— read-only by default: +and you never hand-edit `sys_metadata`. ⛔ Run the stored pass before you move +(on 18.2 or earlier for such a row) — read-only by default: ```bash os migrate meta --stored # preview, writes nothing @@ -447,9 +446,9 @@ code: os migrate meta --stored --json # 0 = every row canonical, 1 = work left ``` -That is what makes "this deployment is on protocol N" a CI check rather than a -belief. Nothing gates on it having run; the read-time rehydration is still the -guarantee. +That is what makes "this deployment is on protocol N" a CI check — valid only +on the release you are leaving: one that dropped a row's conversions no longer +recognises it and answers `0`. Nothing gates on it having run. --- diff --git a/skills/objectstack-upgrade/evals/protocol-major-upgrade.json b/skills/objectstack-upgrade/evals/protocol-major-upgrade.json index ebd472a15a7..2d81e63ed56 100644 --- a/skills/objectstack-upgrade/evals/protocol-major-upgrade.json +++ b/skills/objectstack-upgrade/evals/protocol-major-upgrade.json @@ -34,12 +34,22 @@ { "id": 4, "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.", - "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.", + "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.", "files": [], "assertions": { "must_contain": ["applied", "--stored", "--yes", "field-required-notnull-explicit", "applyConversionsToStoredItem"], "must_not_contain": ["UPDATE sys_metadata"] } + }, + { + "id": 5, + "prompt": "我们在 @objectstack/spec 18.1,想直接升到 18.3。生产库 sys_metadata 里还有 16 时代存下的行,现在读出来都正常,直接升可以吗?", + "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.", + "files": [], + "assertions": { + "must_contain": ["--stored --apply --yes", "--stored --json", "18.3", "applyConversionsToStoredItem"], + "must_not_contain": ["UPDATE sys_metadata"] + } } ] } diff --git a/skills/objectstack-upgrade/references/examples-upgrade.md b/skills/objectstack-upgrade/references/examples-upgrade.md index 840e17708e1..573b003511b 100644 --- a/skills/objectstack-upgrade/references/examples-upgrade.md +++ b/skills/objectstack-upgrade/references/examples-upgrade.md @@ -76,7 +76,7 @@ _N sites, M conversions. Ported into sources from `os migrate meta --out`._ - [ ] `os migrate files-to-references` — media values only warn until it passes. - [ ] `os migrate value-shapes` — stored reference/JSON values unchecked until it passes. -- [ ] `os migrate meta --stored --apply` — rows rehydrate correctly today; this makes it durable. +- [ ] `os migrate meta --stored --apply` — before any release that drops their conversions. ## 5 · Not changed, and why