persistence: multi-version reads across every store
ProcessJobStore and SubstrateStore already implemented the loader-accepts-any-version-in-[1, kVersion] pattern. The other five stores (ControlJobStore, CarrierStore, LoadPortStore, ExceptionStore, SpoolStore) used strict `header[1] != kVersion` rejection, meaning a future kVersion bump there would silently nuke every persisted record on first replay. That's a footgun the test_persistence_upgrade test already flagged as a tripwire. This commit flips the strict checks to `< 1 || > kVersion`, mirroring PJ + Substrate. No format change (kVersion stays at 1 across the five stores), but: - Future v2 of any store now Just Works: add fields at the end of write_record_, bump kVersion to 2, gate the new reads behind `if (version >= 2)`. Old v1 records on disk continue to replay with the new fields defaulted. - Future versions beyond kVersion still get rejected (downgrade protection — older code can't try to decode trailers it doesn't understand). Comment blocks on each kVersion declaration now describe the upgrade discipline so the next contributor doesn't reinvent it. Test additions: - Positive test that v1 ControlJob records load on current code (will continue to pass when kVersion bumps to 2, proving v1 is still readable) - ExceptionStore rejects a v9 (future) record, matching CJ + Carrier - The existing tripwire tests get retitled from "rejects unknown version" to "rejects a future version" to reflect the new contract README §6 gets honest: every store is now multi-version-aware, not just PJ + Substrate. Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
This commit is contained in:
@@ -323,17 +323,18 @@ new dictionary loads. Code changes do require rebuild + restart.
|
||||
- **Code upgrades**: deploy to a canary tool first; bake-test for
|
||||
at least a full wafer batch before fleet-wide rollout.
|
||||
- **Schema migrations**: persistence records carry a 1-byte version
|
||||
stamp after the magic byte. `ProcessJobStore` and `SubstrateStore`
|
||||
currently implement multi-version reads: code at kVersion=2 still
|
||||
loads v1 records (the v2 trailer fields default to empty). The
|
||||
remaining stores (`ControlJobStore`, `CarrierStore`, `LoadPortStore`,
|
||||
`ExceptionStore`, `SpoolStore`) use strict version equality — a
|
||||
future kVersion bump there requires adding a parser for the prior
|
||||
version at the same time, otherwise replay will reject old records.
|
||||
Tests in `tests/test_persistence_upgrade.cpp` lock down both
|
||||
contracts and act as a tripwire if a kVersion bumps silently.
|
||||
Always test the upgrade with a real on-disk journal before fleet
|
||||
rollout.
|
||||
stamp after the magic byte. Every store (`ProcessJobStore`,
|
||||
`SubstrateStore`, `ControlJobStore`, `CarrierStore`, `LoadPortStore`,
|
||||
`ExceptionStore`, `SpoolStore`) accepts any version in
|
||||
`[1, kVersion]`: code at kVersion=2 loads both v1 and v2 records
|
||||
(v1 trailer fields default to empty). Future versions beyond
|
||||
`kVersion` are rejected so a downgrade can't silently corrupt
|
||||
data. Upgrade discipline: when adding fields, bump `kVersion` and
|
||||
gate the new trailer behind `if (version >= N)` in the loader.
|
||||
Tests in `tests/test_persistence_upgrade.cpp` lock down the
|
||||
contract and act as a tripwire if a writer bumps `kVersion`
|
||||
without teaching the loader to handle prior versions. Always
|
||||
test the upgrade with a real on-disk journal before fleet rollout.
|
||||
|
||||
## 7. Integration with the fab stack
|
||||
|
||||
|
||||
Reference in New Issue
Block a user