CultNet selection cut1, commit 2a: delete _projectRecord, collapse the fourth schema matcher
_projectRecord (CultNetDatabaseSubscriptionServer.cs) reached no production caller and ran after authorization with no wire consumer. Removed the field, constructor parameter, and both call sites in Watch() and CreateProjectedSnapshot(); projection is a value on a v1 selection now, not a delegate. The two tests that used projectRecord to simulate a record's identity changing for the reconcile diff (DatabaseSubscriptionServer_AuthorizesRequestAndFiltersSnapshotAndLiveRecords, …ReconcilesDeliveredProjectionAndBodyDemandWhenAuthorityChanges) are rewritten to drive a real rename through the database (delete the old key, put the new one) instead, so they still prove authorization filtering and the Reconcile() diff/body-demand behavior. Self's ruling (docs/cultnet-selection-cut.md, 2026-09-22): the fourth schema-matching copy at CultNetDatabase.cs, serving CreateShardSnapshotResponse and SchemaMatchesCatalogFilter (MatchesRequestedSchema + a duplicate InferSchemaName), collapses into CultNetSchemaAliasMatching.MatchesAny, the one matcher landed in commit 1. Networking tests: 162/162 (was 162/162 after commit 1; no count change, two tests rewritten not added). Negative grep: _projectRecord|projectRecord empty; MatchesRequestedSchema gone (one remaining substring hit is RawSnapshotPayloadMatchesSchema in CultMeshSnapshots.cs, the Mesh copy this commit does not touch — collapses in the next commit). Mesh collapse (§4/§11 of the map, ~365 gross lines across CultMesh.cs, CultMeshSnapshots.cs, CultMeshClient.cs, CultMeshBodyDemand.cs) is not in this commit; it is large enough to build on its own and follows as commit 2b. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
This commit is contained in:
parent
17d10e017f
commit
0787608cef
3 changed files with 37 additions and 79 deletions
|
|
@ -13,8 +13,9 @@ namespace GameCult.Networking
|
|||
{
|
||||
/// <summary>
|
||||
/// Publishes live database changes through any schema-v0 server transport.
|
||||
/// Optional record projection runs after authorization and owns both initial
|
||||
/// snapshot and live-update delivery for a peer.
|
||||
/// Selection match runs after authorization and owns both initial
|
||||
/// snapshot and live-update delivery for a peer. Projection (header vs.
|
||||
/// document) is a value on the request's selection, not a delegate.
|
||||
/// </summary>
|
||||
public sealed class CultNetDatabaseSubscriptionServer : IDisposable
|
||||
{
|
||||
|
|
@ -24,7 +25,6 @@ namespace GameCult.Networking
|
|||
private readonly Func<CultNetDatabaseUnsubscribeMessage, ICultNetSchemaServerPeer, Task> _unsubscribe;
|
||||
private readonly Func<CultNetDatabaseSubscribeMessage, ICultNetSchemaServerPeer, bool>? _authorizeRequest;
|
||||
private readonly Func<CultNetDatabaseSubscribeMessage, ICultNetSchemaServerPeer, string, string, bool>? _authorizeRecord;
|
||||
private readonly Func<CultNetDatabaseSubscribeMessage, ICultNetSchemaServerPeer, CultNetRawDocumentRecord, CultNetRawDocumentRecord?>? _projectRecord;
|
||||
private readonly ICultNetSchemaServerPeerLifecycle? _peerLifecycle;
|
||||
private readonly ConcurrentDictionary<SubscriptionKey, IDisposable> _subscriptions =
|
||||
new ConcurrentDictionary<SubscriptionKey, IDisposable>(SubscriptionKeyComparer.Instance);
|
||||
|
|
@ -40,14 +40,12 @@ namespace GameCult.Networking
|
|||
ICultNetSchemaServer server,
|
||||
CultNetDatabase database,
|
||||
Func<CultNetDatabaseSubscribeMessage, ICultNetSchemaServerPeer, bool>? authorizeRequest = null,
|
||||
Func<CultNetDatabaseSubscribeMessage, ICultNetSchemaServerPeer, string, string, bool>? authorizeRecord = null,
|
||||
Func<CultNetDatabaseSubscribeMessage, ICultNetSchemaServerPeer, CultNetRawDocumentRecord, CultNetRawDocumentRecord?>? projectRecord = null)
|
||||
Func<CultNetDatabaseSubscribeMessage, ICultNetSchemaServerPeer, string, string, bool>? authorizeRecord = null)
|
||||
{
|
||||
_server = server ?? throw new ArgumentNullException(nameof(server));
|
||||
_database = database ?? throw new ArgumentNullException(nameof(database));
|
||||
_authorizeRequest = authorizeRequest;
|
||||
_authorizeRecord = authorizeRecord;
|
||||
_projectRecord = projectRecord;
|
||||
_subscribe = HandleSubscribeAsync;
|
||||
_unsubscribe = HandleUnsubscribeAsync;
|
||||
_server.OnCultNet(_subscribe);
|
||||
|
|
@ -235,13 +233,10 @@ namespace GameCult.Networking
|
|||
|
||||
var sourceRecordKey = ResolveChangeRecordKey(change);
|
||||
var matched = CreateMatchedRecord(change, request, peer);
|
||||
var projected = matched;
|
||||
if (projected != null && _projectRecord != null)
|
||||
projected = _projectRecord(request, peer, projected);
|
||||
ApplyProjectedChange(
|
||||
projection,
|
||||
sourceRecordKey,
|
||||
projected,
|
||||
matched,
|
||||
peer,
|
||||
subscriptionId);
|
||||
}
|
||||
|
|
@ -305,18 +300,16 @@ namespace GameCult.Networking
|
|||
RecordKeys = request.RecordKeys
|
||||
});
|
||||
var bySourceRecordKey = new Dictionary<string, CultNetRawDocumentRecord>(StringComparer.Ordinal);
|
||||
var projectedRecordKeys = new HashSet<string>(StringComparer.Ordinal);
|
||||
var matchedRecordKeys = new HashSet<string>(StringComparer.Ordinal);
|
||||
foreach (var source in snapshot.Documents)
|
||||
{
|
||||
var sourceRecordKey = source.RecordKey;
|
||||
if (_authorizeRecord?.Invoke(request, peer, sourceRecordKey, source.SchemaId) == false)
|
||||
continue;
|
||||
var projected = _projectRecord == null ? source : _projectRecord(request, peer, source);
|
||||
if (projected == null) continue;
|
||||
if (!projectedRecordKeys.Add(projected.RecordKey))
|
||||
if (!matchedRecordKeys.Add(source.RecordKey))
|
||||
throw new InvalidOperationException(
|
||||
$"Database subscription projection produced duplicate record key '{projected.RecordKey}'.");
|
||||
bySourceRecordKey[sourceRecordKey] = projected;
|
||||
$"Database subscription snapshot produced duplicate record key '{source.RecordKey}'.");
|
||||
bySourceRecordKey[sourceRecordKey] = source;
|
||||
}
|
||||
return new ProjectedSnapshot(bySourceRecordKey);
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in a new issue