From 1e0455028ca97698e614ae8307d9d43d2580bd0f Mon Sep 17 00:00:00 2001 From: Meta Vens Date: Wed, 30 Sep 2026 16:15:48 +0200 Subject: [PATCH] CultMesh: AsSchemaAlias is gone; a catalog finds a handle by its type F7 (operator, 2026-09-30): "Schema aliasing sounds like a really bad idea, I support retiring it." One CLR type owns a schema, so a handle never needs converting to another type for the same schema. - Delete AsSchemaAlias from the document and collection handles and their interfaces, with the MessagePack round-trip converters only it used. - The document and collection catalogs look a typed handle up by its type. The schema-name/version fallback existed only to find a handle of another type and alias it. - Tests: the MeshNoteAliasDocument fixture is deleted. Tests that used it for publication, sync, snapshot and prediction paths now use MeshNoteDocument; the one test that only checked alias refusal is deleted. Catalog tests check a type with no handle is not found. - public-api.md stops documenting aliasing; a stale comment in ReadDocumentFromSnapshotResponse that cited the fixture is trimmed. Co-Authored-By: Claude Opus 5.5 --- src/GameCult.Mesh/CultMesh.cs | 8 +- src/GameCult.Mesh/CultMeshPrimitives.cs | 164 ++---------- src/GameCult.Mesh/CultMeshSnapshots.cs | 4 +- src/GameCult.Mesh/docs/public-api.md | 62 ++--- .../CultMeshStreamingTests.cs | 240 +++++++----------- 5 files changed, 140 insertions(+), 338 deletions(-) diff --git a/src/GameCult.Mesh/CultMesh.cs b/src/GameCult.Mesh/CultMesh.cs index 52c67482..18792413 100644 --- a/src/GameCult.Mesh/CultMesh.cs +++ b/src/GameCult.Mesh/CultMesh.cs @@ -2728,11 +2728,9 @@ namespace GameCult.Mesh // runtime does not recognize by any alias) its payload's own embedded schema stamp, // alias-matched against TDocument's descriptor. The parse step // (CultNetDocumentRegistry.TryReadSchemaVersion) is the one decode rule shared with - // DecodeSnapshotDocuments; the match itself stays a direct alias-match against the caller's - // own descriptor rather than a global "which registered type owns this schema string" lookup, - // because that lookup is ambiguous when two document types alias the same schema id (as - // MeshNoteDocument/MeshNoteAliasDocument do in tests/GameCult.Mesh.Tests). No re-filter of the - // server's answer by schema alone, and no fallback that returns a record under the wrong key. + // DecodeSnapshotDocuments; the match itself is a direct alias-match against the caller's own + // descriptor. No re-filter of the server's answer by schema alone, and no fallback that + // returns a record under the wrong key. private static TDocument ReadDocumentFromSnapshotResponse( CultNetSnapshotResponseRawMessage response, string schemaId, diff --git a/src/GameCult.Mesh/CultMeshPrimitives.cs b/src/GameCult.Mesh/CultMeshPrimitives.cs index 58723950..500f9ef3 100644 --- a/src/GameCult.Mesh/CultMeshPrimitives.cs +++ b/src/GameCult.Mesh/CultMeshPrimitives.cs @@ -910,13 +910,10 @@ namespace GameCult.Mesh /// Gets whether this handle can submit a client prediction for the underlying document value. bool CanSubmitPrediction { get; } - - /// Creates a same-schema alias presentation for another CLR document type. - CultMeshDocumentHandle AsSchemaAlias() where TAlias : class; } /// - /// Typed reactive document handle with schema-aware alias conversion. + /// Typed reactive document handle. /// public sealed class CultMeshDocumentHandle : ICultMeshDocumentHandle where TDocument : class @@ -1117,39 +1114,6 @@ namespace GameCult.Mesh return ObserveAsync().ConfigureAwait(false).GetAwaiter().GetResult(); } - /// Creates a same-schema alias presentation for another CLR document type. - public CultMeshDocumentHandle AsSchemaAlias() where TAlias : class - { - var aliasDescriptor = CultDocumentRegistry.Shared.GetRequired(); - if (!string.Equals(Descriptor.SchemaName, aliasDescriptor.SchemaName, StringComparison.Ordinal) || - !string.Equals(Descriptor.SchemaVersion, aliasDescriptor.SchemaVersion, StringComparison.Ordinal)) - { - throw new InvalidOperationException( - $"Document type {typeof(TAlias).FullName} uses schema '{aliasDescriptor.SchemaName}' " + - $"version '{aliasDescriptor.SchemaVersion}', but handle '{DocumentId}' exposes " + - $"schema '{SchemaName}' version '{SchemaVersion}'."); - } - - var aliasFeed = new CultMeshLiveFeed( - DocumentId, - async (parameters, context) => ConvertDocument( - await Feed.SnapshotAsync(parameters, context).ConfigureAwait(false)), - (parameters, context) => Feed - .Watch(parameters, context) - .Select(ConvertDocument), - Sources, - RouteHint); - - Func? replace = _replace == null - ? null - : value => _replace(ConvertDocument(value)); - Func? submitPrediction = _submitPrediction == null - ? null - : value => _submitPrediction(ConvertDocument(value)); - - return new CultMeshDocumentHandle(aliasFeed.Bind(Context), replace, submitPrediction); - } - internal static TDocumentValue CloneDocument(TDocumentValue document) where TDocumentValue : class { @@ -1216,19 +1180,6 @@ namespace GameCult.Mesh "field"); } - internal static TTarget ConvertDocument(TSource document) - where TSource : class - where TTarget : class - { - if (document == null) throw new ArgumentNullException(nameof(document)); - if (document is TTarget alreadyTyped) - { - return alreadyTyped; - } - - var payload = CultDocumentMessagePackSerialization.SerializeUntyped(document, typeof(TSource)); - return (TTarget)CultDocumentMessagePackSerialization.DeserializeUntyped(typeof(TTarget), payload); - } } /// @@ -1912,11 +1863,12 @@ namespace GameCult.Mesh $"CultMesh document catalog does not expose a document for schema '{schema}'."); } - /// Looks up a typed document handle by CLR type or same-schema alias. + /// Looks up a typed document handle by CLR type. public bool TryGetDocument( out CultMeshDocumentHandle document) where TDocument : class { + // One type owns a schema, so the handle for TDocument's schema is the handle for TDocument. if (_documentsByType.TryGetValue(typeof(TDocument), out var untypedDocument) && untypedDocument is CultMeshDocumentHandle typedDocument) { @@ -1924,25 +1876,11 @@ namespace GameCult.Mesh return true; } - var descriptor = CultDocumentRegistry.Shared.GetRequired(); - if (_documentsBySchema.TryGetValue(descriptor.SchemaVersion, out var schemaDocument) || - _documentsBySchema.TryGetValue(descriptor.SchemaName, out schemaDocument!)) - { - if (schemaDocument is CultMeshDocumentHandle schemaTypedDocument) - { - document = schemaTypedDocument; - return true; - } - - document = schemaDocument.AsSchemaAlias(); - return true; - } - document = null!; return false; } - /// Looks up a typed document handle by CLR type or same-schema alias. + /// Looks up a typed document handle by CLR type. public CultMeshDocumentHandle Document() where TDocument : class { @@ -1953,70 +1891,70 @@ namespace GameCult.Mesh $"CultMesh document catalog does not expose a document for {typeof(TDocument).FullName}."); } - /// Reads one typed document snapshot by CLR type or same-schema alias. + /// Reads one typed document snapshot by CLR type. public Task LatestAsync() where TDocument : class { return Document().LatestAsync(); } - /// Reads one typed document synchronously by CLR type or same-schema alias. + /// Reads one typed document synchronously by CLR type. public TDocument Latest() where TDocument : class { return Document().Latest(); } - /// Gets whether one typed document can be replaced by CLR type or same-schema alias. + /// Gets whether one typed document can be replaced by CLR type. public bool CanReplace() where TDocument : class { return TryGetDocument(out var document) && document.CanReplace; } - /// Replaces one typed document by CLR type or same-schema alias. + /// Replaces one typed document by CLR type. public Task ReplaceAsync(TDocument value) where TDocument : class { return Document().ReplaceAsync(value); } - /// Gets whether one typed document can submit client predictions by CLR type or same-schema alias. + /// Gets whether one typed document can submit client predictions by CLR type. public bool CanSubmitPrediction() where TDocument : class { return TryGetDocument(out var document) && document.CanSubmitPrediction; } - /// Submits a client prediction for one typed document by CLR type or same-schema alias. + /// Submits a client prediction for one typed document by CLR type. public Task SubmitPredictionAsync(TDocument value) where TDocument : class { return Document().SubmitPredictionAsync(value); } - /// Gets an explicit authoritative writer by CLR type or same-schema alias. + /// Gets an explicit authoritative writer by CLR type. public CultMeshDocumentWriter AuthoritativeWriter() where TDocument : class { return Document().AuthoritativeWriter(); } - /// Gets an explicit prediction writer by CLR type or same-schema alias. + /// Gets an explicit prediction writer by CLR type. public CultMeshDocumentWriter PredictionWriter() where TDocument : class { return Document().PredictionWriter(); } - /// Watches one typed document by CLR type or same-schema alias. + /// Watches one typed document by CLR type. public Observable Watch() where TDocument : class { return Document().Watch(); } - /// Subscribes to one typed document by CLR type or same-schema alias. + /// Subscribes to one typed document by CLR type. public IDisposable Watch(Action onNext) where TDocument : class { @@ -2050,9 +1988,6 @@ namespace GameCult.Mesh /// Gets typed state sources this collection handle depends on, when known. IReadOnlyList Sources { get; } - - /// Creates a same-schema alias presentation for another CLR document type. - CultMeshCollectionHandle AsSchemaAlias() where TAlias : class; } /// @@ -2118,11 +2053,12 @@ namespace GameCult.Mesh $"CultMesh collection catalog does not expose a collection for schema '{schema}'."); } - /// Looks up a typed collection handle by CLR type or same-schema alias. + /// Looks up a typed collection handle by CLR type. public bool TryGetCollection( out CultMeshCollectionHandle collection) where TDocument : class { + // One type owns a schema, so the handle for TDocument's schema is the handle for TDocument. if (_collectionsByType.TryGetValue(typeof(TDocument), out var untypedCollection) && untypedCollection is CultMeshCollectionHandle typedCollection) { @@ -2130,26 +2066,11 @@ namespace GameCult.Mesh return true; } - var descriptor = CultDocumentRegistry.Shared.GetRequired(); - if (_collectionsBySchema.TryGetValue(descriptor.SchemaId, out var schemaCollection) || - _collectionsBySchema.TryGetValue(descriptor.SchemaVersion, out schemaCollection!) || - _collectionsBySchema.TryGetValue(descriptor.SchemaName, out schemaCollection!)) - { - if (schemaCollection is CultMeshCollectionHandle schemaTypedCollection) - { - collection = schemaTypedCollection; - return true; - } - - collection = schemaCollection.AsSchemaAlias(); - return true; - } - collection = null!; return false; } - /// Looks up a typed collection handle by CLR type or same-schema alias. + /// Looks up a typed collection handle by CLR type. public CultMeshCollectionHandle Collection() where TDocument : class { @@ -2160,21 +2081,21 @@ namespace GameCult.Mesh $"CultMesh collection catalog does not expose a collection for {typeof(TDocument).FullName}."); } - /// Reads one typed collection snapshot by CLR type or same-schema alias. + /// Reads one typed collection snapshot by CLR type. public Task> LatestAsync() where TDocument : class { return Collection().LatestAsync(); } - /// Watches one typed collection by CLR type or same-schema alias. + /// Watches one typed collection by CLR type. public Observable> WatchChanges() where TDocument : class { return Collection().WatchChanges(); } - /// Subscribes to one typed collection by CLR type or same-schema alias. + /// Subscribes to one typed collection by CLR type. public IDisposable WatchChanges(Action> onNext) where TDocument : class { @@ -2246,7 +2167,7 @@ namespace GameCult.Mesh } /// - /// Typed reactive collection handle with schema-aware alias conversion. + /// Typed reactive collection handle. /// public sealed class CultMeshCollectionHandle : ICultMeshCollectionHandle where TDocument : class @@ -2313,49 +2234,6 @@ namespace GameCult.Mesh if (onNext == null) throw new ArgumentNullException(nameof(onNext)); return WatchChanges().Subscribe(onNext); } - - /// Creates a same-schema alias presentation for another CLR document type. - public CultMeshCollectionHandle AsSchemaAlias() where TAlias : class - { - var aliasDescriptor = CultDocumentRegistry.Shared.GetRequired(); - if (!string.Equals(Descriptor.SchemaName, aliasDescriptor.SchemaName, StringComparison.Ordinal) || - !string.Equals(Descriptor.SchemaVersion, aliasDescriptor.SchemaVersion, StringComparison.Ordinal)) - { - throw new InvalidOperationException( - $"Document type {typeof(TAlias).FullName} uses schema '{aliasDescriptor.SchemaName}' " + - $"version '{aliasDescriptor.SchemaVersion}', but collection '{CollectionId}' exposes " + - $"schema '{SchemaName}' version '{SchemaVersion}'."); - } - - return new CultMeshCollectionHandle( - CollectionId, - async () => (await LatestAsync().ConfigureAwait(false)) - .Select(ConvertDocument) - .ToArray(), - () => WatchChanges().Select(change => new CultMeshCollectionChange( - change.Kind, - change.Key, - change.SchemaId, - change.Document == null ? null : ConvertDocument(change.Document), - change.PreviousDocument == null ? null : ConvertDocument(change.PreviousDocument), - change.Message)), - Sources, - RouteHint); - } - - private static TTarget ConvertDocument(TSource document) - where TSource : class - where TTarget : class - { - if (document == null) throw new ArgumentNullException(nameof(document)); - if (document is TTarget alreadyTyped) - { - return alreadyTyped; - } - - var payload = CultDocumentMessagePackSerialization.SerializeUntyped(document, typeof(TSource)); - return (TTarget)CultDocumentMessagePackSerialization.DeserializeUntyped(typeof(TTarget), payload); - } } /// diff --git a/src/GameCult.Mesh/CultMeshSnapshots.cs b/src/GameCult.Mesh/CultMeshSnapshots.cs index 58aede9d..c76f82bc 100644 --- a/src/GameCult.Mesh/CultMeshSnapshots.cs +++ b/src/GameCult.Mesh/CultMeshSnapshots.cs @@ -979,11 +979,11 @@ namespace GameCult.Mesh var canDeserializeWithBinding = binding != null && typeof(TDocument).IsAssignableFrom(binding.DocumentType); - var canDeserializeAsSchemaAlias = + var canDeserializeByWireSchema = CultNetSchemaAliasMatching.Matches(record.SchemaId, descriptor) || (binding != null && CultNetSchemaAliasMatching.Matches(binding.SchemaId, descriptor)) || CultNetDocumentRegistry.PayloadMatchesSchema(record.Payload, descriptor); - if (!canDeserializeWithBinding && !canDeserializeAsSchemaAlias) + if (!canDeserializeWithBinding && !canDeserializeByWireSchema) continue; if (!string.Equals(record.PayloadEncoding, "messagepack", StringComparison.Ordinal)) diff --git a/src/GameCult.Mesh/docs/public-api.md b/src/GameCult.Mesh/docs/public-api.md index e9f19ab7..072e6c73 100644 --- a/src/GameCult.Mesh/docs/public-api.md +++ b/src/GameCult.Mesh/docs/public-api.md @@ -173,28 +173,22 @@ portable machinery that makes it feel native. the normal shard log. Callers can bind a projected live feed, a local `CultCache` record, a distributed `CultNetDatabase` record, or a `CultMeshNode` record through the same surface instead of walking transport - and projection layers themselves. Same-schema CLR aliases can be requested - directly from node/database/snapshot surfaces; CultMesh resolves the canonical - registered document by shared `[CultDocument(schemaName, schemaVersion)]` - identity and uses the shared CultCache MessagePack codec for - read/watch/replace/prediction conversion. `AsSchemaAlias()` remains - available when a caller already has a handle and wants to project it. + and projection layers themselves. One CLR type owns each + `[CultDocument(schemaName, schemaVersion)]` schema; the registry refuses a + second type for the same schema with `CultSchemaConflictException`. - `CultMeshDocumentCatalog` is the schema-aware lookup edge for a set of - document handles. It indexes handles by CLR document type, schema name, and - schema version, and resolves same-schema CLR aliases by delegating to - `CultMeshDocumentHandle.AsSchemaAlias()`. Domain facades - can expose `Document()`, `DocumentBySchema(...)`, `LatestAsync()`, and - `Watch()` without owning schema dictionaries or alias serializers. Mutable - facades can also call `ReplaceAsync(...)` or - `SubmitPredictionAsync(...)` directly on the catalog when they only need - the schema-aliased operation and not the intermediate handle. + document handles. It indexes handles by CLR document type, schema id, schema + name, and schema version. Domain facades can expose `Document()`, + `DocumentBySchema(...)`, `LatestAsync()`, and `Watch()` without owning + schema dictionaries. Mutable facades can also call `ReplaceAsync(...)` or + `SubmitPredictionAsync(...)` directly on the catalog when they do not need + the intermediate handle. - `CultMeshCollectionHandle` is the typed reactive edge for multi-record state. It exposes one `LatestAsync()` collection snapshot and a `WatchChanges()` stream while hiding whether the backing source is an in-process `CultCache`, a distributed `CultNetDatabase`, or a `CultMeshNode`. Collection handles can represent all records of a document type, a named - document view, or an indexed value view, and they support the same - same-schema CLR alias conversion as document handles. + document view, or an indexed value view. - `CultMeshCollectionCatalog` is the collection sibling of `CultMeshDocumentCatalog`. It indexes typed collection handles by CLR document type, schema id, schema name, and schema version, then exposes @@ -258,19 +252,17 @@ var objects = await visibleObjects.ExecuteAsync(viewportRequest); await movePilot.InvokeAsync(moveRequest, idempotencyKey); ``` -A single typed document can be surfaced the same way. The caller asks for the -typed view it wants; if that type is a same-schema alias of the registered -canonical document, CultMesh still opens the correct backing record: +A single typed document can be surfaced the same way: ```csharp -var stockForUi = CultMesh.Document( +var stockHandle = CultMesh.Document( node, new CultRecordKey("station:starbridge:stock"), verse); -var stock = await stockForUi.LatestAsync(); -using var watch = stockForUi.Watch(RenderStock); -await stockForUi.SetAsync(updatedStockFromUi); +var stock = await stockHandle.LatestAsync(); +using var watch = stockHandle.Watch(RenderStock); +await stockHandle.SetAsync(updatedStock); ``` Projected or derived documents can use the same handle shape with explicit @@ -291,8 +283,6 @@ var cockpit = CultMesh.Document( var current = await cockpit.LatestAsync(); using var subscription = cockpit.Watch(next => RenderCockpit(next)); - -var daemonAlias = cockpit.AsSchemaAlias(); ``` Remote CultNet snapshots use the same document handle surface. The caller names @@ -301,20 +291,18 @@ id, response filtering, raw MessagePack payload decode, route metadata, and polling watch fallback: ```csharp -var remoteHealth = CultMesh.DocumentFromPeerSnapshot( +var remoteHealth = CultMesh.DocumentFromPeerSnapshot( "cultnet://daemon.local:3075", "daemon:aetheria.health.v1", verse); -var uiHealth = await remoteHealth.LatestAsync(); +var health = await remoteHealth.LatestAsync(); ``` -Snapshot requests are record-key-first so same logical documents can still be -read when another runtime generated a different schema id for a compatible -schema alias. The decode path prefers exact schema id matches when present and -falls back to the requested record key. Ask for the runtime-facing alias type -directly; `AsSchemaAlias()` is for adapting handles that were already -constructed elsewhere. +Snapshot requests are record-key-first so the same logical document can still be +read when another runtime generated a different schema id for it. The decode +path prefers exact schema id matches when present and falls back to the +requested record key. A domain facade can still collect existing handles into one schema-aware catalog when it is composing pre-built surfaces: @@ -326,7 +314,7 @@ var documents = CultMesh.Documents( zoneContacts); var refit = await documents.LatestAsync(); -var uiDocking = documents.Document(); +var docking = documents.Document(); var bySchema = documents.DocumentBySchema("gamecult.aetheria.station_refit.v1"); ``` @@ -341,11 +329,9 @@ var allies = CultMesh.CollectionByIndex( var currentAllies = await allies.LatestAsync(); using var changes = allies.WatchChanges(change => UpdateRoster(change)); -var uiAllies = allies.AsSchemaAlias(); - var collections = CultMesh.Collections(allies); -var uiRoster = await collections.LatestAsync(); -using var uiRosterChanges = collections.WatchChanges(RenderRoster); +var roster = await collections.LatestAsync(); +using var rosterChanges = collections.WatchChanges(RenderRoster); ``` ```ts diff --git a/tests/GameCult.Mesh.Tests/CultMeshStreamingTests.cs b/tests/GameCult.Mesh.Tests/CultMeshStreamingTests.cs index acf5eb6c..1eb1573d 100644 --- a/tests/GameCult.Mesh.Tests/CultMeshStreamingTests.cs +++ b/tests/GameCult.Mesh.Tests/CultMeshStreamingTests.cs @@ -696,7 +696,7 @@ public sealed class CultMeshStreamingTests } [Test] - public async Task DocumentHandle_ExposesTypedSnapshotsAndSameSchemaAliases() + public async Task DocumentHandle_ExposesTypedSnapshotsAndWatches() { var subject = new Subject(); var route = new CultMeshRouteHint(CultMeshLocalityKind.SharedMemory, "co-located document slab"); @@ -733,17 +733,8 @@ public sealed class CultMeshStreamingTests snapshot.Text.Should().Be("primary"); handle.Latest().Text.Should().Be("primary"); - var alias = handle.AsSchemaAlias(); - var aliasSnapshot = await alias.LatestAsync(); - alias.Latest().Text.Should().Be("primary"); - alias.DocumentId.Should().Be(handle.DocumentId); - alias.SchemaName.Should().Be(handle.SchemaName); - alias.SchemaVersion.Should().Be(handle.SchemaVersion); - aliasSnapshot.Text.Should().Be("primary"); - aliasSnapshot.Revision.Should().Be(1); - - MeshNoteAliasDocument observed = null!; - using var subscription = alias.Watch(value => observed = value); + MeshNoteDocument observed = null!; + using var subscription = handle.Watch(value => observed = value); subject.OnNext(new MeshNoteDocument { Schema = "tests.mesh_note.v1", @@ -790,28 +781,7 @@ public sealed class CultMeshStreamingTests } [Test] - public void DocumentHandle_RejectsAliasTypesWithDifferentSchemaIdentity() - { - var handle = CultMesh.Document( - "mesh.note.current", - CultMesh.Verse("starbridge", "unity-pilot"), - _ => Task.FromResult(new MeshNoteDocument - { - Schema = "tests.mesh_note.v1", - Text = "primary", - Revision = 1 - }), - _ => new Subject()); - - Action act = () => handle.AsSchemaAlias(); - - act.Should() - .Throw() - .WithMessage("*tests.mesh_other*tests.mesh_note*"); - } - - [Test] - public async Task DocumentCatalog_IndexesHandlesByTypeAndSchemaAlias() + public async Task DocumentCatalog_IndexesHandlesByTypeAndSchema() { var current = new MeshNoteDocument { @@ -836,15 +806,12 @@ public sealed class CultMeshStreamingTests .Should() .BeSameAs(handle); - catalog.TryGetDocument(out var alias).Should().BeTrue(); - alias.DocumentId.Should().Be(handle.DocumentId); - alias.SchemaName.Should().Be(handle.SchemaName); - alias.SchemaVersion.Should().Be(handle.SchemaVersion); + catalog.TryGetDocument(out _).Should().BeFalse(); - var aliasSnapshot = await catalog.LatestAsync(); - aliasSnapshot.Text.Should().Be("catalog-primary"); - aliasSnapshot.Revision.Should().Be(3); - catalog.Latest().Text.Should().Be("catalog-primary"); + var snapshot = await catalog.LatestAsync(); + snapshot.Text.Should().Be("catalog-primary"); + snapshot.Revision.Should().Be(3); + catalog.Latest().Text.Should().Be("catalog-primary"); } [Test] @@ -894,21 +861,18 @@ public sealed class CultMeshStreamingTests cache, key, CultMesh.Verse("starbridge", "unity-pilot")); - var alias = handle.AsSchemaAlias(); handle.CanReplace.Should().BeTrue(); - alias.CanReplace.Should().BeTrue(); handle.CanSubmitPrediction.Should().BeFalse(); - alias.CanSubmitPrediction.Should().BeFalse(); handle.DocumentId.Should().Be(key.Value); handle.Sources.Should().ContainSingle().Which.SchemaId.Should().Be(handle.SchemaId); - var snapshot = await alias.LatestAsync(); + var snapshot = await handle.LatestAsync(); snapshot.Text.Should().Be("cache-initial"); - MeshNoteAliasDocument observed = null!; - using var subscription = alias.Watch(value => observed = value); - await alias.ReplaceAsync(new MeshNoteAliasDocument + MeshNoteDocument observed = null!; + using var subscription = handle.Watch(value => observed = value); + await handle.ReplaceAsync(new MeshNoteDocument { Schema = "tests.mesh_note.v1", Text = "cache-replaced", @@ -920,8 +884,8 @@ public sealed class CultMeshStreamingTests observed.Revision.Should().Be(2); var catalog = CultMesh.Documents(handle); - catalog.CanReplace().Should().BeTrue(); - await catalog.ReplaceAsync(new MeshNoteAliasDocument + catalog.CanReplace().Should().BeTrue(); + await catalog.ReplaceAsync(new MeshNoteDocument { Schema = "tests.mesh_note.v1", Text = "cache-catalog-replaced", @@ -929,7 +893,7 @@ public sealed class CultMeshStreamingTests }); cache.Get(key)!.Text.Should().Be("cache-catalog-replaced"); - Func act = () => alias.SubmitPredictionAsync(new MeshNoteAliasDocument + Func act = () => handle.SubmitPredictionAsync(new MeshNoteDocument { Schema = "tests.mesh_note.v1", Text = "cache-predicted", @@ -970,19 +934,17 @@ public sealed class CultMeshStreamingTests database, key, CultMesh.Verse("starbridge", "pilot-a")); - var alias = handle.AsSchemaAlias(); handle.CanReplace.Should().BeFalse(); - alias.CanReplace.Should().BeFalse(); - alias.CanSubmitPrediction.Should().BeTrue(); + handle.CanSubmitPrediction.Should().BeTrue(); var catalog = CultMesh.Documents(handle); - catalog.CanSubmitPrediction().Should().BeTrue(); - var predictionWriter = catalog.PredictionWriter(); + catalog.CanSubmitPrediction().Should().BeTrue(); + var predictionWriter = catalog.PredictionWriter(); predictionWriter.Kind.Should().Be(CultMeshDocumentWriteKind.Prediction); MeshNoteDocument observed = null!; using var subscription = handle.Watch(value => observed = value); - await predictionWriter.WriteAsync(new MeshNoteAliasDocument + await predictionWriter.WriteAsync(new MeshNoteDocument { Schema = "tests.mesh_note.v1", Text = "predicted-thermal", @@ -994,7 +956,7 @@ public sealed class CultMeshStreamingTests observed.Revision.Should().Be(5); (await handle.LatestAsync()).Text.Should().Be("predicted-thermal"); - var updated = await alias.PredictionWriter().UpdateAsync(value => new MeshNoteAliasDocument + var updated = await handle.PredictionWriter().UpdateAsync(value => new MeshNoteDocument { Schema = value.Schema, Text = "updated-as-prediction", @@ -1035,7 +997,7 @@ public sealed class CultMeshStreamingTests }); var catalog = CultMesh.Documents(handle); - using var reactive = await catalog.PredictionWriter().ReactiveAsync( + using var reactive = await catalog.PredictionWriter().ReactiveAsync( new CultMeshReactiveDocumentOptions { FlushDelay = TimeSpan.FromMinutes(1) @@ -1645,7 +1607,7 @@ public sealed class CultMeshStreamingTests } [Test] - public async Task ReactiveDocument_SyncsSameSchemaAliasesAcrossRuntimeHandles() + public async Task ReactiveDocument_SyncsAcrossRuntimeHandles() { var cache = new CultCache(); var schemaId = CultDocumentRegistry.Shared.GetRequired().SchemaId; @@ -1686,13 +1648,11 @@ public sealed class CultMeshStreamingTests database, key, CultMesh.Verse("starbridge", "commander-rts")); - var observedByCommander = new List(); - using var commanderSubscription = commanderHandle - .AsSchemaAlias() - .Watch(observedByCommander.Add); + var observedByCommander = new List(); + using var commanderSubscription = commanderHandle.Watch(observedByCommander.Add); using var pilotReactive = await CultMesh .Documents(pilotHandle) - .PredictionWriter() + .PredictionWriter() .ReactiveAsync( new CultMeshReactiveDocumentOptions { @@ -1710,7 +1670,7 @@ public sealed class CultMeshStreamingTests commanderHandle.Context.RuntimeId.Should().Be("commander-rts"); observedByCommander.Last().Revision.Should().Be(2); - (await commanderHandle.AsSchemaAlias().LatestAsync()).Text.Should().Be("pilot-predicted"); + (await commanderHandle.LatestAsync()).Text.Should().Be("pilot-predicted"); } [Test] @@ -1755,12 +1715,9 @@ public sealed class CultMeshStreamingTests database, key, CultMesh.Verse("starbridge", "commander-rts")); - MeshNoteAliasDocument commanderSnapshot = null!; - using var commanderSubscription = commanderHandle - .AsSchemaAlias() - .Watch(value => commanderSnapshot = value); + MeshNoteDocument commanderSnapshot = null!; + using var commanderSubscription = commanderHandle.Watch(value => commanderSnapshot = value); using var pilotReactive = await pilotHandle - .AsSchemaAlias() .PredictionWriter() .ReactiveAsync(new CultMeshReactiveDocumentOptions { @@ -1788,7 +1745,7 @@ public sealed class CultMeshStreamingTests } [Test] - public async Task NodeDocument_OpensExplicitPredictionWriterForSameSchemaAlias() + public async Task NodeDocument_OpensExplicitPredictionWriter() { var schemaId = CultDocumentRegistry.Shared.GetRequired().SchemaId; using var temp = new TemporaryDirectory(); @@ -1828,7 +1785,7 @@ public sealed class CultMeshStreamingTests }, new CultRecordHandle(key)); using var pilotReactive = await node - .Document(key, CultMesh.Verse("starbridge", "pilot-a")) + .Document(key, CultMesh.Verse("starbridge", "pilot-a")) .PredictionWriter() .ReactiveAsync(new CultMeshReactiveDocumentOptions { @@ -1851,7 +1808,7 @@ public sealed class CultMeshStreamingTests pilotReactive.Document.DocumentId.Should().Be(key.Value); pilotReactive.Document.Context.RuntimeId.Should().Be("pilot-a"); node.Cache.Get(key)!.Text.Should().Be("node-one-call-prediction"); - (await commanderHandle.AsSchemaAlias().LatestAsync()).Revision.Should().Be(2); + (await commanderHandle.LatestAsync()).Revision.Should().Be(2); } [Test] @@ -1897,8 +1854,8 @@ public sealed class CultMeshStreamingTests DocumentRegistry = registry } }); - var handle = surface.SyncTo(node).Document(key.Value); - MeshNoteAliasDocument observed = null!; + var handle = surface.SyncTo(node).Document(key.Value); + MeshNoteDocument observed = null!; using var subscription = handle.Watch(value => observed = value); await sourceCache.UpsertAsync(new MeshNoteDocument { @@ -1956,7 +1913,7 @@ public sealed class CultMeshStreamingTests } })) { - var stale = await surface.SyncTo(crashedRuntime).Document(key.Value).LatestAsync(); + var stale = await surface.SyncTo(crashedRuntime).Document(key.Value).LatestAsync(); stale.Text.Should().Be("before-crash"); } @@ -1983,7 +1940,7 @@ public sealed class CultMeshStreamingTests var reconstructed = await surface .SyncTo(freshRuntime) .Documents(CultMesh.SnapshotDocument(key.Value)) - .LatestAsync(); + .LatestAsync(); reconstructed.Text.Should().Be("after-reboot-authority"); reconstructed.Revision.Should().Be(4); @@ -2034,7 +1991,7 @@ public sealed class CultMeshStreamingTests }); var readOnlyHandle = surface .SyncTo(node) - .Document(key.Value); + .Document(key.Value); readOnlyHandle.CanReplace.Should().BeFalse(); readOnlyHandle.CanSubmitPrediction.Should().BeFalse(); @@ -2645,7 +2602,7 @@ public sealed class CultMeshStreamingTests .Register(CultNetDocumentBinding.ForDocument(CultDocumentRegistry.Shared)); var requests = new List(); - var handle = CultMesh.DocumentFromPublication( + var handle = CultMesh.DocumentFromPublication( CultMeshDocumentPublicationSource.PeerSnapshot( () => new MeshSnapshotSchemaClient(request => { @@ -2666,16 +2623,16 @@ public sealed class CultMeshStreamingTests snapshot.Text.Should().Be("remote-snapshot"); snapshot.Revision.Should().Be(9); - handle.DocumentType.Should().Be(typeof(MeshNoteAliasDocument)); + handle.DocumentType.Should().Be(typeof(MeshNoteDocument)); handle.RouteHint.Kind.Should().Be(CultMeshLocalityKind.Network); handle.Sources.Should().ContainSingle().Which.SourceId.Should().Be(key.Value); requests.Should().ContainSingle(); requests[0].SchemaIds.Should().ContainSingle().Which .Should().Be(CultDocumentRegistry.Shared.GetRequired().SchemaId); requests[0].RecordKeys.Should().ContainSingle().Which.Should().Be(key.Value); - (await catalog.LatestAsync()).Text.Should().Be("remote-snapshot"); + (await catalog.LatestAsync()).Text.Should().Be("remote-snapshot"); - var aliasSchemaHandle = CultMesh.DocumentFromPeerSnapshot( + var aliasSchemaHandle = CultMesh.DocumentFromPeerSnapshot( _ => Task.FromResult(new CultNetSnapshotResponseRawMessage { MessageId = "alias-schema", @@ -2703,7 +2660,7 @@ public sealed class CultMeshStreamingTests (await aliasSchemaHandle.LatestAsync()).Text.Should().Be("record-key-fallback"); - var mixedAliasSchemaHandle = CultMesh.DocumentFromPeerSnapshot( + var mixedAliasSchemaHandle = CultMesh.DocumentFromPeerSnapshot( _ => Task.FromResult(new CultNetSnapshotResponseRawMessage { MessageId = "alias-schema-with-neighbor", @@ -2749,7 +2706,7 @@ public sealed class CultMeshStreamingTests // The recordKey match is exact (ordinal), not case-insensitive. A case-variant key must not // win even when it appears first in the response. var caseVariantKey = key.Value.ToUpperInvariant(); - var caseVariantKeyHandle = CultMesh.DocumentFromPeerSnapshot( + var caseVariantKeyHandle = CultMesh.DocumentFromPeerSnapshot( _ => Task.FromResult(new CultNetSnapshotResponseRawMessage { MessageId = "case-variant-key", @@ -2862,7 +2819,7 @@ public sealed class CultMeshStreamingTests CultMesh.PublicationDocument( firstKey, documentId: "daemon:first"), - CultMesh.PublicationDocument( + CultMesh.PublicationDocument( secondKey, documentId: "daemon:second", source: CultMeshDocumentPublicationSource.SingleFile(secondPath)) @@ -2876,10 +2833,10 @@ public sealed class CultMeshStreamingTests catalog.Documents.Select(document => document.DocumentId).Should().Equal("daemon:first", "daemon:second"); (await catalog.LatestAsync()).Text.Should().Be("first source"); - (await catalog.LatestAsync()).Text.Should().Be("second source"); + (await catalog.LatestAsync()).Text.Should().Be("second source"); catalog.Document().DocumentId.Should().Be("daemon:second"); catalog.Document().RouteHint.Description.Should().Be("publication catalog"); - catalog.Document().Sources.Should().ContainSingle().Which.SourceId.Should().Be("daemon:second"); + catalog.Document().Sources.Should().ContainSingle().Which.SourceId.Should().Be("daemon:second"); } [Test] @@ -2923,7 +2880,7 @@ public sealed class CultMeshStreamingTests CultMesh.PublicationDocument( firstKey, documentId: "local:first"), - CultMesh.PublicationDocument( + CultMesh.PublicationDocument( secondKey, documentId: "local:second", source: CultMeshDocumentPublicationSource.SingleFile(secondPath)) @@ -2936,16 +2893,16 @@ public sealed class CultMeshStreamingTests catalog.Documents.Select(document => document.DocumentId).Should().Equal("local:first", "local:second"); (await catalog.LatestAsync()).Text.Should().Be("first synced source"); - (await catalog.LatestAsync()).Text.Should().Be("second synced source"); + (await catalog.LatestAsync()).Text.Should().Be("second synced source"); node.Cache.Get(firstKey)!.Revision.Should().Be(31); (await node.Document(secondKey, CultMesh.Verse("starbridge", "unity-sync-catalog")) .LatestAsync()).Text.Should().Be("second synced source"); - (await node.Document(secondKey, CultMesh.Verse("starbridge", "unity-sync-catalog")) + (await node.Document(secondKey, CultMesh.Verse("starbridge", "unity-sync-catalog")) .LatestAsync()).Revision.Should().Be(32); } [Test] - public async Task PublicationHelpers_SyncConfiguredPeerSourceIntoLocalNodeAlias() + public async Task PublicationHelpers_SyncConfiguredPeerSourceIntoLocalNode() { var sourceCache = new CultCache(); var registry = new CultNetDocumentRegistry(CultDocumentRegistry.Shared); @@ -2974,7 +2931,7 @@ public sealed class CultMeshStreamingTests } }); - var synced = await CultMesh.SyncDocumentFromPublicationAsync( + var synced = await CultMesh.SyncDocumentFromPublicationAsync( node, CultMeshDocumentPublicationSource.PeerSnapshot( () => new MeshSnapshotSchemaClient(request => @@ -2990,12 +2947,12 @@ public sealed class CultMeshStreamingTests MessageIdPrefix = "mesh-test-publication-sync", PollInterval = TimeSpan.FromMilliseconds(10) }); - var localAlias = await node.Document(key, verse).LatestAsync(); + var local = await node.Document(key, verse).LatestAsync(); synced.Text.Should().Be("publication-synced"); synced.Revision.Should().Be(51); - localAlias.Text.Should().Be("publication-synced"); - localAlias.Revision.Should().Be(51); + local.Text.Should().Be("publication-synced"); + local.Revision.Should().Be(51); requests.Should().ContainSingle().Which.RecordKeys.Should().Equal(key.Value); } @@ -3102,7 +3059,7 @@ public sealed class CultMeshStreamingTests } [Test] - public async Task SnapshotHelpers_DecodeSameSchemaAliasFromForeignSchemaId() + public async Task SnapshotHelpers_DecodeFromForeignSchemaId() { var key = new CultRecordKey("mesh-note:snapshot-alias-foreign-schema"); var snapshot = new CultNetSnapshotResponseRawMessage @@ -3128,7 +3085,7 @@ public sealed class CultMeshStreamingTests } }; - var documents = await CultMesh.FetchSnapshotDocumentsAsync( + var documents = await CultMesh.FetchSnapshotDocumentsAsync( "cultnet://foreign-schema.test:3075", new CultMeshSnapshotRequestOptions { @@ -3172,9 +3129,9 @@ public sealed class CultMeshStreamingTests }; var cacheRegistry = CultMesh.CreateCultCacheDocumentRegistry( typeof(MeshNoteDocument), - typeof(MeshNoteAliasDocument)); + typeof(MeshNoteDocument)); var registry = CultMesh.CreateCultNetDocumentRegistry( - new[] { typeof(MeshNoteDocument), typeof(MeshNoteAliasDocument) }, + new[] { typeof(MeshNoteDocument), typeof(MeshNoteDocument) }, cacheRegistry); var endpoint = CultMesh.SnapshotEndpoint( "cultnet://foreign-schema.test:3075", @@ -3205,7 +3162,7 @@ public sealed class CultMeshStreamingTests } }); - var synced = await endpoint.SyncDocumentAsync(node, key.Value); + var synced = await endpoint.SyncDocumentAsync(node, key.Value); synced.Text.Should().Be("foreign-schema-synced"); node.Cache.Get(key)!.Text.Should().Be("foreign-schema-synced"); @@ -3213,7 +3170,7 @@ public sealed class CultMeshStreamingTests } [Test] - public async Task SnapshotFacade_SyncsRemoteDocumentIntoLocalNodeWithSameSchemaAlias() + public async Task SnapshotFacade_SyncsRemoteDocumentIntoLocalNode() { var sourceCache = new CultCache(); var registry = new CultNetDocumentRegistry(CultDocumentRegistry.Shared); @@ -3241,7 +3198,7 @@ public sealed class CultMeshStreamingTests } }); - var synced = await CultMesh.SyncDocumentFromPeerSnapshotAsync( + var synced = await CultMesh.SyncDocumentFromPeerSnapshotAsync( node, () => new MeshSnapshotSchemaClient(request => { @@ -3255,12 +3212,12 @@ public sealed class CultMeshStreamingTests DocumentRegistry = registry, Context = CultMesh.Verse("starbridge", "unity-raven").Context }); - var localAlias = await node.Document(key.Value, CultMesh.Verse("starbridge", "unity-raven")) + var local = await node.Document(key.Value, CultMesh.Verse("starbridge", "unity-raven")) .LatestAsync(); synced.Text.Should().Be("facade-synced"); synced.Revision.Should().Be(46); - localAlias.Text.Should().Be("facade-synced"); + local.Text.Should().Be("facade-synced"); node.Cache.Get(key)!.Revision.Should().Be(46); requests.Should().ContainSingle().Which.RecordKeys.Should().Equal(key.Value); } @@ -3300,9 +3257,9 @@ public sealed class CultMeshStreamingTests var sourceCache = new CultCache(); var cacheRegistry = CultMesh.CreateCultCacheDocumentRegistry( typeof(MeshNoteDocument), - typeof(MeshNoteAliasDocument)); + typeof(MeshNoteDocument)); var networkRegistry = CultMesh.CreateCultNetDocumentRegistry( - new[] { typeof(MeshNoteDocument), typeof(MeshNoteAliasDocument) }, + new[] { typeof(MeshNoteDocument), typeof(MeshNoteDocument) }, cacheRegistry); var key = new CultRecordKey("mesh-note:registry-helper"); await sourceCache.UpsertAsync(new MeshNoteDocument @@ -3313,7 +3270,7 @@ public sealed class CultMeshStreamingTests }, new CultRecordHandle(key)); var endpoint = "cultnet://registry-helper.test:3077"; - var documents = await CultMesh.FetchSnapshotDocumentsAsync( + var documents = await CultMesh.FetchSnapshotDocumentsAsync( endpoint, new CultMeshSnapshotRequestOptions { @@ -3324,15 +3281,15 @@ public sealed class CultMeshStreamingTests networkRegistry); var schemaId = cacheRegistry.GetRequired().SchemaId; - cacheRegistry.GetRequired().SchemaId.Should().Be(schemaId); + cacheRegistry.GetRequired().SchemaId.Should().Be(schemaId); + networkRegistry.GetByDocumentType(typeof(MeshNoteDocument)).Should().NotBeNull(); networkRegistry.GetByDocumentType(typeof(MeshNoteDocument)).Should().NotBeNull(); - networkRegistry.GetByDocumentType(typeof(MeshNoteAliasDocument)).Should().NotBeNull(); networkRegistry.GetBySchemaId(schemaId)!.DocumentType.Should().Be(typeof(MeshNoteDocument)); documents.Should().ContainSingle().Which.Text.Should().Be("registry-helper"); } [Test] - public async Task SnapshotEndpoint_ProvidesTypedHandlesAndSchemaAliases() + public async Task SnapshotEndpoint_ProvidesTypedHandles() { var sourceCache = new CultCache(); var registry = new CultNetDocumentRegistry(CultDocumentRegistry.Shared); @@ -3364,7 +3321,7 @@ public sealed class CultMeshStreamingTests } }); - var fetchedAlias = await surface.FetchDocumentAsync(key.Value); + var fetched = await surface.FetchDocumentAsync(key.Value); using var node = await CultMesh.CreateNodeAsync( Path.Combine(Path.GetTempPath(), $"cultmesh-snapshot-endpoint-{Guid.NewGuid():N}.ccmp"), new CultMeshNodeOptions @@ -3379,12 +3336,12 @@ public sealed class CultMeshStreamingTests DocumentRegistry = registry } }); - var syncedAlias = await surface.SyncDocumentAsync(node, key.Value); - var aliasHandle = surface.Document(key.Value); - var aliasLatest = await aliasHandle.LatestAsync(); + var syncedDocument = await surface.SyncDocumentAsync(node, key.Value); + var endpointHandle = surface.Document(key.Value); + var endpointLatest = await endpointHandle.LatestAsync(); var catalog = surface.Documents( CultMesh.SnapshotDocument(key.Value, "daemon:mesh-note:snapshot-endpoint")); - var catalogAlias = await catalog.LatestAsync(); + var catalogLatest = await catalog.LatestAsync(); await sourceCache.UpsertAsync(new MeshNoteDocument { Schema = "tests.mesh_note.v1", @@ -3392,7 +3349,7 @@ public sealed class CultMeshStreamingTests Revision = 20 }, new CultRecordHandle(key)); var syncedEndpoint = surface.SyncTo(node); - var syncedHandle = syncedEndpoint.Document(key.Value); + var syncedHandle = syncedEndpoint.Document(key.Value); var syncedLatest = await syncedHandle.LatestAsync(); await sourceCache.UpsertAsync(new MeshNoteDocument { @@ -3402,16 +3359,16 @@ public sealed class CultMeshStreamingTests }, new CultRecordHandle(key)); var syncedCatalog = syncedEndpoint.Documents( CultMesh.SnapshotDocument(key.Value)); - var syncedCatalogAlias = await syncedCatalog.LatestAsync(); + var syncedCatalogLatest = await syncedCatalog.LatestAsync(); - fetchedAlias.Text.Should().Be("snapshot-endpoint"); - syncedAlias.Text.Should().Be("snapshot-endpoint"); - aliasLatest.Revision.Should().Be(19); + fetched.Text.Should().Be("snapshot-endpoint"); + syncedDocument.Text.Should().Be("snapshot-endpoint"); + endpointLatest.Revision.Should().Be(19); catalog.Document().DocumentId.Should().Be("daemon:mesh-note:snapshot-endpoint"); - catalogAlias.Text.Should().Be("snapshot-endpoint"); + catalogLatest.Text.Should().Be("snapshot-endpoint"); syncedLatest.Text.Should().Be("snapshot-endpoint-synced"); node.Cache.Get(key)!.Revision.Should().Be(21); - syncedCatalogAlias.Text.Should().Be("snapshot-endpoint-catalog-synced"); + syncedCatalogLatest.Text.Should().Be("snapshot-endpoint-catalog-synced"); requests.Should().HaveCount(6); requests.Should().OnlyContain(request => request.SchemaIds == null && @@ -3464,7 +3421,7 @@ public sealed class CultMeshStreamingTests } [Test] - public async Task CollectionHandle_SupportsSameSchemaAliases() + public async Task CollectionHandle_IsIndexedInItsCatalogByTypeAndSchema() { var cache = new CultCache(); await cache.UpsertAsync( @@ -3477,14 +3434,12 @@ public sealed class CultMeshStreamingTests new CultRecordHandle(new CultRecordKey("mesh-note:collection"))); var collection = CultMesh.Collection(cache); - var alias = collection.AsSchemaAlias(); var catalog = CultMesh.Collections(collection); - alias.CollectionId.Should().Be(collection.CollectionId); - alias.SchemaName.Should().Be(collection.SchemaName); catalog.Collections.Should().ContainSingle().Which.Should().BeSameAs(collection); - catalog.TryGetCollection(out var catalogAlias).Should().BeTrue(); - catalogAlias.CollectionId.Should().Be(collection.CollectionId); + catalog.TryGetCollection(out var byType).Should().BeTrue(); + byType.Should().BeSameAs(collection); + catalog.TryGetCollection(out _).Should().BeFalse(); catalog.TryGetCollectionBySchema("tests.mesh_note.v1", out var byVersion).Should().BeTrue(); byVersion.Should().BeSameAs(collection); catalog.CollectionBySchema("tests.mesh_note").Should().BeSameAs(collection); @@ -3492,13 +3447,13 @@ public sealed class CultMeshStreamingTests .Should() .BeSameAs(collection); - var snapshot = await alias.LatestAsync(); + var snapshot = await collection.LatestAsync(); snapshot.Should().ContainSingle().Which.Text.Should().Be("collection-alias"); - var catalogSnapshot = await catalog.LatestAsync(); + var catalogSnapshot = await catalog.LatestAsync(); catalogSnapshot.Should().ContainSingle().Which.Revision.Should().Be(4); - CultMeshCollectionChange observed = null!; - using var subscription = catalog.WatchChanges(change => observed = change); + CultMeshCollectionChange observed = null!; + using var subscription = catalog.WatchChanges(change => observed = change); await cache.UpsertAsync( new MeshNoteDocument { @@ -3543,11 +3498,10 @@ public sealed class CultMeshStreamingTests node, key, CultMesh.Verse("starbridge", "unity-pilot")); - var alias = handle.AsSchemaAlias(); MeshNoteDocument observed = null!; using var subscription = handle.Watch(value => observed = value); - await alias.ReplaceAsync(new MeshNoteAliasDocument + await handle.ReplaceAsync(new MeshNoteDocument { Schema = "tests.mesh_note.v1", Text = "node-replaced", @@ -3985,20 +3939,6 @@ public sealed class CultMeshStreamingTests public int Revision { get; set; } } - [CultDocument("tests.mesh_note", "tests.mesh_note.v1")] - [MessagePackObject(AllowPrivate = true)] - internal sealed class MeshNoteAliasDocument - { - [Key(0)] - public string Schema { get; set; } = string.Empty; - - [Key(1)] - public string Text { get; set; } = string.Empty; - - [Key(2)] - public int Revision { get; set; } - } - [CultDocument("tests.mesh_publication_note", "tests.mesh_publication_note.v1")] [MessagePackObject(AllowPrivate = true)] internal sealed class MeshPublicationNoteDocument