re: making turrets targets does not save the escort — the effect is inside the noise

The Stage-02 outcome write-up ended by naming "turrets near the asset must
become targets" as the fix worth ~50% of the escort damage. That was an
inference from a co-presence attribution, not a measurement. Run it and it
does not hold.

Also corrects the run labelling: pilot.py gained the SYLPH_KILL_TURRETS gate
two minutes before mission02 started, so mission02 was already a treatment run,
not a second baseline. Only mission01 (0 of 3968 pilot frames targeting a
turret) is the baseline.

At a common t=428s: baseline 46.9% escort hull, treatment 44.5% and 53.0%. The
two runs of the same arm differ by more than either differs from the baseline,
and the escort still reaches zero at t~590-670s in all three. So the
transferable finding is the power limit: one 430s flight cannot resolve an
effect below ~9 percentage points, and every single-run pilot conclusion,
including this one's, is inside it.

What does reproduce: the assault is scripted (onset 166/167/166s), and the
e007/e010 damage split is 50/50 in all three arms including the one that never
fires at a turret -- so that attribution measures the wave script, not us.

Also records that the viewer's include_external hypothesis in BACKLOG is dead
(it defaults true and is threaded through unchanged).
This commit is contained in:
2026-08-11 05:29:52 +00:00
parent f4d59c5783
commit 5c3e3dfe47
6 changed files with 297 additions and 4 deletions

View File

@@ -100,6 +100,18 @@ MISSILE_PERIOD = 2.0 # s between launches; 300 rounds is not unlimited
# configuration here — override with $SYLPH_ASSET for another stage.
ASSET_NAME = os.environ.get("SYLPH_ASSET", "Acropolis")
# Turrets are keep-out zones everywhere else in this file, and that rule is what
# stopped the pilot being shot down. But the 2026-08-10 outcome run measured the
# cost of it: of the damage that sinks the ACROPOLIS, roughly half comes from
# e007 turrets sitting 1.5-3 km off it (the other half from e010 bombers), and a
# turret is 100 HP -- one missile, or ~7 nose-gun hits. Several were already at
# 45-95 HP from stray fire and were never finished off, because nothing ever
# targets them. So the rule that keeps us alive is also what loses the escort.
# Gated rather than simply changed, so the measured baseline stays reproducible:
# SYLPH_KILL_TURRETS=1 lets DEFEND -- and only DEFEND -- treat a turret that is
# near the asset as a target. ENGAGE still avoids them.
KILL_TURRETS = os.environ.get("SYLPH_KILL_TURRETS") == "1"
class Pilot:
KP, KD = 2.2, 0.45
@@ -230,7 +242,9 @@ class Pilot:
"""
out = []
for off, nm, p, v, r, hard in hos:
if hard:
# A turret near the asset IS a killable objective (100 HP) when
# SYLPH_KILL_TURRETS is set; a capital hull never is.
if hard and not (KILL_TURRETS and "Turret" in nm):
continue
rel = a_p - p
d = float(np.linalg.norm(rel))
@@ -520,9 +534,12 @@ class Pilot:
self.set_throttle(0)
fire = True
# a turret inside its keep-out radius outranks the target
# A turret inside its keep-out radius outranks the target -- except the
# one we are deliberately attacking, or the keep-out would steer us off
# the very thing we chose to kill and neither goal would be served.
tgt_off = tgt[0] if tgt else None
for off, nm, p, v, r, hard in hos:
if not hard:
if not hard or (KILL_TURRETS and off == tgt_off):
continue
d = float(np.linalg.norm(p - me_p))
if d < self.TURRET_KEEPOUT: