diff --git a/crates/format/src/lib.rs b/crates/format/src/lib.rs index d81da80e..208ec6c9 100644 --- a/crates/format/src/lib.rs +++ b/crates/format/src/lib.rs @@ -22,6 +22,8 @@ //! - **v3** (M10.2): graphic clips (`ItemKind::Graphic`, text/shape layers). The shape of older //! data is unchanged (no-op step); the bump makes builds without graphics refuse such files //! cleanly instead of failing to parse them. +//! - **v4** (M7.4): Essential Sound (clip audio types and settings, `EffectInstance::essential`). +//! No-op step; older builds would otherwise drop these fields silently when saving. pub mod atomic; pub mod autosave; @@ -40,7 +42,7 @@ pub type Migration = fn(Value) -> Result; /// `MIGRATIONS[i]` upgrades schema `i + 1` to `i + 2`. Append one function per schema bump; never /// edit a shipped one. -pub const MIGRATIONS: &[Migration] = &[v1_to_v2, v2_to_v3]; +pub const MIGRATIONS: &[Migration] = &[v1_to_v2, v2_to_v3, v3_to_v4]; /// The schema version this build writes (and the newest it reads). pub const SCHEMA_VERSION: u32 = MIGRATIONS.len() as u32 + 1; @@ -219,13 +221,18 @@ fn v2_to_v3(doc: Value) -> Result { Ok(doc) } +/// v3 → v4: Essential Sound fields added; existing data needs no change. +fn v3_to_v4(doc: Value) -> Result { + Ok(doc) +} + #[cfg(test)] mod tests { use super::*; #[test] fn schema_version_matches_table() { - assert_eq!(SCHEMA_VERSION, 3); + assert_eq!(SCHEMA_VERSION, 4); } #[test] diff --git a/docs/project-files.md b/docs/project-files.md index 9b6dfc6a..4da57a12 100644 --- a/docs/project-files.md +++ b/docs/project-files.md @@ -8,7 +8,7 @@ writing them is `crates/format` (`filmcraft-format`); the engine's `file.*` comm ```json { "format": "filmcraft.project", - "schema_version": 3, + "schema_version": 4, "generator": "FilmCraft 0.1.0", "project": { "name": "…", "settings": { … }, "root": { … }, "items": { … }, "next_id": 48 } } @@ -27,6 +27,7 @@ writing them is `crates/format` (`filmcraft-format`); the engine's `file.*` comm | 1 | M0 | the bare `Project` object with a `"version": 1` field | | 2 | M11.1 | the envelope above; the project's own `version` field is gone | | 3 | M10.2 | graphic clips (`ItemKind::Graphic` with text/shape layers); a no-op step for older data | +| 4 | M7.4 | Essential Sound: clip audio types and settings; no-op step | ### Migrations @@ -43,7 +44,8 @@ document; after the last one the result is deserialized into the current model. Fields added with `#[serde(default)]` don't need a migration: missing values take their defaults. But when new data would make the file unreadable to an older build (a new enum variant such as `ItemKind::Graphic`, a new required shape), bump the schema with a no-op step so older builds refuse -the file with the message below instead of failing with a parse error. +the file with the message below instead of failing with a parse error. Do the same when an older +build would load the file but silently drop new fields on its next save. When you open an older file FilmCraft says so ("Upgraded project from schema v1 to v2"). The file on disk is unchanged until you save. The **first save over it** keeps the original next to it as @@ -53,8 +55,8 @@ on disk is unchanged until you save. The **first save over it** keeps the origin A file with a `schema_version` newer than the build supports is **refused**, not half-read: -> this project was saved by a newer version of FilmCraft (project schema v4); this build reads up to -> v3. Update FilmCraft to open it. +> this project was saved by a newer version of FilmCraft (project schema v5); this build reads up to +> v4. Update FilmCraft to open it. Reading it partially and saving it back would silently drop whatever the newer version added.