CultNet refuses a variant on both live-change paths, loudly, by key

A load or write that landed a variant reached CultNet subscribers as a plain
"added" record carrying the full resolved payload; a later base edit published
only the base, so the subscriber's copy of the variant went stale. Under Q6
CultNet carries no variants until its own cut. Both live paths now refuse a
change whose key holds a variant, after selection and authorization match, and
send the matching subscriber a CultNetErrorMessage naming the variant and its
base. Refused loudly rather than omitted: an omission is a silent hole in the
subscriber's view, and the snapshot path already refuses by throwing.

Tests: a real load through a real RUDP subscription never delivers the variant
as a record and delivers the typed error; the database server's change builder
refuses the same change.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
This commit is contained in:
Meta Vens 2026-09-29 06:58:51 +02:00
commit cdb8ee5dcc
4 changed files with 167 additions and 7 deletions

View file

@ -315,7 +315,18 @@ namespace GameCult.Networking
}
var sourceRecordKey = ResolveChangeRecordKey(change);
var matched = CreateMatchedRecord(change, request, peer);
CultNetRawDocumentRecord? matched;
try
{
matched = CreateMatchedRecord(change, request, peer);
}
catch (NotSupportedException refusal)
{
// Q6: a variant is not a record CultNet can carry; the subscriber that would have received it is told, by key.
peer.SendCultNet(new CultNetErrorMessage { Error = refusal.Message });
return;
}
ApplyProjectedChange(
projection,
sourceRecordKey,
@ -541,6 +552,7 @@ namespace GameCult.Networking
if (kind == CultNetDatabaseChangeKind.Removed || document == null)
return null;
CultNetDocumentRegistry.RefuseVariantChange(_database.Cache, key);
return _database.Documents.ToRawRecord(descriptor, key, document, DateTimeOffset.UtcNow.ToString("O"));
}