tools: add SYLPH_WEAKEST target scoring; record that assert_stage != in flight
pilot.py gains SYLPH_WEAKEST=1, which scales a target's score by its remaining
hull (pos+0x154) so the pilot finishes what is already hurt instead of
re-engaging whatever is nearest. Motivated by b69cc23: over ~8 minutes the pilot
damaged 14 of 16 e010 attackers (hulls 360..500) and killed none, because 500 HP
spread across a squadron kills nobody.
STATUS: the flag is implemented and its targeting works -- 3105 of 3105 target
samples selected e010 -- but it is UNVERIFIED in combat, because the run it was
written for was lost.
That loss is the second half of this commit. The run printed "READY ROOM / >>>
HUD / Stage 02 OK" and I began the experiment; there was no FLIGHT: line, because
the flight check failed three times and fell through silently while the next line
read like success. The game was frozen on a near-black screen (screen_id `other`,
mean 10.8/2.8/2.1, frozen.py max_pixel_delta=0) and the pilot's every sample from
t=0.0 to t=406.1 is byte-identical with speed 0.
assert_stage.py could not have caught it: it reads the DEFINITION table, which is
populated when the STAGE loads, independently of whether the mission is running.
Recorded in nav-guards.md with the rule -- enforce the flight gate with a non-zero
exit, and run the three-crop TIME liveness check before any experiment.
This commit is contained in:
@@ -104,3 +104,36 @@ this confirms it visually and pins the cursor's start position.)
|
|||||||
unit-tested, but "the route is now reproducible" rests on a single success.
|
unit-tested, but "the route is now reproducible" rests on a single success.
|
||||||
* Why the game window leaves the window tree during a load at all was not
|
* Why the game window leaves the window tree during a load at all was not
|
||||||
investigated — only guarded against.
|
investigated — only guarded against.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## ⚠️ `assert_stage` passing does NOT mean the run is in flight
|
||||||
|
|
||||||
|
Measured the hard way 2026-08-27. A run printed:
|
||||||
|
|
||||||
|
```
|
||||||
|
MENU confirmed
|
||||||
|
loaded
|
||||||
|
READYROOM
|
||||||
|
>>> HUD
|
||||||
|
Stage 02 OK
|
||||||
|
```
|
||||||
|
|
||||||
|
…and I started an experiment against it. There is no `FLIGHT:` line in that
|
||||||
|
output. The flight check ran, failed to match three times, and fell through
|
||||||
|
**silently**; the very next line said `Stage 02 OK`, which read like success.
|
||||||
|
|
||||||
|
It was not. The game was frozen on a near-black screen — `screen_id` `other`,
|
||||||
|
mean `(10.8, 2.8, 2.1)`, `frozen.py max_pixel_delta=0` — and the whole 460 s
|
||||||
|
experiment ran against a static world. The pilot's own log is the clearest
|
||||||
|
evidence: **every sample from t=0.0 to t=406.1 is byte-identical**, speed `0`,
|
||||||
|
the ship never even started moving.
|
||||||
|
|
||||||
|
**Why the stage assertion did not catch it:** `assert_stage.py` reads the
|
||||||
|
DEFINITION table, and definitions are loaded when the *stage* loads — before,
|
||||||
|
and independently of, the mission actually starting. It answers "is the right
|
||||||
|
stage loaded", never "is the mission running".
|
||||||
|
|
||||||
|
**Rule:** the flight gate must be *enforced*, not attempted — exit non-zero when
|
||||||
|
`screen_id` never reads `flight`, and take the three-crop TIME liveness check
|
||||||
|
before any experiment. Both were skipped here, and the run was lost.
|
||||||
|
|||||||
@@ -115,6 +115,12 @@ KILL_TURRETS = os.environ.get("SYLPH_KILL_TURRETS") == "1"
|
|||||||
|
|
||||||
HUNT = os.environ.get("SYLPH_HUNT") == "1"
|
HUNT = os.environ.get("SYLPH_HUNT") == "1"
|
||||||
PREFER = os.environ.get("SYLPH_PREFER", "")
|
PREFER = os.environ.get("SYLPH_PREFER", "")
|
||||||
|
# SYLPH_WEAKEST=1 scores a target by REMAINING HULL as well as range, so the
|
||||||
|
# pilot finishes what is already hurt instead of re-engaging whatever is
|
||||||
|
# nearest. Measured 2026-08-27 (ob-counts-marked-attackers.md): over ~8 minutes
|
||||||
|
# the pilot damaged 14 of 16 e010 attackers -- hulls 360..500 -- and killed
|
||||||
|
# NONE, because each carries 500 HP and the fire was spread across the squadron.
|
||||||
|
WEAKEST = os.environ.get("SYLPH_WEAKEST", "") not in ("", "0")
|
||||||
|
|
||||||
|
|
||||||
class Pilot:
|
class Pilot:
|
||||||
@@ -399,6 +405,10 @@ class Pilot:
|
|||||||
# pointed at the thing the mission actually asks for.
|
# pointed at the thing the mission actually asks for.
|
||||||
if PREFER:
|
if PREFER:
|
||||||
score *= 0.05 if PREFER in nm else 4.0
|
score *= 0.05 if PREFER in nm else 4.0
|
||||||
|
if WEAKEST:
|
||||||
|
h = self.f32(off + HULL_OFF)
|
||||||
|
if h and h > 0.0:
|
||||||
|
score *= max(h, 1.0) / 500.0
|
||||||
if score < bestscore:
|
if score < bestscore:
|
||||||
best, bestscore = (off, nm, lead, lead - me_p, d, r), score
|
best, bestscore = (off, nm, lead, lead - me_p, d, r), score
|
||||||
return best
|
return best
|
||||||
|
|||||||
Reference in New Issue
Block a user