CultNet selection cut1, commit 2b: collapse IsSameCultDocumentSchema into the one alias matcher
CultMesh.IsSameCultDocumentSchema (CultMesh.cs) and the decode-time alias check
in CultMeshSnapshots.DecodeSnapshotDocuments both re-implemented schema-identity
comparison independently of CultNetSchemaAliasMatching, the one matcher landed
in commit 1. Both now call CultNetSchemaAliasMatching.Matches; the private
InferSchemaName duplicated at CultMeshSnapshots.cs is deleted (Matches already
applies the same .vN inference internally).
Spec discrepancy, reported per the Hands brief (map contradicted by the Body):
docs/cultnet-selection-cut.md section 4 lists CultMeshSnapshots.cs:1033-1047
(RawSnapshotPayloadMatchesSchema) and :1078-1088 (InferSchemaName) as deletions,
on the stated reasoning that decode no longer needs a client-side re-filter
because the server's v1 answer is exact. Deleting RawSnapshotPayloadMatchesSchema
outright breaks two existing, still-relevant Mesh tests:
SnapshotHelpers_DecodeSameSchemaAliasFromForeignSchemaId and
SnapshotEndpoint_SyncsCompatibleForeignSchemaIdIntoLocalCache
(CultMeshStreamingTests.cs). Both cover a wire schemaId this runtime cannot
resolve by any alias at all (a foreign/runtime-generated id, e.g.
"runtime.generated.mesh-note.ui.42") where the only way to decode is to trust
the payload's own embedded schemaVersion. That is a decode capability, not a
re-filter of an already-exact server answer, and the map's stated reason for
deleting it does not apply to it. Smallest change keeping the map's intent
true: kept RawSnapshotPayloadMatchesSchema and TryReadSchemaVersion, deleted
only the duplicate InferSchemaName inside it and routed the comparison through
CultNetSchemaAliasMatching.Matches.
Test counts, no regressions: Networking 162/162, Mesh 252/253 (the one
pre-existing skip), Caching 188/188.
Negative grep: MatchesRequestedSchema empty. The one remaining
"MatchesSchema(" grep hit is RawSnapshotPayloadMatchesSchema's own name and
declaration, kept for the reason above.
Still outstanding from the map's Mesh collapse (§4/§11, ~365 gross lines):
the five cloned CultMeshSnapshotRequestOptions-carrying option records, the
"no schema filter when keys are given" rule (x3), CleanSnapshotFilter, the
four-tier ReadDocumentFromSnapshotResponse fallback, and every selector
literal in CultMeshClient.cs/CultMeshBodyDemand.cs/CultMesh.cs peer-snapshot
and body-subscribe construction. Those require CultMeshSnapshotRequestOptions
(and the v0 wire builders that read it) to carry a Selection instead of
separate SchemaIds/RecordKeys — a wider, structural change across Mesh's
public surface that is not done in this commit. Recorded as the next slice.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
This commit is contained in:
parent
0787608cef
commit
c5b03cb455
2 changed files with 12 additions and 26 deletions
|
|
@ -3471,13 +3471,15 @@ namespace GameCult.Mesh
|
|||
CultDocumentRegistry.Shared.GetRequired<TDocument>());
|
||||
}
|
||||
|
||||
// The one schema-alias matcher (docs/cultnet-selection-cut.md, D4): every runtime-side
|
||||
// schema identity decision, wire or local, goes through CultNetSchemaAliasMatching.
|
||||
private static bool IsSameCultDocumentSchema(
|
||||
Type documentType,
|
||||
CultDocumentDescriptor descriptor,
|
||||
string? schemaId = null)
|
||||
{
|
||||
if (!string.IsNullOrWhiteSpace(schemaId) &&
|
||||
string.Equals(schemaId, descriptor.SchemaId, StringComparison.Ordinal))
|
||||
CultNetSchemaAliasMatching.Matches(schemaId, descriptor))
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
|
@ -3492,8 +3494,7 @@ namespace GameCult.Mesh
|
|||
return false;
|
||||
}
|
||||
|
||||
return string.Equals(storedDescriptor.SchemaName, descriptor.SchemaName, StringComparison.Ordinal) &&
|
||||
string.Equals(storedDescriptor.SchemaVersion, descriptor.SchemaVersion, StringComparison.Ordinal);
|
||||
return CultNetSchemaAliasMatching.Matches(storedDescriptor.SchemaVersion, descriptor);
|
||||
}
|
||||
|
||||
private static TDocument ConvertUntypedDocument<TDocument>(object document)
|
||||
|
|
|
|||
|
|
@ -1002,8 +1002,8 @@ namespace GameCult.Mesh
|
|||
binding != null &&
|
||||
typeof(TDocument).IsAssignableFrom(binding.DocumentType);
|
||||
var canDeserializeAsSchemaAlias =
|
||||
string.Equals(record.SchemaId, descriptor.SchemaId, StringComparison.Ordinal) ||
|
||||
(binding != null && IsSameCultDocumentSchema(binding.DocumentType, descriptor)) ||
|
||||
CultNetSchemaAliasMatching.Matches(record.SchemaId, descriptor) ||
|
||||
(binding != null && CultNetSchemaAliasMatching.Matches(binding.SchemaId, descriptor)) ||
|
||||
RawSnapshotPayloadMatchesSchema(record.Payload, descriptor);
|
||||
if (!canDeserializeWithBinding && !canDeserializeAsSchemaAlias)
|
||||
continue;
|
||||
|
|
@ -1030,20 +1030,17 @@ namespace GameCult.Mesh
|
|||
return documents;
|
||||
}
|
||||
|
||||
// Decode-time fallback for a wire schemaId this runtime does not recognize by any alias
|
||||
// (e.g. a foreign/runtime-generated id): trust the payload's own embedded schemaVersion
|
||||
// instead. This is a decode concern, not a selector engine — the server's answer is not
|
||||
// re-filtered here, and schema identity itself still goes through the one alias matcher.
|
||||
private static bool RawSnapshotPayloadMatchesSchema(
|
||||
byte[] payload,
|
||||
CultDocumentDescriptor descriptor)
|
||||
{
|
||||
var schemaVersion = TryReadSchemaVersion(payload);
|
||||
if (string.IsNullOrWhiteSpace(schemaVersion))
|
||||
return false;
|
||||
|
||||
if (string.Equals(schemaVersion, descriptor.SchemaVersion, StringComparison.Ordinal))
|
||||
return true;
|
||||
|
||||
var schemaName = InferSchemaName(schemaVersion!);
|
||||
return !string.IsNullOrWhiteSpace(schemaName) &&
|
||||
string.Equals(schemaName, descriptor.SchemaName, StringComparison.Ordinal);
|
||||
return !string.IsNullOrWhiteSpace(schemaVersion) &&
|
||||
CultNetSchemaAliasMatching.Matches(schemaVersion!, descriptor);
|
||||
}
|
||||
|
||||
private static string? TryReadSchemaVersion(byte[] payload)
|
||||
|
|
@ -1074,17 +1071,5 @@ namespace GameCult.Mesh
|
|||
|
||||
return null;
|
||||
}
|
||||
|
||||
private static string? InferSchemaName(string schemaVersion)
|
||||
{
|
||||
var marker = schemaVersion.LastIndexOf(".v", StringComparison.Ordinal);
|
||||
if (marker <= 0 || marker + 2 >= schemaVersion.Length)
|
||||
return null;
|
||||
|
||||
var version = schemaVersion.Substring(marker + 2);
|
||||
return version.All(char.IsDigit)
|
||||
? schemaVersion.Substring(0, marker)
|
||||
: null;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in a new issue