diff --git a/Aetheria.State.Import/Program.cs b/Aetheria.State.Import/Program.cs index 56d3a7a7d..13a92c89e 100644 --- a/Aetheria.State.Import/Program.cs +++ b/Aetheria.State.Import/Program.cs @@ -47,7 +47,8 @@ ResetMaterializedStateOutput(statePath); await using var node = await AetheriaStateNode.OpenAsync(statePath, "aetheria-legacy-catalog-import"); -await node.PutLegacyCatalogQuarantineAsync(new AetheriaLegacyCatalogQuarantine +await node.MutableDocument(AetheriaStateNode.LegacyCatalogQuarantineKey) + .ReplaceAsync(new AetheriaLegacyCatalogQuarantine { RootPath = sourceRoot, CapturedAtUtc = capturedAtUtc, @@ -62,7 +63,8 @@ await node.PutLegacyCatalogQuarantineAsync(new AetheriaLegacyCatalogQuarantine ] }); -await node.PutMigrationLedgerAsync(new AetheriaMigrationLedger +await node.MutableDocument(AetheriaStateNode.MigrationLedgerKey) + .ReplaceAsync(new AetheriaMigrationLedger { Source = LegacyMigrationBoundary.LegacyGameDataFile, SourceFingerprint = catalog.Fingerprint, @@ -111,21 +113,30 @@ await node.PutMigrationLedgerAsync(new AetheriaMigrationLedger foreach (var item in itemDefinitions) { - await node.PutLegacyItemDefinitionAsync(item); + await node.MutableDocument(AetheriaCatalogKeys.ItemDefinitionFromLegacyId(item.LegacyId)) + .ReplaceAsync(item); } foreach (var corporation in corporations) { - await node.PutLegacyCorporationAsync(corporation); + await node.MutableDocument(AetheriaCatalogKeys.CorporationFromLegacyId(corporation.LegacyId)) + .ReplaceAsync(corporation); } foreach (var nameFile in parsedNameFiles) { - await node.PutLegacyNameFileAsync(nameFile); + await node.MutableDocument(AetheriaCatalogKeys.NameFileFromLegacyId(nameFile.LegacyId)) + .ReplaceAsync(nameFile); } +await node.FlushAsync(); var runtimeCatalog = await node.RuntimeCatalog().LatestAsync().ConfigureAwait(false); -await node.PutCatalogSurfaceAsync(AetheriaCatalogSurfaceProjector.Build(runtimeCatalog, capturedAtUtc)); +await node.MutableDocument(AetheriaStateNode.TradeValuePolicyKey) + .ReplaceAsync(AetheriaRuntimeStateMapper.ToTradeValuePolicy( + runtimeCatalog.TradeValueSettings, + capturedAtUtc)); +await node.FlushAsync(); +await node.CatalogSurface().LatestAsync().ConfigureAwait(false); await node.FlushAsync(); diff --git a/Aetheria.State.Verify/Program.cs b/Aetheria.State.Verify/Program.cs index 4a3544ba4..d4c117c84 100644 --- a/Aetheria.State.Verify/Program.cs +++ b/Aetheria.State.Verify/Program.cs @@ -110,8 +110,9 @@ var ledger = await node.MutableDocument(AetheriaStateNo ?? throw new InvalidOperationException("Missing typed migration ledger."); var quarantine = await node.MutableDocument(AetheriaStateNode.LegacyCatalogQuarantineKey).ReadAsync() ?? throw new InvalidOperationException("Missing legacy catalog quarantine document."); -var publishedSurface = await node.MutableDocument(AetheriaStateNode.CatalogSurfaceKey).ReadAsync() - ?? throw new InvalidOperationException("Missing Aetheria catalog Eve surface document."); +var publishedSurface = await node.CatalogSurface().LatestAsync().ConfigureAwait(false); +if (publishedSurface == null) + throw new InvalidOperationException("Missing managed Aetheria catalog Eve surface document."); var items = node.Cache.GetAll().ToArray(); var corporations = node.Cache.GetAll().ToArray(); @@ -11666,6 +11667,7 @@ static void RequireCatalogSurfaceUsesManagedRuntimeCatalog(string root) { var projectorPath = Path.Combine(root, "Aetheria.State", "AetheriaCatalogSurfaceProjector.cs"); var bridgePath = Path.Combine(root, "Aetheria.State", "AetheriaEveCommandBridge.cs"); + var importPath = Path.Combine(root, "Aetheria.State.Import", "Program.cs"); var legacySnapshotPath = Path.Combine(root, "Aetheria.State", "AetheriaCatalogSnapshot.cs"); var projector = File.Exists(projectorPath) ? File.ReadAllText(projectorPath) @@ -11673,6 +11675,9 @@ static void RequireCatalogSurfaceUsesManagedRuntimeCatalog(string root) var bridge = File.Exists(bridgePath) ? File.ReadAllText(bridgePath) : throw new InvalidOperationException("Cannot verify Eve command bridge catalog refresh; AetheriaEveCommandBridge.cs is missing."); + var import = File.Exists(importPath) + ? File.ReadAllText(importPath) + : throw new InvalidOperationException("Cannot verify legacy catalog import; Aetheria.State.Import/Program.cs is missing."); var requiredProjectorSymbols = new[] { @@ -11725,6 +11730,47 @@ static void RequireCatalogSurfaceUsesManagedRuntimeCatalog(string root) "Eve catalog refresh still rebuilds the legacy catalog snapshot instead of using AetheriaStateNode.RuntimeCatalog()."); } + var requiredImportSymbols = new[] + { + "node.MutableDocument(AetheriaStateNode.LegacyCatalogQuarantineKey)", + "node.MutableDocument(AetheriaStateNode.MigrationLedgerKey)", + "node.MutableDocument(AetheriaCatalogKeys.ItemDefinitionFromLegacyId(item.LegacyId))", + "node.MutableDocument(AetheriaCatalogKeys.CorporationFromLegacyId(corporation.LegacyId))", + "node.MutableDocument(AetheriaCatalogKeys.NameFileFromLegacyId(nameFile.LegacyId))", + "node.MutableDocument(AetheriaStateNode.TradeValuePolicyKey)", + "AetheriaRuntimeStateMapper.ToTradeValuePolicy(", + "await node.CatalogSurface().LatestAsync().ConfigureAwait(false);" + }; + var missingImportSymbols = requiredImportSymbols + .Where(symbol => !import.Contains(symbol, StringComparison.Ordinal)) + .ToArray(); + if (missingImportSymbols.Length > 0) + { + throw new InvalidOperationException( + "Legacy catalog import must write through managed typed document handles and materialize the managed catalog surface: " + + string.Join(", ", missingImportSymbols)); + } + + var forbiddenImportSymbols = new[] + { + "PutLegacyCatalogQuarantineAsync(", + "PutMigrationLedgerAsync(", + "PutLegacyItemDefinitionAsync(", + "PutLegacyCorporationAsync(", + "PutLegacyNameFileAsync(", + "PutTradeValuePolicyAsync(", + "PutCatalogSurfaceAsync(" + }; + var forbiddenImportHits = forbiddenImportSymbols + .Where(symbol => import.Contains(symbol, StringComparison.Ordinal)) + .ToArray(); + if (forbiddenImportHits.Length > 0) + { + throw new InvalidOperationException( + "Legacy catalog import still uses AetheriaStateNode Put helpers instead of managed typed documents: " + + string.Join(", ", forbiddenImportHits)); + } + Console.WriteLine("Catalog Eve surface: refresh path uses the managed runtime catalog document"); }