From 0ae8226ccbec99e79ff226085bfa75d7866fca81 Mon Sep 17 00:00:00 2001 From: Meta Vens Date: Sat, 19 Sep 2026 20:14:16 +0200 Subject: [PATCH] Cut 7: retire a test Cut 6b made vacuous, and the invariant it claimed Cut 3's harness reported OutOfArcConsumesNoDraw as "not yet reached" -- no mutation could turn it red. Chasing that rather than accepting it found the reason, and it is not a fixture defect. The test asserted that a shot gated to zero draws nothing from ItemManager. Random, so the shared stream advanced exactly as if the shot had never queued. Cut 6b moved every roll onto a per-shot local generator seeded from (zone, shot id), so Commit stopped touching that stream on EVERY path. The test then passed for a reason unrelated to arcs -- it passed identically with the target dead ahead -- and the rule it named stopped existing along with the stream it was about. The short-circuit it guarded is now a cheap guard, not an invariant, and Commit's comment was still asserting otherwise. Rewritten as CombatNeverDrawsFromTheSharedStream, a Theory over both an out-of-arc and an in-arc target, pinning the rule that IS live after 6b: no combat path draws from the shared stream at all. Verified by hand -- restoring the shared-stream read in Commit turns the in-arc case red while the out-of-arc case stays green, which is exactly why the old test could not have caught it. 218 tests pass. All six mutation harnesses run clean with tree-clean PASS. Co-Authored-By: Claude Opus 5 --- Assets/Scripts/ServerShared/FireControl.cs | 11 +++++++--- .../FireAuthorityTests.cs | 21 ++++++++++++------- 2 files changed, 21 insertions(+), 11 deletions(-) diff --git a/Assets/Scripts/ServerShared/FireControl.cs b/Assets/Scripts/ServerShared/FireControl.cs index 214f0bc2d..e9cc2829f 100644 --- a/Assets/Scripts/ServerShared/FireControl.cs +++ b/Assets/Scripts/ServerShared/FireControl.cs @@ -290,9 +290,14 @@ public static class FireControl // R3/R4: the one roll. p_base was frozen at fire; the only thing measured live is how far the target has // actually strayed, by now, from where a straight-line projection of its fire-time velocity said it would - // be -- forgiven by the targeting system's Tracking, likewise frozen at fire. A shot gated to zero at fire - // (out of arc, out of range, unlocked, undetected) draws nothing here (short-circuit below): the RNG - // sequence is exactly as if the shot had never queued. + // be -- forgiven by the targeting system's Tracking, likewise frozen at fire. + // + // Cut 7: the short-circuit below (`p > 0f &&`) is a guard, NOT an invariant. It used to be one -- a shot + // gated to zero at fire had to draw nothing so the shared stream advanced exactly as if it had never + // queued -- but Cut 6b gave every shot its own generator, seeded from (zone, shot id) and discarded here, + // so whether a gated shot draws is unobservable from anywhere. The claim this comment used to make is + // gone with the stream it was about, and the test that asserted it became vacuous the same moment; what + // replaced it pins the live rule instead (combat touches no shared stream, on any path). private static ShotOutcome Commit(Zone zone, PendingShot shot, float now) { // Cut 6b, 6.1 (Soul finding 6): a shot's dice belong to the shot, not to whatever else happened to diff --git a/tests/Aetheria.Shared.Tests/FireAuthorityTests.cs b/tests/Aetheria.Shared.Tests/FireAuthorityTests.cs index 732b35f9f..3f65f24d8 100644 --- a/tests/Aetheria.Shared.Tests/FireAuthorityTests.cs +++ b/tests/Aetheria.Shared.Tests/FireAuthorityTests.cs @@ -256,15 +256,20 @@ public sealed class FireAuthorityTests : IDisposable Assert.Equal(unaided.Items.GameplaySettings.UnaidedAccuracy, FireControl.HitProbability(unaided.Weapon, unaided.Shooter, unaided.Target), 3); } - // The gate is a gate, not a penalty: an out-of-arc commit consumes exactly zero draws from the shared RNG - // stream. Mutation: roll first and multiply the result by zero -- that still advances the stream by one - // draw, which this test would catch by seeing a different next value than an untouched stream produces. - [Fact] - public void OutOfArcConsumesNoDraw() + // Cut 7 (docs/fire-control-cut.md): this was OutOfArcConsumesNoDraw, which asserted that a shot gated to + // zero left ItemManager.Random untouched. Cut 6b (6.1) moved the roll onto a per-shot local generator, so + // Commit stopped touching that stream on EVERY path and the old test passed for a reason that had nothing + // to do with arcs -- it would have passed just as well with the target dead ahead, and no mutation of the + // short-circuit it named could ever turn it red. Rewritten to pin the rule that is actually live: no + // combat path draws from the shared stream, in arc or out. Mutation: restore the shared-stream read in + // Commit; the in-arc case then goes red. + [Theory] + [InlineData(100f, 0f)] // directly abeam: gated to zero, outside the default arc + [InlineData(0f, 100f)] // dead ahead: a real firing solution that actually rolls + public void CombatNeverDrawsFromTheSharedStream(float x, float z) { - var e = Build(TestSettings()); - // Directly abeam -- outside even the wide 170-degree default arc dead ahead. - e.Target.Position = float3(100, 0, 0); + var e = Build(TestSettings(), accuracy: 1, resolution: 1, spread: 0); + e.Target.Position = float3(x, 0, z); const uint seed = 4242u; var untouched = new Random(seed);