fix(F8): session schema versioning with migration hook + corruption diag - #83
Merged
Conversation
Track F-HIGH #8 from ROADMAP.md. ## Problem `load_session` (`storage.rs:98-104`) deserialized raw JSON with no schema versioning. Two pain points: 1. **Corrupted files** (truncated mid-write before atomic save shipped, or external mutation) surfaced as `expected ',' or '}' at line N column M` with no file path. A user with many sessions had to grep to figure out which one was broken. 2. **No migration path** for future schema bumps. Field additions so far used `#[serde(default)]` so they migrated transparently, but a real shape change (renaming a field, restructuring `tree.entries`) would silently corrupt old sessions on first load with no way to detect. ## Fix `Session` gains `pub schema_version: u32` with `#[serde(default)]` so pre-F8 files load with `schema_version = 0`. `Session::new` sets it to the current `SCHEMA_VERSION` constant (initial value: 1 — first versioned schema). `load_session` now: 1. Wraps the parse error with `path.display()` context so the user sees `failed to parse <path>: <serde error>`. 2. After successful deserialize, compares `session.schema_version` against `SCHEMA_VERSION`: - Lower → call `migrate_session(&mut session)` then bump. - Equal → no-op. - Higher (file from newer dirge) → warn via tracing but still load. Most fields default-migrate via serde; only truly new fields get default values. `migrate_session` is a single function with version gates ready for future schema work. The v0 → v1 step is a no-op (current schema is structurally identical to pre-F8; only the field introduction marks the version). ## Tests Two new tests in `session::storage::tests`: - `load_session_migrates_pre_f8_files`: writes a minimal pre-F8 session JSON (no schema_version field) to disk, loads it, asserts schema_version is bumped to SCHEMA_VERSION and the data is intact. - `load_session_corrupted_file_includes_path_in_error`: writes a truncated JSON, asserts the error mentions the path so the user can grep `dirge` logs and identify the broken file. 664 pass (was 662). All build profiles clean.
allen-munsch
pushed a commit
to allen-munsch/dirge
that referenced
this pull request
Jun 3, 2026
…iag (dirge-code#83) Track F-HIGH dirge-code#8 from ROADMAP.md. ## Problem `load_session` (`storage.rs:98-104`) deserialized raw JSON with no schema versioning. Two pain points: 1. **Corrupted files** (truncated mid-write before atomic save shipped, or external mutation) surfaced as `expected ',' or '}' at line N column M` with no file path. A user with many sessions had to grep to figure out which one was broken. 2. **No migration path** for future schema bumps. Field additions so far used `#[serde(default)]` so they migrated transparently, but a real shape change (renaming a field, restructuring `tree.entries`) would silently corrupt old sessions on first load with no way to detect. ## Fix `Session` gains `pub schema_version: u32` with `#[serde(default)]` so pre-F8 files load with `schema_version = 0`. `Session::new` sets it to the current `SCHEMA_VERSION` constant (initial value: 1 — first versioned schema). `load_session` now: 1. Wraps the parse error with `path.display()` context so the user sees `failed to parse <path>: <serde error>`. 2. After successful deserialize, compares `session.schema_version` against `SCHEMA_VERSION`: - Lower → call `migrate_session(&mut session)` then bump. - Equal → no-op. - Higher (file from newer dirge) → warn via tracing but still load. Most fields default-migrate via serde; only truly new fields get default values. `migrate_session` is a single function with version gates ready for future schema work. The v0 → v1 step is a no-op (current schema is structurally identical to pre-F8; only the field introduction marks the version). ## Tests Two new tests in `session::storage::tests`: - `load_session_migrates_pre_f8_files`: writes a minimal pre-F8 session JSON (no schema_version field) to disk, loads it, asserts schema_version is bumped to SCHEMA_VERSION and the data is intact. - `load_session_corrupted_file_includes_path_in_error`: writes a truncated JSON, asserts the error mentions the path so the user can grep `dirge` logs and identify the broken file. 664 pass (was 662). All build profiles clean. Co-authored-by: Yogthos <yogthos@gmail.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Track F-HIGH #8.
Sessiongainsschema_version: u32with serde default 0 for pre-F8 files.load_sessionrunsmigrate_sessionon version-lower files, warns on version-higher, and wraps corrupted-JSON errors with the file path so users can identify which session is broken. 2 new tests, 664 pass.