diff --git a/docs/re/captures/ob-bitflag-refuted-stage02.json b/docs/re/captures/ob-bitflag-refuted-stage02.json new file mode 100644 index 00000000..7c471b1c --- /dev/null +++ b/docs/re/captures/ob-bitflag-refuted-stage02.json @@ -0,0 +1,186 @@ +{ + "pass1": { + "nA": 4, + "nB": 8, + "hud_a": 4, + "hud_b": 8, + "entities_a": 24, + "entities_b": 74, + "candidates_a": { + "set": 255, + "clear": 455 + }, + "survivors": [ + { + "polarity": "set", + "offset": 592, + "bit": 1 + }, + { + "polarity": "set", + "offset": 592, + "bit": 4 + }, + { + "polarity": "set", + "offset": 592, + "bit": 5 + }, + { + "polarity": "set", + "offset": 2080, + "bit": 5 + }, + { + "polarity": "set", + "offset": 2100, + "bit": 5 + }, + { + "polarity": "set", + "offset": 348, + "bit": 6 + }, + { + "polarity": "set", + "offset": 592, + "bit": 8 + }, + { + "polarity": "set", + "offset": 592, + "bit": 9 + }, + { + "polarity": "set", + "offset": 592, + "bit": 10 + }, + { + "polarity": "set", + "offset": 624, + "bit": 10 + }, + { + "polarity": "set", + "offset": 1936, + "bit": 12 + }, + { + "polarity": "set", + "offset": 592, + "bit": 13 + }, + { + "polarity": "set", + "offset": 592, + "bit": 14 + }, + { + "polarity": "set", + "offset": 2084, + "bit": 14 + }, + { + "polarity": "set", + "offset": 388, + "bit": 16 + }, + { + "polarity": "set", + "offset": 592, + "bit": 16 + }, + { + "polarity": "set", + "offset": 640, + "bit": 16 + }, + { + "polarity": "set", + "offset": 592, + "bit": 18 + }, + { + "polarity": "set", + "offset": 984, + "bit": 18 + }, + { + "polarity": "set", + "offset": 592, + "bit": 19 + }, + { + "polarity": "set", + "offset": 592, + "bit": 20 + }, + { + "polarity": "set", + "offset": 628, + "bit": 21 + }, + { + "polarity": "set", + "offset": 592, + "bit": 23 + }, + { + "polarity": "set", + "offset": 592, + "bit": 24 + }, + { + "polarity": "set", + "offset": 592, + "bit": 25 + }, + { + "polarity": "set", + "offset": 592, + "bit": 29 + }, + { + "polarity": "set", + "offset": 636, + "bit": 30 + }, + { + "polarity": "set", + "offset": 644, + "bit": 31 + }, + { + "polarity": "clear", + "offset": 1204, + "bit": 25 + } + ] + }, + "pass2": { + "nA": 8, + "nB": 12, + "hud_a": 8, + "hud_b": 8, + "entities_a": 100, + "entities_b": 217, + "candidates_a": { + "set": 133, + "clear": 64 + }, + "survivors": [ + { + "polarity": "set", + "offset": 1080, + "bit": 17 + }, + { + "polarity": "set", + "offset": 2096, + "bit": 25 + } + ] + }, + "intersection": [] +} \ No newline at end of file diff --git a/docs/re/mission-freeze-and-ob-flag.md b/docs/re/mission-freeze-and-ob-flag.md index 942d5fb4..7a62b981 100644 --- a/docs/re/mission-freeze-and-ob-flag.md +++ b/docs/re/mission-freeze-and-ob-flag.md @@ -269,3 +269,43 @@ The freeze was caught in about a minute by `frozen()` instead of consuming the whole 700 s window — which is the difference the guard makes, and the only thing this attempt bought. Still **no verification**: four runs, four windows, zero second transitions. + +--- + +## 🔴 2026-08-24 — the BIT-level flag is refuted too, on two independent transitions + +The short-run strategy worked: both counter steps happen in the first minutes of +flight, so `ob_bitflag.py` got two complete passes out of one run before anything +could freeze or be killed. + +| pass | scan | filter | candidates at A | survivors | +|---|---|---|---|---| +| 1 | counter **4**, 24 entities | **4 → 8** (HUD confirmed) | 255 set + 455 clear | **29** | +| 2 | counter **8**, 100 entities | **8 → 12** | 133 set + 64 clear | **2** | + +**The intersection of the two survivor sets is EMPTY.** +([`captures/ob-bitflag-refuted-stage02.json`](captures/ob-bitflag-refuted-stage02.json)) + +Not one `(offset, bit)` survives two independently selected transitions. So there +is **no per-entity bit** — in either polarity, anywhere in `-0x400 … +0xC00` +around the position triple — whose population tracks `REMAINING OB`. Together +with the word-level refutation this closes the "objectives are marked in the +entity object" family as far as this method can reach. + +### Why pass 1 looked richer than it was + +**16 of its 29 survivors are the same word**, `pos+0x0250`, with sixteen +different bits. That is the signature of a **shared value**, not a flag: if four +entities hold the identical word at `+0x250`, every set bit of it "survives" +together, and the bit framing is spurious. It is the same offset the word-level +sweep found shared by 12 attackers (`pos+0x0250 = 239d6732`), so `+0x250` is a +per-class or per-group word — a parameter or a pointer — and its bit counts track +the class population rather than the objective count. + +⚠️ **One reading caveat, kept:** pass 2's B-sample HUD read `8` while RAM read +`12`; the address had been HUD-verified at sample A and the RAM value is what the +filter used, but the confirming screenshot at that instant did not agree. + +**What is still not ruled out** is unchanged from the word-level pass: anything +outside the window, and anything on entities `entities2.typed` cannot see (it +types by position *changing*, so stationary objectives are invisible).