hoangsonww / hoangsonww/Diffuse-Native-Apps
Add schema-v2 migration path so old snapshots survive a breaking model change
- Dominant language
- Swift
- Stars
- 2
- Forks
- 0
- Avg merge
- 1h 53m
- Merged PRs (30d)
- 14
Description
## Motivation
Every snapshot carries `schemaVersion` (`Snapshot.swift:154`) and `SchemaVersion.current`, and ADR 0003 promises that a snapshot stays readable long after the app that wrote it. But nothing in the tree actually *acts* on that field: there is no migrator, no version branch in `SnapshotCoding`, and no test that decodes a v1 snapshot under a v2 model. The version is recorded and then ignored.
The first genuinely breaking model change — renaming a property key, changing a `PropertyValue` case, altering identity semantics — will therefore silently fail to decode, and a user's entire local history becomes unreadable. There is no cloud copy to fall back on ([ADR 0008](Documentation/adr/0008-no-cloud-sync.md)), so this is permanent data loss on a local-first product.
## Proposed Solution
Introduce a `SnapshotMigrator` in `DiffuseModels` that maps an older `SchemaVersion` payload forward to `.current` before decoding into the typed model. `SnapshotCoding.decode` reads `schemaVersion` first, runs the migration chain (v1 → v2 → …), then decodes. Migrations are pure functions over `[String: Any]`/`JSONValue`, registered in an ordered table so each new version adds one step rather than editing the decoder.
Mirror the same chain in the Kotlin engine (`Android/app/src/main/java/com/diffuse/android/domain/Models.kt`) so both families stay on the fixture contract from [ADR 0009](Documentation/adr/0009-native-android.md).
## Acceptance Criteria
- [ ] `SnapshotMigrator` exists with an ordered, testable chain keyed by `SchemaVersion`
- [ ] `SnapshotCoding.decode` reads `schemaVersion` before decoding and migrates when it is older than `.current`
- [ ] Decoding a snapshot from a *newer* schema fails with a clear, actionable error rather than a generic `DecodingError`
- [ ] A frozen v1 fixture is committed and a test proves it still decodes and diffs correctly after a synthetic v2 bump
- [ ] The Kotlin engine performs the equivalent migration, proven by `FixtureCompatibilityTest`
- [ ] `Documentation/SnapshotSchema.md` documents how to add a migration step
## Additional Context
Related: `Fixtures/snapshots/`, `Documentation/adr/0003-schema-driven-diff.md`. The golden fixtures are the natural regression net here — do not weaken them.
Contributor guide
Assessment
This issue has not been assessed yet.