docs+tools: the per-entity OB flag is refuted, and the counter decrements when the player kills

With the pilot finally shooting, the experiment completed both halves. Sample A
at counter 12 over 120 entities gave 2 offsets where exactly 12 entities share a
value; the counter then went 12 -> 11 and NEITHER survived. So within +-0x400 of
an entity's position triple there is no 4-byte word whose shared-value population
tracks REMAINING OB.

The limits are recorded as part of the result, because they bound it: the test
asks which entities share an EXACT 32-bit value, so a single bit ORed into a word
that also carries health or a timer would never show up - a bit-level version of
the same differential is the follow-on. Anything outside the window, or on
entities that entities2 cannot see (it types by position CHANGING, so stationary
objectives are invisible), is untested too, and the populations differed a lot
between samples - 120 against 194.

Separately: REMAINING OB went 12 -> 11, the first decrement of this whole
investigation, while pilot.py logged 411 fire=1 samples and the HUD reached YOU
KILLED WARPLANES 0003. Stated carefully - it does NOT show the counter counts
kills, since an earlier run had the hostile population fall by a third with no
movement; it shows some kills close something the counter tracks.

Two robustness fixes: ob_flag retries an empty entity sample (one void run was
caused by exactly that), and Pad releases everything on interpreter exit - a
file-backed pad PERSISTS after its writer dies, so a tool killed mid-press would
leave a button held and the game would walk through menus on its own.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01PMRJjbxLqZtsb5Vb7KunPE
This commit is contained in:
Sylpheed RE agent
2026-08-23 23:21:08 +00:00
parent e65b730af0
commit 26421d5266
5 changed files with 94 additions and 1 deletions

View File

@@ -11,6 +11,7 @@ then per frame a timestamp, the input vector, and every instance's raw window.
Usage: flight_probe.py <out.bin> [seconds]
"""
import atexit
import os
import struct
import sys
@@ -59,6 +60,11 @@ class Pad:
"LT": 0.0, "RT": 0.0}
self.buttons = set()
self._write()
# A file-backed pad has a failure mode the FIFO did not: the state
# PERSISTS after the writer dies. A tool killed mid-press leaves the
# button held forever, and the game then walks through menus on its own
# with nobody touching it. Release everything on exit.
atexit.register(self.reset)
def _write(self):
parts = []

View File

@@ -110,7 +110,20 @@ def main():
"ob_hunt.py before trusting anything below", flush=True)
return 2
nA, entsA, gA = sample(w, defs, out, "A")
# RETRY an empty sample. entities2.moving() types entities by their position
# CHANGING between two reads, so a sample that lands on a load, a stall, or
# simply loses the race with another scanner comes back with nothing — and a
# zero-entity sample silently produces zero candidates and a void run. Seen
# once, with sample B finding 81 entities moments later.
for _ in range(6):
nA, entsA, gA = sample(w, defs, out, "A")
if len(entsA) >= 10:
break
print("[A] too few entities — retrying", flush=True)
time.sleep(5)
if len(entsA) < 10:
print("[A] never got a usable entity sample", flush=True)
return 4
hist = Counter(nm for _, nm in entsA)
print(f"[A] class histogram vs counter {nA}:", flush=True)
for nm, k in hist.most_common(12):