diff --git a/Aetheria.State.Import/Program.cs b/Aetheria.State.Import/Program.cs index d6f308004..368461301 100644 --- a/Aetheria.State.Import/Program.cs +++ b/Aetheria.State.Import/Program.cs @@ -210,7 +210,10 @@ if (args.Any(argument => string.Equals(argument, "--merge-station-sensor", Strin ResetMaterializedStateOutput(statePath); -await using var node = await AetheriaStateNode.OpenAsync(statePath, "aetheria-legacy-catalog-import"); +await using var node = await AetheriaStateNode.OpenAsync( + statePath, + "aetheria-legacy-catalog-import", + useDirectoryStore: false); await node.MutableDocument(AetheriaStateNode.LegacyCatalogQuarantineKey) .ReplaceAsync(new AetheriaLegacyCatalogQuarantine diff --git a/Aetheria.State.Verify/Program.cs b/Aetheria.State.Verify/Program.cs index d65206b86..b8c590ac6 100644 --- a/Aetheria.State.Verify/Program.cs +++ b/Aetheria.State.Verify/Program.cs @@ -8,6 +8,13 @@ var root = args.Length > 0 ? Path.GetFullPath(args[0]) : Directory.GetCurrentDir var statePath = args.Length > 1 ? Path.GetFullPath(args[1]) : AetheriaStatePaths.ResolveDefaultStatePath(root); +var verificationDirectory = Path.Combine( + Path.GetTempPath(), + "aetheria-state-verify", + Guid.NewGuid().ToString("N")); +Directory.CreateDirectory(verificationDirectory); +var verificationStatePath = Path.Combine(verificationDirectory, "aetheria-world.cc"); +File.Copy(statePath, verificationStatePath, overwrite: true); RequireGameplaySourcePurity(root); RequireManagedContentOnlyAssetDelivery(root); @@ -111,7 +118,7 @@ RequireAuthoritySmokeUsesManagedPointers(root); RequireAetheriaStateNodeUsesManagedPointers(root); await using var node = await AetheriaStateNode.OpenAsync( - statePath, + verificationStatePath, "aetheria-state-verify", enableDurableShardLogs: false); diff --git a/Aetheria.State/AetheriaStateNode.cs b/Aetheria.State/AetheriaStateNode.cs index 719f24888..9a624465c 100644 --- a/Aetheria.State/AetheriaStateNode.cs +++ b/Aetheria.State/AetheriaStateNode.cs @@ -41,7 +41,8 @@ public sealed class AetheriaStateNode : IAsyncDisposable, IDisposable string statePath, string runtimeId = "aetheria-local", bool startServer = false, - bool enableDurableShardLogs = true) + bool enableDurableShardLogs = true, + bool useDirectoryStore = true) { if (string.IsNullOrWhiteSpace(statePath)) { @@ -62,7 +63,7 @@ public sealed class AetheriaStateNode : IAsyncDisposable, IDisposable Registry = cacheRegistry, PullOnOpen = true, StoreFlushOnDispose = true, - UseDirectoryStore = true + UseDirectoryStore = useDirectoryStore }, DatabaseOptions = new CultNetDatabaseOptions { diff --git a/Aetheria.State/README.md b/Aetheria.State/README.md index 9cf052db4..f52816ba8 100644 --- a/Aetheria.State/README.md +++ b/Aetheria.State/README.md @@ -10,8 +10,10 @@ The first live state files are `GameData/aetheria-world.cc` for daemon-owned Verse state and `GameData/aetheria-client.cc` for the client-owned active Verse target. `Aetheria.State.Import` generates the daemon-owned world file from checked-in legacy catalog inputs without embedding machine-local absolute -paths. Legacy files such as `GameData/AetherDB.msgpack` are migration inputs -only. +paths. A full import emits one self-contained monolithic `.cc` suitable for a +fresh clone or released package. Runtime-created `.cc.records` directories are +mutable materializations, not part of the release contract. Legacy files such +as `GameData/AetherDB.msgpack` are migration inputs only. The typed runtime state model is split into player settings, loadout templates, run state, zone state, entity snapshots, item slots, weapon groups, action-bar @@ -304,8 +306,10 @@ Legacy GUID references that are `Guid.Empty` are imported as absent references, not as resolvable catalog links. Before materializing state, the importer clears the generated `.cc`, `.cc.records`, and `.cultmesh` outputs for the selected state path. Legacy -catalog inputs are captured first and are not deleted. This lets schema changes -rebuild the typed artifact instead of failing on a stale embedded schema catalog. +catalog inputs are captured first and are not deleted. Full import writes the +result through the monolithic CultCache store; no ignored directory record may +be required to open the artifact. This lets schema changes rebuild the typed +artifact instead of failing on a stale embedded schema catalog. `AetheriaCatalogSnapshot` is the typed read surface over materialized catalog documents. It exposes trade items, legacy-ID migration lookup, typed diff --git a/GameData/aetheria-world.cc b/GameData/aetheria-world.cc index e90d99016..4efce55d2 100644 Binary files a/GameData/aetheria-world.cc and b/GameData/aetheria-world.cc differ diff --git a/GameData/aetheria-world.cc.records/3b2b177b2026aebdedd310fee6758e1bc3db30612209f3b763607a4dfd231f4d.msgpack b/GameData/aetheria-world.cc.records/3b2b177b2026aebdedd310fee6758e1bc3db30612209f3b763607a4dfd231f4d.msgpack deleted file mode 100644 index d1bf0cf4f..000000000 --- a/GameData/aetheria-world.cc.records/3b2b177b2026aebdedd310fee6758e1bc3db30612209f3b763607a4dfd231f4d.msgpack +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:784b46a94de4b1af13f0ca52f72ee3d38e7a15714acb51987aafd170a4711d6b -size 3529 diff --git a/README.md b/README.md index d9e3d32c4..52f87b43d 100644 --- a/README.md +++ b/README.md @@ -144,7 +144,7 @@ The state spine lives in `Aetheria.State`. It defines CultCache documents, CultN Use `Aetheria.State.Import` to quarantine the checked-in legacy catalog files and map stable MessagePack payload fields into typed CultCache state. The importer records path, size, and SHA-256 provenance for `GameData/AetherDB.msgpack` and `GameData/NameFile/*.msgpack`, then emits typed item, faction, and name-file records for the fields that have earned migration authority. -Use `Aetheria.State.Verify` after import to prove the materialized `.cc` file is internally coherent: migration-ledger counts must match actual typed catalog records, and legacy-ID lookups must resolve through `Aetheria.State` rather than importer-local key strings. +Use `Aetheria.State.Verify` after import to prove the materialized `.cc` file is internally coherent and self-contained. Verification opens a temporary copy of the tracked monolith, so ignored `.cc.records` files cannot accidentally satisfy the proof. Migration-ledger counts must match actual typed catalog records, and legacy-ID lookups must resolve through `Aetheria.State` rather than importer-local key strings. #### Editing Items diff --git a/docs/aetheria-perfect-machine-map.md b/docs/aetheria-perfect-machine-map.md index cbd7f00dd..93e7b2fa8 100644 --- a/docs/aetheria-perfect-machine-map.md +++ b/docs/aetheria-perfect-machine-map.md @@ -526,9 +526,12 @@ legacy catalog cache, and legacy UI paths should be migration-only or deleted. - `Aetheria.State.Import` writes a typed quarantine manifest and migration ledger for the legacy catalog files. It also raw-decodes stable old MessagePack union fields into typed item/faction/name-file documents without - compiling the old Unity domain model into `Aetheria.State`. The current - checked-in catalog maps to 115 item definitions, 12 factions, and 12 name - files. Item definitions now carry legacy manufacturer IDs, price, shape + compiling the old Unity domain model into `Aetheria.State`. A full import + writes those documents into one monolithic, tracked `.cc`; ignored + `.cc.records` directories are runtime materializations and cannot be required + to open a fresh clone. The current checked-in catalog maps to 116 item + definitions, 12 factions, and 12 name files. Item definitions now carry + legacy manufacturer IDs, price, shape dimensions, occupied cell counts, full typed shape-cell masks, hardpoint type, hull type, interior shape masks for hull/cargo equipment, hull hardpoint definitions, behavior kind fingerprints, typed recursive behavior @@ -630,7 +633,8 @@ legacy catalog cache, and legacy UI paths should be migration-only or deleted. can redirect/disable the mount for diagnostics. Batchmode disables the bootstrap so verification runs do not create renderer state. - `GameData/aetheria-world.cc` is now materialized from the importer as the - project-local typed state file for the checked-in catalog. The importer stores + self-contained project-local typed state file for the checked-in catalog. The + importer stores relative provenance in the state document, not machine-local absolute paths. Unity resolves this path through the embedded `GameCult.Aetheria.State.Unity` runtime package, not through the legacy catalog boundary. Unity also asks the @@ -638,10 +642,13 @@ legacy catalog cache, and legacy UI paths should be migration-only or deleted. warning is notification-only and does not make legacy catalog data the typed state owner. Import rebuilds clear the generated `.cc`, `.cc.records`, and `.cultmesh` - outputs for the selected state path after capturing legacy inputs, so schema - evolution can rematerialize typed state instead of being blocked by stale - embedded schema catalogs. - `Aetheria.State.Verify` opens the materialized file and checks that migration + outputs for the selected state path after capturing legacy inputs, then writes + the release artifact with the monolithic store. Schema evolution can + rematerialize typed state instead of being blocked by stale embedded schema + catalogs. Mutable runtime nodes may materialize their private directory-store + overlay after deployment; that overlay is never release authority. + `Aetheria.State.Verify` copies the tracked monolith into a fresh temporary + directory before opening it and checks that migration ledger counts match actual typed catalog records, that name-file v2 records carry their full name arrays, that the legacy-ID lookup API resolves migrated item, corporation, and name-file documents, and that the expanded typed