Cut 9: the die is not a die
9.1, blocking. FireControl seeded CultMath's xorshift32 per shot and drew once. NextFloat returns the top 24 bits of the FIRST round, and one round cannot carry ShotId's low-bit variation into the high bits -- so every zone's hit roll spanned about an eighth, with the threshold fixed at zone creation. A shot was a step function of p: below the band it never hit, above it always did. An unaided shooter hit 0 of 18,926 shots. That is the operator's "no hits registering," and being stable per zone is why it came and went. The seed derivation is unchanged -- still a pure function of (zone, shot id), Cut 6b's rule -- and only its diffusion into the first output changes, via an fmix32 finalizer. Measured across six zone seeds: hit fraction at p=.3 went from 0.0% in five of six zones to 29-31%, and at p=.6 to 58-61%, with the roll spanning the full range. The defect survived three cuts because nothing in the campaign measured a distribution -- every fixture uses accuracy 1 or 0, and a constant satisfies a determinism test perfectly. TheDieIsUniform now asserts the observed hit fraction is within .08 of p across several zone seeds, which is the test whose absence was the real defect. 9.2. Sigma is floored at half a cell. HullKernel approximates a continuous Gaussian with a discrete sum over occupied cells, and that sum collapses once sigma falls well under one cell against an aim point that is not exactly on a cell centre -- true of every shipped hull. Past Precision ~4, pOnHull went to zero and a better targeting system made the weapon unable to hit anything. 9.3. An active entity's Target is now always a live entity it has info on. Cut 8's _active guard could never have fixed the operator's LockWeapon crash -- that code only runs on active entities, and cut8's own harness header says so. The live route was dock, target dies, undock; Deactivate disposed the subscription that nulls a stale Target and Activate reseeded EntityInfoGathered without reconciling it. Still not a TryGetValue in LockWeapon. 229 tests pass. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
parent
16d8493e0c
commit
6db6dc78f3
4 changed files with 797 additions and 5 deletions
|
|
@ -285,6 +285,19 @@ public abstract class Entity
|
|||
// subscribe with whatever Target already holds, which is harmless -- TargetItem starts null anyway.
|
||||
_subscriptions.Add(Target.Subscribe(_ => TargetItem.Value = null));
|
||||
|
||||
// 9.3 (docs/fire-control-cut.md, Soul C3): a Target surviving Deactivate can point at an entity
|
||||
// this zone removed while inactive -- Deactivate disposes the Zone.Entities.ObserveRemove
|
||||
// subscription that is the only thing that nulls a stale Target, and EntityInfoGathered was just
|
||||
// rebuilt above from the zone's *current* membership, not from whatever Target still remembers.
|
||||
// Reconcile here, now that both the fresh EntityInfoGathered and the Target-change subscription
|
||||
// above are live (so this write also clears TargetItem through it): an active entity's Target
|
||||
// must always be an entity it has info on. Activate owns this reconciliation rather than
|
||||
// Deactivate nulling Target outright, because nulling on every dock would throw away a target
|
||||
// that is still alive and simply never changed while docked -- the common case, and not the one
|
||||
// that crashed.
|
||||
if (Target.Value != null && !EntityInfoGathered.ContainsKey(Target.Value))
|
||||
Target.Value = null;
|
||||
|
||||
if(WeaponGroups.All(wg=>!wg.items.Any()))
|
||||
GenerateWeaponGroups();
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in a new issue