From ef8d2ab0d854bad0a314b87b447d0e00073bcd0f Mon Sep 17 00:00:00 2001 From: Sylpheed RE agent Date: Wed, 26 Aug 2026 11:26:44 +0000 Subject: [PATCH] re: the freeze is independent of the mask poke -- control run settles it MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit challenge-mission-gate.md §5.6 attributes the 128 MB heap failure to a careless cleared-stage mask poke, concludes that poking only real story ids does not blow the heap, and ends by asking for the control: repeat without the poke. Ran it. nav_to_flight.sh gains SYLPH_NO_POKE=1, which skips the write; only Stage 1 is selectable without it, so the control changes stage too, which makes the agreement stronger rather than weaker. poked 0x0001FFFE Stage 02 frozen, 128 MB request refused control untouched Stage 01 frozen, 128 MB request refused Both logs carry not merely the same error but the same numbers: requested 134217728 bytes, parent free 28969/131072 pages 28969 in both, across two stages and two boots. So the poke does not cause it and neither does the stage; the guest reproducibly arrives at a 128 MB request with ~113 MB free. An identical free-page count across independent runs also says the allocation pattern is deterministic -- not a race, not host pressure. The control was verified three ways, because the first attempt was confounded: two emulators were alive at once (the previous one survived a pkill). The mask was read back as 0x0 from the live mapping, the log was confirmed to be this run's, and the liveness test was repeated after killing the stale process so exactly one emulator was running -- three frames at rmse 0.00, and an 8 MB slab of guest RAM with 0 bytes changed over 3 s. --- docs/re/BACKLOG.md | 1 + docs/re/mission-freeze-heap-exhaustion.md | 37 ++++++++++++++++++----- tools/re-capture/nav_to_flight.sh | 11 +++++-- 3 files changed, 39 insertions(+), 10 deletions(-) diff --git a/docs/re/BACKLOG.md b/docs/re/BACKLOG.md index ce6e45d5..2d1f43e3 100644 --- a/docs/re/BACKLOG.md +++ b/docs/re/BACKLOG.md @@ -720,6 +720,7 @@ search cannot find a *schedule*. 6500 candidates → 32 witnesses at 21/s, and the flags have **zero contradictions** with the loss data (the one loss is unflagged; every flagged sample has no losses). That is the check the three previous versions failed. +* ✅ **ROOT-CAUSED 2026-08-26 — see [`mission-freeze-heap-exhaustion.md`](mission-freeze-heap-exhaustion.md).** The freeze is a **guest 128 MB physical allocation being refused** (`MmAllocatePhysicalMemoryEx`, `parent free 28969/131072 pages` ≈ 113 MB) after which the guest throws a C++ exception and stops; the emulator keeps spinning at 399 % CPU, which is why it reads as a hang. **Independent of the cleared-stage mask poke and of the stage** — a `SYLPH_NO_POKE=1` control on Stage 01 froze with the *identical* free-page count as the poked Stage 02 run. This also refutes `challenge-mission-gate.md` §5.6's "poking only real story ids does not blow the heap". * 🔴 **The freeze is now THE blocker.** Onset across runs: **27, 45, 83, 183, 255 s** (median ~83 s) — usable window is 1–4 min and unpredictable. This run froze at 45 s with 1 loss, useless for arrivals despite a working instrument. diff --git a/docs/re/mission-freeze-heap-exhaustion.md b/docs/re/mission-freeze-heap-exhaustion.md index 0c87bfce..78b726e5 100644 --- a/docs/re/mission-freeze-heap-exhaustion.md +++ b/docs/re/mission-freeze-heap-exhaustion.md @@ -53,14 +53,35 @@ cleared-stage mask blows the heap on a 128 MB request, and concludes: This run poked **`0x0001FFFE`** — the value called safe — and hit the **same 128 MB failure**, with `parent free 28969/131072` against that page's `30633/131072`. -🟡 The two are not identical and the refutation is bounded: there, the failure was -on entering `MISSION SELECT`; here `MISSION SELECT` and the stage list worked, and -the failure came later, during the **take-off load**. So the correct reading is -not "the safe value is unsafe" but that **the poke value is not what decides it** — -both values fail the same 128 MB request, at whichever load happens to arrive when -free pages have drained below it. That page's own open question — *"repeat without -the poke to see whether it fails the same way regardless"* — is now the load-bearing -experiment, and it is still unrun. +### ✅ And the control run settles it: the poke is irrelevant + +That page ends with the right experiment — *"repeat without the poke to see whether +it fails the same way regardless"* — so I ran it. `nav_to_flight.sh` gained +`SYLPH_NO_POKE=1`, which skips the write; only Stage 1 is selectable without it, +so the control also changes stage, which makes the agreement stronger rather than +weaker. + +| run | mask | stage | outcome | +|---|---|---|---| +| poked | `0x0001FFFE` | Stage 02 | frozen; 128 MB request refused | +| **control** | **untouched, reads `0x0`** | **Stage 01** | **frozen; 128 MB request refused** | + +Both logs carry the identical line — not merely the same error, the **same +numbers**: + + requested 134217728 bytes, parent free 28969/131072 pages + +`28969` in both, across two stages and two boots. The control was verified three +ways: the mask read back `0x0` from the live mapping, the log was this run's, and +the liveness test was repeated with the stale process killed so exactly one +emulator was running (three frames, rmse 0.00; an 8 MB slab, 0 bytes changed in +3 s). + +🔴 **So the poke does not cause it, and neither does the stage.** The guest +reproducibly arrives at a 128 MB physical request with ~113 MB free and throws. +The identical free-page count across independent runs says the allocation pattern +up to that point is deterministic — this is not a race and not memory pressure +from the host. ## ⚠️ A frozen game passes the screen classifier diff --git a/tools/re-capture/nav_to_flight.sh b/tools/re-capture/nav_to_flight.sh index e9216c2f..feac5d16 100755 --- a/tools/re-capture/nav_to_flight.sh +++ b/tools/re-capture/nav_to_flight.sh @@ -60,8 +60,15 @@ for i in $(seq 1 "$MENU_TIMEOUT"); do done [ "$MENU" = 1 ] || { say "TIMEOUT: no main menu"; shot 00-timeout; exit 1; } -say "poking the cleared-stage mask so every story stage is selectable" -poke w32 0x828F40C0 0x0001FFFE +# SYLPH_NO_POKE=1 skips the mask poke, so a run can test whether the 128 MB +# heap failure in mission-freeze-heap-exhaustion.md depends on it. Only Stage 1 +# is selectable without it. +if [ "${SYLPH_NO_POKE:-0}" = "1" ]; then + say "SYLPH_NO_POKE=1 — NOT poking the cleared-stage mask (Stage 1 only)" +else + say "poking the cleared-stage mask so every story stage is selectable" + poke w32 0x828F40C0 0x0001FFFE +fi # main menu -> EXTRAS -> MISSION SELECT for _ in 1 2 3 4; do pad dpad down 0.06; sleep 0.35; done