From a204a4e63bb67b996db040b147bf3f3be6efbc14 Mon Sep 17 00:00:00 2001 From: Meta Vens Date: Sun, 28 Jun 2026 08:38:37 +0100 Subject: [PATCH] Name catalog store reads as managed state bootstrap --- Aetheria.State.Verify/Program.cs | 42 +++++++++++++-- .../Runtime/AetheriaRuntimeVerseClient.cs | 51 +++++++++++-------- 2 files changed, 66 insertions(+), 27 deletions(-) diff --git a/Aetheria.State.Verify/Program.cs b/Aetheria.State.Verify/Program.cs index d3c70add6..492e967f8 100644 --- a/Aetheria.State.Verify/Program.cs +++ b/Aetheria.State.Verify/Program.cs @@ -10287,10 +10287,12 @@ static void RequireAetheriaRuntimeVerseClientContract(string root) "AetheriaRuntimeLoadoutTemplatesDocument", "ProjectStarbridgeSummaryAsync", "var catalog = await catalogDocument.LatestAsync().ConfigureAwait(false);", - "ReadRuntimeCatalogSnapshot()", - "ReadLoadoutTemplatesDocument()", - "ReadPlayerSettingsDocument()", - "ReadVerseHostSettingsDocument()", + "BootstrapCatalogDocument(", + "CatalogBootstrapSource(", + "BootstrapRuntimeCatalogSnapshot()", + "BootstrapLoadoutTemplatesDocument()", + "BootstrapPlayerSettingsDocument()", + "BootstrapVerseHostSettingsDocument()", "SubmitDaemonCommandAsync(", "SubmitEveCommandAsync(", "AetheriaRuntimeVerseRecordKeys.DaemonCommand(command.CommandId)", @@ -10402,16 +10404,46 @@ static void RequireAetheriaRuntimeVerseClientContract(string root) ? client.Substring(starbridgeSummaryStart, indexedDocumentStart - starbridgeSummaryStart) : client.Substring(starbridgeSummaryStart); if (!starbridgeSummaryBlock.Contains("var catalog = await catalogDocument.LatestAsync().ConfigureAwait(false);", StringComparison.Ordinal) || - starbridgeSummaryBlock.Contains("ReadRuntimeCatalogSnapshot()", StringComparison.Ordinal)) + starbridgeSummaryBlock.Contains("BootstrapRuntimeCatalogSnapshot()", StringComparison.Ordinal) || + starbridgeSummaryBlock.Contains("AetheriaRuntimeCatalogStore.OpenReadOnly", StringComparison.Ordinal)) { throw new InvalidOperationException( "Starbridge summary projection must use the managed runtime catalog document instead of reopening the catalog store."); } + var requiredClientBootstrapSymbols = new[] + { + "BootstrapCatalogDocument(", + "CatalogBootstrapSource(", + "legacy catalog store bootstrap seed for managed Aetheria state", + "BootstrapRuntimeCatalogSnapshot()", + "BootstrapLoadoutTemplatesDocument()", + "BootstrapPlayerSettingsDocument()", + "BootstrapVerseHostSettingsDocument()" + }; + var missingClientBootstrapSymbols = requiredClientBootstrapSymbols + .Where(symbol => !client.Contains(symbol, StringComparison.Ordinal)) + .ToArray(); + if (missingClientBootstrapSymbols.Length > 0) + { + throw new InvalidOperationException( + "AetheriaRuntimeVerseClient must name catalog/settings file reads as bootstrap seeds for managed documents: " + + string.Join(", ", missingClientBootstrapSymbols)); + } + var forbiddenClientCompatibilityStoreBypasses = new[] { "return Task.FromResult(AetheriaRuntimeCatalogStore.ReadPlayerSettings(StatePath));", "return Task.FromResult(AetheriaRuntimeCatalogStore.ReadVerseHostSettings(StatePath));", + "ReadRuntimeCatalogSnapshot()", + "ReadLoadoutTemplatesDocument()", + "ReadPlayerSettingsDocument()", + "ReadVerseHostSettingsDocument()", + "var catalogDocument = CatalogDocument(", + "var loadoutTemplatesDocument = CatalogDocument(", + "CultMeshDocumentHandle CatalogDocument(", + "projected Aetheria catalog document", + "Aetheria typed catalog state", "public async Task GetProviderAdvertisementAsync()", "public async Task GetHealthAsync()", "public async Task GetCommandBoundaryAsync()", diff --git a/Packages/org.gamecult.aetheria.state/Runtime/AetheriaRuntimeVerseClient.cs b/Packages/org.gamecult.aetheria.state/Runtime/AetheriaRuntimeVerseClient.cs index b88ebff9c..d7b773cd8 100644 --- a/Packages/org.gamecult.aetheria.state/Runtime/AetheriaRuntimeVerseClient.cs +++ b/Packages/org.gamecult.aetheria.state/Runtime/AetheriaRuntimeVerseClient.cs @@ -528,16 +528,16 @@ namespace GameCult.Aetheria.State.Verse var frameChanges = WatchLatestFrames() .Where(change => change.Document != null) .Select(change => change.Document!); - var catalogDocument = CatalogDocument( + var catalogDocument = BootstrapCatalogDocument( "aetheria.catalog.runtime", - () => Task.FromResult(ReadRuntimeCatalogSnapshot()), + () => Task.FromResult(BootstrapRuntimeCatalogSnapshot()), AetheriaRuntimeCatalogSnapshot.SchemaId, - CultMesh.ProjectionSource("catalog:aetheria.runtime")); - var loadoutTemplatesDocument = CatalogDocument( + CatalogBootstrapSource("catalog:aetheria.runtime")); + var loadoutTemplatesDocument = BootstrapCatalogDocument( "aetheria.catalog.loadout_templates", - () => Task.FromResult(ReadLoadoutTemplatesDocument()), + () => Task.FromResult(BootstrapLoadoutTemplatesDocument()), AetheriaRuntimeLoadoutTemplatesDocument.SchemaId, - CultMesh.ProjectionSource("catalog:aetheria.loadout_templates")); + CatalogBootstrapSource("catalog:aetheria.loadout_templates")); var starbridgeScenarioDocument = Document( AetheriaRuntimeVerseRecordKeys.StarbridgeScenarioLatest); var starbridgeSessionDocument = Document( @@ -566,16 +566,16 @@ namespace GameCult.Aetheria.State.Verse AetheriaRuntimeVerseRecordKeys.DaemonEditorTuiSurface), catalogDocument, loadoutTemplatesDocument, - CatalogDocument( + BootstrapCatalogDocument( "aetheria.settings.player", - () => Task.FromResult(ReadPlayerSettingsDocument()), + () => Task.FromResult(BootstrapPlayerSettingsDocument()), AetheriaRuntimePlayerSettingsDocument.SchemaId, - CultMesh.ProjectionSource("catalog:aetheria.player_settings")), - CatalogDocument( + CatalogBootstrapSource("catalog:aetheria.player_settings")), + BootstrapCatalogDocument( "aetheria.settings.verse_host", - () => Task.FromResult(ReadVerseHostSettingsDocument()), + () => Task.FromResult(BootstrapVerseHostSettingsDocument()), AetheriaRuntimeVerseHostSettingsDocument.SchemaId, - CultMesh.ProjectionSource("catalog:aetheria.verse_host_settings")), + CatalogBootstrapSource("catalog:aetheria.verse_host_settings")), ProjectedDocument( "aetheria.current.zone", frame => Task.FromResult(AetheriaRuntimeRtsProjection.ProjectCurrentZone(frame)), @@ -676,27 +676,27 @@ namespace GameCult.Aetheria.State.Verse routeHint: new CultMeshRouteHint(CultMeshLocalityKind.SharedMemory, "Aetheria typed projected state")); } - CultMeshDocumentHandle CatalogDocument( + CultMeshDocumentHandle BootstrapCatalogDocument( string documentId, - Func> project, + Func> bootstrap, string schemaId, params CultMeshProjectionSource[] additionalSources) where TDocument : class { var sources = (additionalSources ?? Array.Empty()) - .Append(CultMesh.ProjectionSource(documentId, schemaId, "projected Aetheria catalog document")) + .Append(CultMesh.ProjectionSource(documentId, schemaId, "managed Aetheria catalog document")) .ToArray(); var verse = CultMesh.Verse("aetheria.local", RuntimeId); return CultMesh.Document( documentId, verse, - async _ => await project().ConfigureAwait(false), + async _ => await bootstrap().ConfigureAwait(false), _ => frameChanges .SelectAwait(async (_, cancellationToken) => - await project().ConfigureAwait(false)), + await bootstrap().ConfigureAwait(false)), sources: sources, - routeHint: new CultMeshRouteHint(CultMeshLocalityKind.SharedMemory, "Aetheria typed catalog state")); + routeHint: new CultMeshRouteHint(CultMeshLocalityKind.SharedMemory, "Aetheria managed catalog state")); } async Task ProjectStationRefitAsync( @@ -769,24 +769,31 @@ namespace GameCult.Aetheria.State.Verse }); } - private AetheriaRuntimeCatalogSnapshot ReadRuntimeCatalogSnapshot() + private static CultMeshProjectionSource CatalogBootstrapSource(string sourceId) + { + return CultMesh.ProjectionSource( + sourceId, + description: "legacy catalog store bootstrap seed for managed Aetheria state"); + } + + private AetheriaRuntimeCatalogSnapshot BootstrapRuntimeCatalogSnapshot() { return AetheriaRuntimeCatalogStore.OpenReadOnly(StatePath); } - private AetheriaRuntimeLoadoutTemplatesDocument ReadLoadoutTemplatesDocument() + private AetheriaRuntimeLoadoutTemplatesDocument BootstrapLoadoutTemplatesDocument() { return new AetheriaRuntimeLoadoutTemplatesDocument( AetheriaRuntimeCatalogStore.ReadLoadoutTemplates(StatePath)); } - private AetheriaRuntimePlayerSettingsDocument ReadPlayerSettingsDocument() + private AetheriaRuntimePlayerSettingsDocument BootstrapPlayerSettingsDocument() { return AetheriaRuntimePlayerSettingsDocument.FromSnapshot( AetheriaRuntimeCatalogStore.ReadPlayerSettings(StatePath)); } - private AetheriaRuntimeVerseHostSettingsDocument ReadVerseHostSettingsDocument() + private AetheriaRuntimeVerseHostSettingsDocument BootstrapVerseHostSettingsDocument() { return AetheriaRuntimeVerseHostSettingsDocument.FromSnapshot( AetheriaRuntimeCatalogStore.ReadVerseHostSettings(StatePath));