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
10 KiB
An in-mission freeze, and the first cut at what REMAINING OB counts
2026-08-23. One Stage 02 run, aimed at the ❔ that
structures/mission-objective-counter.md
leaves open — what the counter counts. It produced one clean refutation, one
new confirmation, and one experiment that proves nothing, for a reason worth
having a tool for.
✅ The address recurs a third time
HUD=4 RAM=4 at 0xbdb59668, read before anything else was attempted. That is
the third run putting the counter at that exact address (runs 1, 4, 5 of the
five measured), against runs 2 and 3 where it read a hard 0. The rule in the
structure file — try it, check it against the HUD, re-scan when it reads 0 —
survives another test.
🔴 The counter is not a live class head-count
With the counter at 4, the typed live entity list was:
| n | class |
|---|---|
| 8 | UN_e010_ADAN_Attacker_S |
| 7 | UN_f001_TCAF_DeltaSaber_T |
| 7 | UN_e007_ADAN_Turret |
| 1 | UN_f001_TCAF_DeltaSaber_T_Player |
No class has 4 members, and no sum of two of them does either. This is a
sharper version of the corpus's existing note (012 on the HUD against 118 live
ADAN): it is not merely "not the hostile count", it is not the count of any
class the enumeration can see. So the counter is either a subset marked some
other way — the OB badge — or a number the mission script keeps of its own.
🔴 The flag experiment proves nothing — the guest had frozen
The plan was the same shape that settled the address: find every 4-byte offset around an entity where exactly N entities agree, then require the survivors to agree exactly N′ times after the counter moves. The first half ran — 20 candidate offsets where exactly 4 of the 23 entities share a value — and then the counter sat at 4 for the whole 600 s window and the run reported "counter never moved".
That reading was wrong, and the correction is the useful part. The guest had stopped advancing about ten seconds into flight:
pilot.pylogged 5 910 samples over 734 s and every one after t=10.6 s carried the identical speed, yaw and pitch — 724 s of frozen state.- Two screenshots six seconds apart were byte-identical: max difference 0
over 863 325 pixels (
captures/stage02-inmission-freeze.png). - Everything that is supposed to notice, did not:
screen_id.pystill saidflight, the emulator was alive at 212 % CPU, and the process liveness check every script uses was satisfied.
So "the counter never moved" was a fact about a dead world, not about the game.
🔴 Withdrawn with it: the claim written into ob_session.sh that the counter
"climbs on its own as waves spawn in the first minutes" — in a run that is
advancing it did (004 → 008 → 012 twice), but this run cannot support the general
statement and the two facts had been about to be conflated.
The freeze is intermittent, not universal: the run an hour earlier stepped
the counter twice and had pilot.py in DEFEND at t=629 s with changing state.
frozen.py
Two screenshots, a gap, exact comparison — no tolerance, because a stopped
simulation is identical, not merely similar. Checked in both directions: 0 on
the frozen pair, max_pixel_delta=254 on two frames of a live one. ob_hunt.py
and ob_flag.py now consult it after a minute of no movement and say
GUEST FROZEN instead of quietly waiting out their timeout.
What is still open
- ❔ The flag itself. 20 candidate offsets exist but have never been put to
the second test. Repeat
ob_flag.pyon a run that is actually advancing; it now aborts early instead of wasting the window if it is not. - ❔ Whether the enumeration can even see the objectives.
entities2.typedfinds entities by their position changing, so a stationary objective is invisible to it. Stage 02's objective is "shoot down all invading enemy fighters", which move — but a null result would not rule out a flag on objects this method never enumerates, and that limit is now written into the tool. - ❔ What causes the freeze. Not investigated here at all; this run only establishes that it happens, that it can happen within seconds of the HUD appearing, and how to detect it in one call.
2026-08-23 (later) — the flag experiment finally ran, and still cannot verify
A run that stayed animating for its whole 25 minutes (checked repeatedly with
frozen.py) got the first real sample:
HUD=12 RAM=12 (0xbdb59668 again — 5 of 7 runs now)
[A] counter=12 entities=161
114 UN_e007_ADAN_Turret
32 UN_e010_ADAN_Attacker_S
14 UN_f001_TCAF_DeltaSaber_T
1 UN_f001_TCAF_DeltaSaber_T_Player
[A] classes whose head-count equals the counter: NONE
[A] offsets where exactly 12 entities agree: 11
with a much bigger entity list than the frozen run's 23, so the earlier "🔴 not a class head-count" result is now confirmed on a 161-entity sample too.
The 11 candidates, with who they group — the part worth looking at:
| offset | value | members |
|---|---|---|
+0x00d0 |
3f57f496 |
12 of the 14 friendly Delta Sabers |
+0x017c–+0x0198 (7 words) |
floats | 12 of the 32 e010 attackers |
+0x00b0, +0x015c |
43f9ffff |
10 turrets + 2 attackers |
+0x0238 |
00000004 |
12 turrets |
The seven consecutive floats at +0x017c…+0x0198 shared by exactly twelve
attackers look far more like one shared parameter block — a squad flying the
same AI or weapon configuration — than like a per-entity objective flag, and
+0x0238 = 4 on twelve turrets is hard to reconcile with an objective that
reads "shoot down all invading enemy fighters". None of this is verified, and
the reason is the next paragraph.
🔴 REMAINING OB held at 012 for fifteen minutes of live flight
Not a frozen world this time — the game was animating throughout, and the run ended only because the experiment's window did. So the counter genuinely did not move, and there was no second sample to test the candidates against.
And it held while the hostile population fell by a third. pilot.py's own
rescans went 132 ADAN → 93 ADAN over the window: roughly 39 hostiles died
(to wingmen and to the ACROPOLIS's guns) and REMAINING OB did not change by
one. That is a real negative about what the counter counts — it is not
"hostiles left", on a much stronger sample than the earlier head-count argument.
🔴 A tool defect that bounds every kill-based experiment
pilot.py never fires: fire=1 appears in 0 of its 13 521 logged
samples in this run. It flies, chases and evades, but the trigger is never
pulled. Every "kill something and watch X" experiment in this corpus is
therefore relying on the wingmen, and the pilot's own contribution to a kill
count is zero. Not fixed here — recorded because it silently weakens conclusions
drawn from runs that assumed the pilot was shooting.
Freeze frequency, updated
This run did not freeze in ~25 minutes. Of the seven Stage 02 runs that have reached flight, three froze — so it is common but not the majority, and a run that survives the first minute or two seems to keep going.
🔴 2026-08-23 (final) — the per-entity flag hypothesis is REFUTED, on a transition it was not selected by
With the pilot actually shooting (pilot-never-fires.md), the experiment this
file was written for finally completed both halves:
HUD=12 RAM=12
[A] counter=12 entities=120 96 turrets, 16 attackers, 7 wingmen, 1 player
[A] classes whose head-count equals the counter: NONE
[A] offsets where exactly 12 entities agree: 2
pos+0x0238 = 00000006 {12 × e007_ADAN_Turret}
pos+0x0250 = 239d6732 {12 × e010_ADAN_Attacker_S}
counter 12 -> 11
[B] counter=11 entities=194
[B] of 2 candidates, 0 still hold exactly 11
(captures/ob-flag-refuted-stage02.json)
Both candidates die on the verification. So: within ±0x400 of an entity's
position triple there is no 4-byte word whose shared-value population tracks
REMAINING OB. The simplest reading of "objectives are marked in the entity
object" is dead.
What that does and does not rule out — the limits are the result too
- 🔴 Ruled out: a per-entity word, in that window, holding a common value on exactly the objective entities.
- ❔ Not ruled out — a flag packed into a word that also varies. The test asks which entities share an exact 32-bit value. A single bit ORed into a word that also carries health, a timer or a state machine would never produce a shared value, and this method cannot see it. A bit-level version of the same differential is the obvious follow-on.
- ❔ Not ruled out — anything outside the window, or on entities the
enumeration cannot see:
entities2.typedtypes entities by their position changing, so a stationary objective is invisible to it. - ⚠️ The populations differ a lot between samples — 120 entities at A, 194 at B — so a flag on entities that spawned between the two would not have been tested either.
✅ And the counter DECREMENTS when the player kills
REMAINING OB went 12 → 11 during this run — the first decrement seen in
this whole investigation — while pilot.py logged 411 fire=1 samples and
the HUD's own tally reached YOU KILLED WARPLANES 0003
(captures/stage02-you-killed-warplanes-0003.png).
That is worth stating carefully. It does not show that the counter counts kills — the earlier fifteen-minute run had the hostile population fall by a third with no movement at all. What it shows is that some kills close something the counter tracks, which is exactly the behaviour an objective counter should have, and it is the first time the player's own guns have been part of the experiment rather than a bystander.
One more robustness fix, from a void run
ob_flag.py now retries an empty sample. entities2.moving() types entities
by position changing, so a sample that lands on a load or loses the race with
another scanner returns nothing — and a zero-entity sample silently yields zero
candidates and a run that proves nothing. Seen exactly that way once, with the
following sample finding 81 entities moments later.