@@ -65,7 +65,10 @@ classDiagram
6565
6666 class UserFMUDirectory
6767
68- class CacheManager
68+ class CacheManager {
69+ +get_revision_content(..., migration_manager)
70+ +restore_revision(..., migration_manager)
71+ }
6972 class LockManager {
7073 +acquire()
7174 +ensure_can_write()
@@ -75,12 +78,20 @@ classDiagram
7578 }
7679
7780 class PydanticResourceManager~PydanticResource~ {
81+ +migration_manager
7882 +load(force, store_cache)
7983 +save(model)
8084 +get_resource_diff(incoming_resource)
8185 +get_structured_model_diff(current_model, incoming_model)
8286 }
8387
88+ class MigrationManager~MigratableResource~ {
89+ +model_class
90+ +current_version: int
91+ +migrate_resource(data)
92+ +requires_migration(data)
93+ }
94+
8495 class MutablePydanticResourceManager~MutablePydanticResource~ {
8596 +get(key, default)
8697 +set(key, value)
@@ -129,6 +140,8 @@ classDiagram
129140
130141 FMUDirectoryBase *-- LockManager
131142 FMUDirectoryBase *-- CacheManager
143+ PydanticResourceManager o-- MigrationManager
144+ CacheManager ..> MigrationManager
132145 ProjectFMUDirectory *-- ProjectConfigManager
133146 ProjectFMUDirectory *-- ChangelogManager
134147 ProjectFMUDirectory *-- MappingsManager
@@ -140,10 +153,53 @@ The main library split is:
140153- ` FMUDirectoryBase ` is the filesystem-centered abstraction. It owns the ` .fmu ` path, lock manager, cache manager, and generic read/write helpers.
141154- ` ProjectFMUDirectory ` and ` UserFMUDirectory ` specialize the base class for project-local ` .fmu/ ` directories and ` $HOME/.fmu/ ` .
142155- ` PydanticResourceManager ` is the generic resource engine for loading, saving, diffing, and caching JSON-backed Pydantic models.
156+ - ` MigrationManager ` applies registered, forward-only schema migrations and validates the result as the current Pydantic model.
143157- ` MutablePydanticResourceManager ` adds dot-notation ` get ` , ` set ` , ` update ` , ` reset ` , and merge behavior for editable resources.
144158- ` ProjectConfigManager ` , ` UserConfigManager ` , ` MappingsManager ` , and ` LogManager ` bind specific Pydantic models to managed files inside ` .fmu/ ` .
145159- Directory objects compose the correct managers and delegate resource operations to them.
146160
161+ ## Schema Migration
162+
163+ ` ProjectConfig ` , ` UserConfig ` , and ` InternalMappings ` are versioned resources. Each
164+ model declares its current schema version, and each resource manager has a
165+ ` MigrationManager ` with the migration registry for that model.
166+
167+ Migration is forward-only. Data without ` schema_version ` is treated as version 1.
168+ Each registered migration function increments the schema version by one. The manager
169+ rejects a newer schema, a missing migration step, an invalid version, or data that
170+ does not validate as the current model.
171+
172+ The migration boundary depends on the resource operation:
173+
174+ - ** Load:** ` PydanticResourceManager ` decodes the stored JSON and asks
175+ ` MigrationManager ` for a validated current model. Migration happens in memory.
176+ Loading does not write the resource, create a cache revision, or add a changelog
177+ entry.
178+ - ** Save:** The resource manager checks the write lock first. If the stored data is
179+ older, it attempts to store the exact original JSON under
180+ ` .fmu/migration-backups/ ` before writing the current model. This backup is
181+ best-effort: a file-system failure is logged and does not stop the save. The
182+ original JSON is also stored as a cache revision. The newly written current
183+ data is added as another cache revision.
184+ - ** Cache read:** ` CacheManager ` uses the migration manager to return old revisions
185+ as current validated models.
186+ - ** Restore:** ` CacheManager ` migrates the selected revision before writing it, so
187+ the restored resource uses the current schema. If you roll back to an older
188+ release while the pre-migration revision is still retained, restore that revision with
189+ the older release to return the resource file to the older schema. Project restore
190+ operations use the existing restore changelog entry.
191+
192+ There is no backward migration. After a current-schema resource is saved, an older
193+ ` fmu-settings ` release can reject it as newer than supported. If the pre-migration
194+ cache revision is still retained, restore it with the older release. Migration
195+ backups are not loaded or restored by the library. If the cache revision is no longer
196+ available, we should help users copy the appropriate migration backup back to the
197+ resource file before running the older release.
198+
199+ See the
200+ [ schema migration guide] ( src/fmu/settings/_migrations/README.md )
201+ for the implementation, test, and coordinated release process.
202+
147203## Runtime Flow
148204
149205The full runtime spans multiple repositories, but ` fmu-settings ` owns the ` .fmu/ ` directory operations used by the API and CLI.
0 commit comments