Follow-up to #3903 (option 2), downgraded from decision to enhancement by PR #4317. Filed per Prime Directive #10.
Context
#4317 answered #3903 with option 1: every stored-row rehydration seam replays the full ADR-0087 conversion chain (applyConversionsToStoredItem, retired entries included), so a row written under any past protocol reads canonical forever. That closes the correctness gap — data at rest can no longer diverge from the contract.
What it deliberately does NOT do is make the rows themselves canonical. A pre-17 row keeps its legacy bytes; the chain re-lowers it on every load, and each affected row emits one [metadata_spec_invalid]-adjacent conversion warning per process (deduped, but recurring per boot). Today the only ways a row gets rewritten are a Studio re-save and duplicatePackage.
The enhancement
os migrate meta --stored (or an admin route): walk sys_metadata (active + draft, all orgs), run the same applyConversionsToStoredItem pass, and re-save changed bodies through the normal write path (history row, checksum, mutation projectors) with source: 'migrate-stored'. Optionally --dry-run printing the per-row conversion notices.
Value:
- rows stop carrying pre-protocol dialects (cleaner diffs, exports, history going forward);
- the boot/read conversion pass returns to a no-op on every row, and the recurring notices go quiet;
- operators get an explicit, verifiable "my data is on protocol N" statement instead of an implicit perpetual shim.
Not load-bearing: the read path stays the guarantee (#3855's conclusion that operator-run migrations cannot be relied on still holds — this is hygiene for those who run it, not a prerequisite for anyone).
Refs #3903, PR #4317, ADR-0087 addendum "stored metadata replays the chain", #3855.
Follow-up to #3903 (option 2), downgraded from decision to enhancement by PR #4317. Filed per Prime Directive #10.
Context
#4317 answered #3903 with option 1: every stored-row rehydration seam replays the full ADR-0087 conversion chain (
applyConversionsToStoredItem, retired entries included), so a row written under any past protocol reads canonical forever. That closes the correctness gap — data at rest can no longer diverge from the contract.What it deliberately does NOT do is make the rows themselves canonical. A pre-17 row keeps its legacy bytes; the chain re-lowers it on every load, and each affected row emits one
[metadata_spec_invalid]-adjacent conversion warning per process (deduped, but recurring per boot). Today the only ways a row gets rewritten are a Studio re-save andduplicatePackage.The enhancement
os migrate meta --stored(or an admin route): walksys_metadata(active + draft, all orgs), run the sameapplyConversionsToStoredItempass, and re-save changed bodies through the normal write path (history row, checksum, mutation projectors) withsource: 'migrate-stored'. Optionally--dry-runprinting the per-row conversion notices.Value:
Not load-bearing: the read path stays the guarantee (#3855's conclusion that operator-run migrations cannot be relied on still holds — this is hygiene for those who run it, not a prerequisite for anyone).
Refs #3903, PR #4317, ADR-0087 addendum "stored metadata replays the chain", #3855.