From 4c33a62b29d3f106b4cf93eeba4e9a922a2e5750 Mon Sep 17 00:00:00 2001 From: Meta Vens Date: Tue, 22 Sep 2026 03:54:36 +0200 Subject: [PATCH] CultNet selection cut1, commit 2e: mutation entries for the Mesh collapse scripts/mutate-cultnet-selection-mesh.entries.ps1 covers the two rules moved in commit 2d against tests/GameCult.Mesh.Tests: ResolveDefaultSelection's "no schema filter when keys are given" default, and ReadDocumentFromSnapshotResponse's recordKey-anchored exact read (including the foreign-schema-id decode fallback it still honors). M0: green, 87 passed (CultMeshStreamingTests). Verdicts: - MESH-DEFAULT-Revert: KILLED - MESH-DEFAULT-Loosening: SURVIVED - MESH-KEY-Revert: KILLED - MESH-KEY-Loosening: SURVIVED - MESH-FOREIGN-Revert: KILLED - Final: green, 87 passed. All restores byte-exact (working tree clean after the run). Both SURVIVED entries are recorded as fixture gaps, not swapped for easier mutants: no test in CultMeshStreamingTests.cs passes an explicit empty (non-null) recordKeys array, and none varies a record key's case, so nothing distinguishes MESH-DEFAULT-Loosening's `recordKeys != null` from the correct `recordKeys is { Count: > 0 }`, or MESH-KEY-Loosening's OrdinalIgnoreCase from the correct Ordinal comparison. MESH-FOREIGN has a revert entry only; no distinct, still-wrong "loosening" of "decode successfully as TDocument" was found that isn't already one of the other two entries. Co-Authored-By: Claude Sonnet 5 --- .../mutate-cultnet-selection-mesh.entries.ps1 | 68 +++++++++++++++++++ 1 file changed, 68 insertions(+) create mode 100644 scripts/mutate-cultnet-selection-mesh.entries.ps1 diff --git a/scripts/mutate-cultnet-selection-mesh.entries.ps1 b/scripts/mutate-cultnet-selection-mesh.entries.ps1 new file mode 100644 index 00000000..7f32360f --- /dev/null +++ b/scripts/mutate-cultnet-selection-mesh.entries.ps1 @@ -0,0 +1,68 @@ +# Entries for scripts/mutate-dotnet.ps1: CultNet typed selection, Cut 1, commit 2d - the CultMesh +# collapse (docs/cultnet-selection-cut.md, sections 4/7/11). Targets: src/GameCult.Mesh/CultMesh.cs +# (ReadDocumentFromSnapshotResponse's one exact read) and src/GameCult.Mesh/CultMeshSnapshots.cs +# (ResolveDefaultSelection's "no schema filter when keys are given" rule). Test project: +# tests/GameCult.Mesh.Tests. +# +# Every entry below carries its own File, so this runs as one invocation with both -Target paths. +# +# Two of the three loosening entries here SURVIVED against the current fixtures (recorded, not +# swapped for an easier mutant): MESH-DEFAULT-Loosening and MESH-KEY-Loosening. Both are genuine +# weaker readings of the rule they sit beside; no test in tests/GameCult.Mesh.Tests exercises an +# explicit empty (non-null) recordKeys array or a record-key case variation, so nothing currently +# distinguishes the loosened behavior from the correct one. That is a fixture gap in +# CultMeshStreamingTests.cs, not evidence the mutant is unreachable in principle. + +@( + @{ + Id = 'MESH-DEFAULT-Revert' + Rule = 'ResolveDefaultSelection: an explicit non-empty recordKeys with no schemaIds means no schema filter, not the document type''s own schema.' + Mutant = 'revert' + File = 'src/GameCult.Mesh/CultMeshSnapshots.cs' + Killer = 'FullyQualifiedName=GameCult.Mesh.Tests.CultMeshStreamingTests.SnapshotEndpoint_ProvidesTypedHandlesAndSchemaAliases' + Old = 'var schemas = schemaIds != null + ? Clean(schemaIds) + : (recordKeys is { Count: > 0 } ? null : new[] { descriptor.SchemaId });' + New = 'var schemas = schemaIds != null ? Clean(schemaIds) : new[] { descriptor.SchemaId };' + }, + @{ + Id = 'MESH-DEFAULT-Loosening' + Rule = 'ResolveDefaultSelection: the no-schema-filter branch triggers on a non-empty recordKeys, not merely a non-null one.' + Mutant = 'loosening' + File = 'src/GameCult.Mesh/CultMeshSnapshots.cs' + Killer = 'FullyQualifiedName=GameCult.Mesh.Tests.CultMeshStreamingTests.SnapshotEndpoint_ProvidesTypedHandlesAndSchemaAliases' + Old = 'recordKeys is { Count: > 0 } ? null : new[] { descriptor.SchemaId }' + New = 'recordKeys != null ? null : new[] { descriptor.SchemaId }' + }, + @{ + Id = 'MESH-KEY-Revert' + Rule = 'ReadDocumentFromSnapshotResponse: a candidate must name this recordKey - the one exact read never returns a record under the wrong key.' + Mutant = 'revert' + File = 'src/GameCult.Mesh/CultMesh.cs' + Killer = 'FullyQualifiedName=GameCult.Mesh.Tests.CultMeshStreamingTests.DocumentHandle_ReadsRemotePeerSnapshotsAsTypedDocuments' + Old = 'if (!string.Equals(candidate.RecordKey, recordKey, StringComparison.Ordinal)) + continue;' + New = '' + }, + @{ + Id = 'MESH-KEY-Loosening' + Rule = 'ReadDocumentFromSnapshotResponse: the recordKey match is exact (ordinal), not case-insensitive.' + Mutant = 'loosening' + File = 'src/GameCult.Mesh/CultMesh.cs' + Killer = 'FullyQualifiedName=GameCult.Mesh.Tests.CultMeshStreamingTests.DocumentHandle_ReadsRemotePeerSnapshotsAsTypedDocuments' + Old = 'if (!string.Equals(candidate.RecordKey, recordKey, StringComparison.Ordinal))' + New = 'if (!string.Equals(candidate.RecordKey, recordKey, StringComparison.OrdinalIgnoreCase))' + }, + @{ + Id = 'MESH-FOREIGN-Revert' + Rule = 'ReadDocumentFromSnapshotResponse: a foreign/runtime-generated schema id at the right recordKey still matches when its payload decodes as TDocument.' + Mutant = 'revert' + File = 'src/GameCult.Mesh/CultMesh.cs' + Killer = 'FullyQualifiedName=GameCult.Mesh.Tests.CultMeshStreamingTests.DocumentHandle_ReadsRemotePeerSnapshotsAsTypedDocuments' + Old = 'if (string.Equals(candidate.SchemaId, schemaId, StringComparison.Ordinal) || + CultNetSchemaAliasMatching.Matches(candidate.SchemaId, descriptor) || + TryDecodeAsMessagePack(candidate, out _))' + New = 'if (string.Equals(candidate.SchemaId, schemaId, StringComparison.Ordinal) || + CultNetSchemaAliasMatching.Matches(candidate.SchemaId, descriptor))' + } +)