Entity.Death, the owner of the stream, now ends after its first cause. A blast that destroyed a
cockpit fired Death, which removed and deactivated the entity, and the blast's own DamageHull then
raised a second Death to every subscriber but Zone's idempotent handler. Every damage path gets the
guard because none of them raise Death themselves.
New pins: one blast killing three ships (a break after the first kill survives the old suite), a
shieldless ship outside the disc receiving nothing, a cockpit-kill blast and a direct hull kill each
raising Death exactly once.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Each rule below was protected only by a test a mutant passed. New or
strengthened tests, with the mutant each one kills:
- AContactOrDelayedBlastOnAMissDoesNothing: ApplyBlastHit's miss guard.
- ToWorldPointIsTheInverseOfToSchematicPointAtANonAxisFacing and
AContactBlastLandsOnTheCellItHitAtANonAxisFacing: ToWorldPoint's right axis,
asserted per cell at facing (2,1); TurningAfterCommit now compares per cell.
- ProximityBurstPositionIsThePredictedInterceptForAMovingTarget: a moving
target and an intercept solved in the test, not Durability <= before.
- AnUntouchedEntitysShieldIsNotConsulted: Detonate's skip of untouched
entities.
- TheFusePointStaysOnMetalAcrossAConcaveGap: the delayed point clamps at the
first gap (the lane's walk ends there).
- ShieldPaysForWhatReachesIt asserts the reserve dropped by the covered share;
AShieldRaisedBetweenCommitAndArrivalAbsorbsTheBlast and
AShieldDroppedBetweenCommitAndArrivalDoesNotAbsorbTheBlast replace the
outcome-flags-only check with the shield state flipped between commit and
arrival.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
F1: RectDiskOverlap counted a whole square when a cell edge sat exactly r from
the disc centre (`h < yhi`, `-h > ylo`). The comparisons are inclusive now, so
the chord bounds the piece. A proximity burst on an integer centre of mass
delivered 127.32 of 100 at BlastRadius 1 and 100.80 at 3.
F2: delete Detonate's distance prefilter and the radius <= 0 guard. The
prefilter measured from the centre of mass with the bounding box's
half-diagonal, which is not a bound on how far a hull's cells reach; it culled
real overlap on an L-shaped hull and on the shipped Longinus corners.
RectDiskOverlap is the single decider. An untouched entity is still skipped
(its covered list is never allocated).
F3: Detonate iterates a snapshot of zone.Entities, as Zone.Update does. A
lethal blast removed the entity from the live collection and the next MoveNext
threw, leaving the shot pending so it detonated again the next tick.
Tests: tangent discs through Fire and Detonate, an L-shaped hull, grazing
blasts at the farthest corner of Longinus and LonginusX (expected values from
a numeric overlap), and a lethal blast that must resolve once.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Geometry, absorption order, symmetry/frame, shields and fuse tests from the
cut doc's own verification list, plus Soul's three fold-in probes (a
radius-without-a-fuse damage-outcome test, a moving-target proximity-burst
pin, and Detonate's nonpositive-radius guard) and the two catalog probes
(shipped-catalog neutrality on BlastRadius/Fuse, and a WeaponFuse/BlastRadius
round-trip through a written and reopened catalog copy).
Fixture: SchematicCellSize 2, target off the origin, hull centre of mass not
an integer cell, one facing with |fx| > |fy| -- the rules the cut doc names
for every blast test. Geometry expectations come from exact half-split
symmetry where possible (TheShareOffTheHullIsLost, ShieldPaysForWhatReachesIt)
and from an independent numeric area integral otherwise (EachCellTakesItsShare
OfTheDisc, TheFusePointStaysOnMetal), never from the SUT's own overlap code.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>