From 4a78b1bc86e7e38ea4a3db5e7b4593fe9336f672 Mon Sep 17 00:00:00 2001 From: Sylpheed RE agent Date: Thu, 27 Aug 2026 02:42:46 +0000 Subject: [PATCH] re: turret control CONFIRMED, arrival timing n=3, decrement still unproven Third Stage 02 run, pilot with SYLPH_PREFER=e010 (312 fire=1 samples), per-class live counts logged every 11s beside the HUD (new tools/re-capture/class_count.py). CONTROL CONFIRMED: the live turret population fell 108 -> 101 -- seven e007 deaths -- and REMAINING OB never decremented, only rose. Previously this was inferred from a run whose kill log happened to be turrets; it is now measured with the classes counted directly. ARRIVAL TIMING n=3: 004 -> 008 in (108.7s, 125.5s] and 008 -> 012 in (204.2s, 221.7s], both brackets containing the predicted 120 and 210. The live e010 count sat at exactly 16 in 20 of 26 samples -- precisely phase 1's e010 roster (ADT102/ADT107/ADT113/ADS151, each n=4) -- an independent runtime corroboration of the static roster. DECREMENT STILL UNPROVEN: the e010 floor never fell, so no marked attacker died and the counter had no chance to move. Three runs have failed to kill one. The blocker is combat effectiveness, not instrumentation. Artifact recorded: six of 26 class samples read 17-28. Spikes are always upward and transient -- the tool dedups on a position triple read just after the pattern scan, so an entity written between the two reads is counted twice. --- docs/re/ob-counts-marked-attackers.md | 59 +++++++++++++++++++++++++++ tools/re-capture/class_count.py | 32 +++++++++++++++ 2 files changed, 91 insertions(+) create mode 100644 tools/re-capture/class_count.py diff --git a/docs/re/ob-counts-marked-attackers.md b/docs/re/ob-counts-marked-attackers.md index de0b6199..886afb2b 100644 --- a/docs/re/ob-counts-marked-attackers.md +++ b/docs/re/ob-counts-marked-attackers.md @@ -341,3 +341,62 @@ distinct positions carry the player definition. Not investigated. A run in which a **marked** attacker demonstrably dies — which means logging the per-class roster before and after each kill, not just the ADAN total. The pilot already prefers `e010`; what is missing is the bookkeeping to prove it hit one. + +--- + +# 2026-08-27 (third run) — ✅ the turret CONTROL passes, arrival timing at n=3 + +`pilot.py` with `SYLPH_PREFER=e010` for 320 s (312 `fire=1` samples), with a +per-class live count logged every 11 s beside the HUD +([`class_count.py`](../../tools/re-capture/class_count.py)) and the mission clock +sampled throughout ([capture](captures/ob-turret-control-timeline.png)). + +## ✅ Killing turrets does NOT move the counter — control confirmed + +The live turret population fell monotonically while the counter only ever rose: + +``` +sample 0: e007=108 e010=16 OB 004 +sample 9: e007=105 e010=16 OB 008 +sample 21: e007=102 e010=16 OB 012 +sample 25: e007=101 e010=16 OB 012 +``` + +**Seven `e007` turrets died and `REMAINING OB` never decremented once.** This was +previously only *weakly* supported — inferred from a run whose kill log happened +to be turrets. It is now a measured control with the classes counted directly. + +## ✅ Arrival timing reproduces a third time + +| mission `TIME` | `OB` | | +|---|---|---| +| 01:48.73 → **02:05.54** | `004` → **`008`** | step in (108.7 s, 125.5 s] ∋ **120** | +| 03:24.16 → **03:41.70** | `008` → **`012`** | step in (204.2 s, 221.7 s] ∋ **210** | + +**n = 3.** Both predicted times are inside their brackets on every run so far. + +## ✅ The live `e010` baseline is exactly phase 1's roster + +The count sat at **16** in 20 of 26 samples — precisely the phase-1 `e010` +roster (`ADT102`, `ADT107`, `ADT113`, `ADS151`, each n=4). That is an independent +runtime corroboration of the static roster, and it locates the counter's 12 as +the three `A`-route squadrons within that 16. + +⚠️ **Measurement artifact, stated:** six samples read 17–28. The spikes are always +*upward* and never persist, and the counter dedups by a position triple read a +moment after the pattern scan, so an entity written between the two reads can be +counted twice. The stable floor of 16 is the signal; the spikes are noise in my +tool, not arrivals. + +## 🟡 The decrement is STILL unproven + +No marked attacker died in this run either: the `e010` floor never dropped below +16 despite 312 `fire=1` samples. So the counter had no opportunity to decrement, +and its stillness says nothing about the claim. + +Three runs have now failed to kill one `e010`. The blocker is combat +effectiveness, not instrumentation — `pilot-never-fires.md` and the +`SYLPH_PREFER` notes already record that this pilot lands few attacker kills +because turrets are nearer and far more numerous. ❔ Options not yet tried: +pick a lone attacker while the squadron is still inbound, or wait for the +wingmen/ACROPOLIS guns to kill one (which counts just as well). diff --git a/tools/re-capture/class_count.py b/tools/re-capture/class_count.py new file mode 100644 index 00000000..4c84c87e --- /dev/null +++ b/tools/re-capture/class_count.py @@ -0,0 +1,32 @@ +"""Fast per-class live count: search ONE definition pointer, dedup by position.""" +import sys, os, struct, time +sys.path.insert(0, '/tmp/rc') +import gmem, gworld, entities2 as E + +w = gworld.World() +defs = E.definitions(w) +want = {nm: pat for pat, nm in defs.items() + if nm in ('UN_e010_ADAN_Attacker_S', 'UN_e007_ADAN_Turret')} +lo, hi = gmem.va_to_off(E.ENT_VA_LO), gmem.va_to_off(E.ENT_VA_HI) + +def count(pat): + seen = set() + for a, b in gmem.extents(w.fd, w.size): + a, b = max(a, lo), min(b, hi) + if b <= a: continue + blob = os.pread(w.fd, b - a, a); i = 0 + while True: + j = blob.find(pat, i) + if j < 0: break + off = a + j + if off % 4 == 0: + p = off - 0x130 + d = os.pread(w.fd, 12, p) + if len(d) == 12: seen.add(struct.unpack('>fff', d)) + i = j + 4 + return len(seen) + +for n in range(int(sys.argv[1])): + row = ' '.join('%s=%d' % (k.split('_')[1], count(v)) for k, v in sorted(want.items())) + print('%2d %s' % (n, row), flush=True) + time.sleep(float(sys.argv[2]))