Formalize save-format versioning + a migration registry nf-6ms9 ← Beads

closed priority 2 task unassigned

Twinned from https://github.com/cfsh/ninefold/issues/250 by tools/beads/import_github.py's reconcile pass.

Idle-time proposal (CLAUDE.md value 4) — flagging before schema drift compounds; no action until you weigh in.

## The drift so far The save format is now evolving in three uncoordinated ways: - #209/#244 introduced LegacyMigrations.Modernize() — an ad-hoc, load-time, per-sound rewrite (drum-kit → sampled kit) that must run forever because nothing records whether a save predates it. - #228/#248 added Pattern.Stash — nullable-so-old-readers-cope, which works but is a convention nobody wrote down. - The library mirror (#193/#233) copies files whose schema version is implicit in "whatever the code was when it saved".

Each change is individually safe, but the failure mode is cumulative: five migrations from now, load-time code is a pile of "sniff the shape and guess" heuristics that must all stay correct against every historical combination.

## Proposal 1. "v": 1 on each saved file (song/sound/pattern). Absent ⇒ v0. 2. A Migrations registry: ordered (fromVersion, Migrate(json/model)) steps run at load until current — LegacyMigrations becomes step v0→v1 instead of a forever-sniffer. 3. A unit-test fixture directory of REAL old saves (one per version) asserting every historical save loads to the current model — the DemoDataTests pattern, pointed backwards. 4. Convention note in CLAUDE.md: additive nullable fields need no version bump; anything that reinterprets existing data does.

Cost is small now (one field + moving one existing migration behind an interface); it grows with every schema change we make before adopting it.

If you 👍 I'll open a PR (likely stacked on #244 since it touches LegacyMigrations).

Dependencies

None.

Comments

No comments.

Add a comment