diff --git a/Aetheria.State.Verify/Program.cs b/Aetheria.State.Verify/Program.cs index 8c080806e..a152e08c5 100644 --- a/Aetheria.State.Verify/Program.cs +++ b/Aetheria.State.Verify/Program.cs @@ -13491,23 +13491,38 @@ static void RequireRuntimeStateReaderOwnsUnityStateAcquisition(string root) string.Join(", ", missingDaemonStateFacadeSymbols)); } - var requiredManagedClientAccessSymbols = new[] + var requiredManagedClientConnectionSymbols = new[] { "public AetheriaClientState State => _state;", - "public AetheriaClientState Aetheria() => State;", - "public CultMeshDocumentHandle Document()", - "public Task LatestAsync()", - "public Observable Watch()", - "public CultMeshReactiveDocument Reactive(" + "public AetheriaClientState Aetheria() => State;" }; - var missingManagedClientAccessSymbols = requiredManagedClientAccessSymbols + var missingManagedClientConnectionSymbols = requiredManagedClientConnectionSymbols .Where(symbol => !aetheriaClient.Contains(symbol, StringComparison.Ordinal)) .ToArray(); - if (missingManagedClientAccessSymbols.Length > 0) + if (missingManagedClientConnectionSymbols.Length > 0) { throw new InvalidOperationException( - "AetheriaClient must expose managed typed document access instead of document-specific compatibility readers: " + - string.Join(", ", missingManagedClientAccessSymbols)); + "AetheriaClient must expose the managed state object without owning document-catalog shortcuts: " + + string.Join(", ", missingManagedClientConnectionSymbols)); + } + + var requiredManagedStateAccessSymbols = new[] + { + "public CultMeshDocumentHandle Document()", + "public ICultMeshDocumentHandle DocumentBySchema(string schemaVersion)", + "public Task LatestAsync()", + "public Observable Watch()", + "public Task> ReactiveAsync(", + "public CultMeshReactiveDocument Reactive(" + }; + var missingManagedStateAccessSymbols = requiredManagedStateAccessSymbols + .Where(symbol => !aetheriaClientState.Contains(symbol, StringComparison.Ordinal)) + .ToArray(); + if (missingManagedStateAccessSymbols.Length > 0) + { + throw new InvalidOperationException( + "AetheriaClientState must expose managed typed document access instead of AetheriaClient forwarding shortcuts: " + + string.Join(", ", missingManagedStateAccessSymbols)); } var requiredObservedDaemonStateSymbols = new[] @@ -13576,7 +13591,13 @@ static void RequireRuntimeStateReaderOwnsUnityStateAcquisition(string root) "public async Task DaemonEditorSurfaceAsync()", "public async Task DaemonEditorTuiSurfaceAsync()", "public Func CreateEveSurfaceStateRefResolver()", - "public CultMeshStateRefResolver CreateEveSurfaceCultMeshStateRefResolver()" + "public CultMeshStateRefResolver CreateEveSurfaceCultMeshStateRefResolver()", + "public CultMeshDocumentHandle Document()", + "public ICultMeshDocumentHandle DocumentBySchema(string schemaVersion)", + "public Task LatestAsync()", + "public Observable Watch()", + "public Task> ReactiveAsync(", + "public CultMeshReactiveDocument Reactive(" }; var daemonClientBypassHits = forbiddenDaemonClientBypassSymbols .Where(symbol => aetheriaClient.Contains(symbol, StringComparison.Ordinal)) diff --git a/Aetheria.State/docs/cultmesh-ergonomics-staged-migration-plan.md b/Aetheria.State/docs/cultmesh-ergonomics-staged-migration-plan.md index 8d1c27de7..8dc8a9a15 100644 --- a/Aetheria.State/docs/cultmesh-ergonomics-staged-migration-plan.md +++ b/Aetheria.State/docs/cultmesh-ergonomics-staged-migration-plan.md @@ -351,7 +351,7 @@ Work: Gates: - `InventoryMenu`, `InventoryPanel`, `TradeMenu`, `LocalMenu`, `SchematicDisplay`, `SectorRenderer`, `MapRenderer`, and `ZoneRenderer` do not manually join state projections to obtain domain values. -- Shared projected documents are reachable through `client.Aetheria().Document()`, including same-schema CLR aliases, `client.Aetheria().DocumentBySchema(schemaVersion)`, `client.Aetheria().LatestAsync()`, and `client.Watch()`; the underlying type/schema lookup is delegated to CultMesh rather than an Aetheria-owned schema registry. +- Shared projected documents are reachable through `client.Aetheria().Document()`, including same-schema CLR aliases, `client.Aetheria().DocumentBySchema(schemaVersion)`, `client.Aetheria().LatestAsync()`, and `client.Aetheria().Watch()`; the underlying type/schema lookup is delegated to CultMesh rather than an Aetheria-owned schema registry. - Client-facing code contains no `_observedFacadeIndex.TryResolve*` outside Unity render adapter internals. - Client-facing code contains no `ResolveClient().Current*Async().GetAwaiter().GetResult()` or equivalent blocking state reads. - `TryGetTypedCurrentDockingBayFacade` and similar transitional helpers are deleted rather than renamed. diff --git a/Aetheria.State/scripts/verify-stage7d-unity-parity.ps1 b/Aetheria.State/scripts/verify-stage7d-unity-parity.ps1 index 93f5e162a..1b20bf6ca 100644 --- a/Aetheria.State/scripts/verify-stage7d-unity-parity.ps1 +++ b/Aetheria.State/scripts/verify-stage7d-unity-parity.ps1 @@ -578,20 +578,13 @@ Assert-Contains $tickRunner "ProjectTradeValuePolicySurfaceDocument(stateFilePat $client = Read-Text "Packages\org.gamecult.aetheria.state\Runtime\AetheriaClient.cs" Assert-Contains $client "AetheriaClientState State" "AetheriaClient must expose the semantic typed state facade." Assert-Contains $client "Aetheria()" "AetheriaClient must expose the canonical domain facade entrypoint." -Assert-Contains $client "Document()" "AetheriaClient must allow callers to retrieve a projected state document by shared document type." -Assert-Contains $client "DocumentBySchema(string schemaVersion)" "AetheriaClient must allow projected state lookup by shared schema identity." -Assert-Contains $client "LatestAsync()" "AetheriaClient must allow one-call typed state reads by shared document type." -Assert-Contains $client "Watch()" "AetheriaClient must allow reactive typed state reads by shared document type." -Assert-Contains $client "ObjectsViewportAsync" "AetheriaClient must expose objects viewport facade." -Assert-Contains $client "GravityViewportAsync" "AetheriaClient must expose gravity viewport facade." -Assert-Contains $client "CurrentZoneAsync" "AetheriaClient must expose current-zone facade." -Assert-Contains $client "CurrentEntityAsync" "AetheriaClient must expose current-entity facade." -Assert-Contains $client "CurrentDockingAsync" "AetheriaClient must expose current-docking facade." -Assert-Contains $client "ZoneContactsAsync" "AetheriaClient must expose zone-contacts facade." -Assert-Contains $client "StationRefitAsync" "AetheriaClient must expose station-refit facade." -Assert-Contains $client "SectorMapAsync" "AetheriaClient must expose sector-map facade." -Assert-Contains $client "ZoneDetailsAsync" "AetheriaClient must expose zone-details facade." -Assert-Contains $client "ZoneRenderAsync" "AetheriaClient must expose zone-render facade." +Assert-Contains $client "AetheriaControl Control" "AetheriaClient must expose command controls separately from managed state documents." +Assert-Contains $client "AetheriaUi Ui" "AetheriaClient must expose UI command submission separately from managed state documents." +Assert-NotContains $client "Document()" "AetheriaClient must not forward typed document lookup; use AetheriaClientState." +Assert-NotContains $client "DocumentBySchema(string schemaVersion)" "AetheriaClient must not forward schema document lookup; use AetheriaClientState." +Assert-NotContains $client "LatestAsync()" "AetheriaClient must not forward one-call typed reads; use AetheriaClientState." +Assert-NotContains $client "Watch()" "AetheriaClient must not forward reactive reads; use AetheriaClientState." +Assert-NotContains $client "ReactiveAsync" "AetheriaClient must not forward reactive document creation; use AetheriaClientState." $verseClient = Read-Text "Packages\org.gamecult.aetheria.state\Runtime\AetheriaRuntimeVerseClient.cs" Assert-Contains $verseClient "AetheriaClientState Aetheria()" "AetheriaRuntimeVerseClient must expose the shared domain state facade." diff --git a/Assets/Scripts/Tests/DaemonRuntimeDocumentTests.cs b/Assets/Scripts/Tests/DaemonRuntimeDocumentTests.cs index c09ecf121..1150c0ea1 100644 --- a/Assets/Scripts/Tests/DaemonRuntimeDocumentTests.cs +++ b/Assets/Scripts/Tests/DaemonRuntimeDocumentTests.cs @@ -194,11 +194,11 @@ public class DaemonRuntimeDocumentTests .LatestAsync() .GetAwaiter() .GetResult(); - var currentEntityFromClientType = client + var currentEntityFromClientType = client.State .LatestAsync() .GetAwaiter() .GetResult(); - using var currentEntityReactive = client + using var currentEntityReactive = client.State .ReactiveAsync() .GetAwaiter() .GetResult(); @@ -222,21 +222,21 @@ public class DaemonRuntimeDocumentTests Assert.AreEqual("aetheria.current.entity", client.State.Current.Entity.DocumentId); Assert.AreSame(client.State.Current.Entity, client.State.Document()); - Assert.AreSame(client.State.Catalog, client.Document()); - Assert.AreSame(client.State.ZoneRender, client.Document()); - Assert.AreSame(client.State.LatestFrame, client.Document()); + Assert.AreSame(client.State.Catalog, client.State.Document()); + Assert.AreSame(client.State.ZoneRender, client.State.Document()); + Assert.AreSame(client.State.LatestFrame, client.State.Document()); Assert.AreSame(client.State.Daemon.LatestFrame, client.State.LatestFrame); Assert.AreSame(client.State.Daemon.LatestSoaView, client.State.LatestSoaView); Assert.AreSame( client.State.Daemon.ProviderAdvertisement, - client.Document()); - Assert.AreSame(client.State.Daemon.Health, client.Document()); + client.State.Document()); + Assert.AreSame(client.State.Daemon.Health, client.State.Document()); Assert.AreSame( client.State.Daemon.CommandBoundary, - client.Document()); + client.State.Document()); Assert.AreSame( client.State.Daemon.AuthorityPolicy, - client.Document()); + client.State.Document()); Assert.AreSame( client.State.Daemon.AuthorityPolicy, client.State.DocumentBySchema(AetheriaRuntimeVerseAuthoritySchemas.Policy)); @@ -244,17 +244,17 @@ public class DaemonRuntimeDocumentTests Assert.AreEqual(AetheriaRuntimeDaemonGameSurfaceBuilder.TuiSurfaceId, client.State.Daemon.GameTuiSurface.DocumentId); Assert.AreEqual(AetheriaRuntimeDaemonEditorSurfaceBuilder.SurfaceId, client.State.Daemon.EditorSurface.DocumentId); Assert.AreEqual(AetheriaRuntimeDaemonEditorSurfaceBuilder.TuiSurfaceId, client.State.Daemon.EditorTuiSurface.DocumentId); - Assert.AreSame(client.State.Settings.Player, client.Document()); - Assert.AreSame(client.State.Settings.VerseHost, client.Document()); + Assert.AreSame(client.State.Settings.Player, client.State.Document()); + Assert.AreSame(client.State.Settings.VerseHost, client.State.Document()); Assert.AreSame( client.State.Current.Entity, client.State.DocumentBySchema(AetheriaRuntimeDaemonSchemas.CurrentEntity)); Assert.AreSame( client.State.ZoneContacts, - client.DocumentBySchema("gamecult.aetheria.zone_contacts")); + client.State.DocumentBySchema("gamecult.aetheria.zone_contacts")); Assert.AreEqual( typeof(AetheriaRuntimeCurrentEntityDocument), - client.DocumentBySchema(AetheriaRuntimeDaemonSchemas.CurrentEntity).DocumentType); + client.State.DocumentBySchema(AetheriaRuntimeDaemonSchemas.CurrentEntity).DocumentType); Assert.IsTrue(client.State.TryGetDocument(out var sectorMapDocument)); Assert.AreSame(client.State.SectorMap, sectorMapDocument); Assert.IsTrue(client.State.TryGetDocumentBySchema( @@ -325,8 +325,8 @@ public class DaemonRuntimeDocumentTests Assert.AreEqual(AetheriaRuntimeVerseHostSettingsDocument.SchemaId, verseHost.Schema); Assert.AreEqual("", player.PlayerName); Assert.AreEqual("", verseHost.VerseId); - Assert.AreSame(client.State.Settings.Player, client.Document()); - Assert.AreSame(client.State.Settings.VerseHost, client.Document()); + Assert.AreSame(client.State.Settings.Player, client.State.Document()); + Assert.AreSame(client.State.Settings.VerseHost, client.State.Document()); } [Test] diff --git a/Packages/org.gamecult.aetheria.state/Runtime/AetheriaClient.cs b/Packages/org.gamecult.aetheria.state/Runtime/AetheriaClient.cs index 8c8e61644..5d1cdadd2 100644 --- a/Packages/org.gamecult.aetheria.state/Runtime/AetheriaClient.cs +++ b/Packages/org.gamecult.aetheria.state/Runtime/AetheriaClient.cs @@ -2,8 +2,6 @@ using System; using System.IO; using System.Threading.Tasks; using GameCult.Eve.Surface; -using GameCult.Mesh; -using R3; #nullable enable @@ -39,56 +37,6 @@ namespace GameCult.Aetheria.State.Verse public AetheriaClientState Aetheria() => State; - public CultMeshDocumentHandle Document() - where TDocument : class - { - ThrowIfDisposed(); - return State.Document(); - } - - public ICultMeshDocumentHandle DocumentBySchema(string schemaVersion) - { - ThrowIfDisposed(); - return State.DocumentBySchema(schemaVersion); - } - - public Task LatestAsync() - where TDocument : class - { - ThrowIfDisposed(); - return State.LatestAsync(); - } - - public Observable Watch() - where TDocument : class - { - ThrowIfDisposed(); - return State.Watch(); - } - - public IDisposable Watch(Action onNext) - where TDocument : class - { - ThrowIfDisposed(); - return State.Watch(onNext); - } - - public Task> ReactiveAsync( - CultMeshReactiveDocumentOptions? options = null) - where TDocument : class - { - ThrowIfDisposed(); - return State.ReactiveAsync(options); - } - - public CultMeshReactiveDocument Reactive( - CultMeshReactiveDocumentOptions? options = null) - where TDocument : class - { - ThrowIfDisposed(); - return State.Reactive(options); - } - internal AetheriaRuntimeDaemonOperationsClient Operations => _operations; public static async Task OpenAsync(