diff --git a/docs/re/BACKLOG.md b/docs/re/BACKLOG.md index 2d1f43e3..56f49059 100644 --- a/docs/re/BACKLOG.md +++ b/docs/re/BACKLOG.md @@ -6,6 +6,26 @@ unknown, what evidence exists, and what the first step would be. Move an item in --- +## 🔴 BLOCKER — the mission freeze is a software-rendering hang (2026-08-26) + +The freeze that blocks every dynamic measurement is in the **host rendering +path**, proven by control: with `--gpu=null` the guest runs at ~1 core through +the same content load that hangs every rendered run, with zero allocation +failures, while under `lavapipe` `Main XThread` sits at 0 ms CPU in +`futex_do_wait` and nine `llvmpipe` threads saturate for six minutes without +producing a frame. + +**Deciding whether `lavapipe` is deadlocked or merely pathologically slow needs +hardware Vulkan, which this container does not have.** That is a stated container +limit, so it is recorded here rather than worked around. + +🟡 **Workaround with a gap:** `--gpu=null` gives a live guest, and everything the +backlog needs is read from guest memory, not pixels. What is missing is +navigation — menu-walking is screenshot-driven today, and blind Ⓐ presses reached +no mission (`DEF_VTABLE` scan 0/0). **First step: drive navigation from guest +memory instead of the screen.** +See [`mission-freeze-heap-exhaustion.md`](mission-freeze-heap-exhaustion.md). + ## 🧰 The boot path — three failures that look like the emulator and are not (2026-08-26) * ✅ **`--audio` prevents boot outright.** `run-canary`'s own header says the flag diff --git a/docs/re/mission-freeze-heap-exhaustion.md b/docs/re/mission-freeze-heap-exhaustion.md index 0b161971..3f54d6fb 100644 --- a/docs/re/mission-freeze-heap-exhaustion.md +++ b/docs/re/mission-freeze-heap-exhaustion.md @@ -946,3 +946,56 @@ command processor has already handed off and is itself waiting. ⚠️ **Method rule earned the hard way: do not diagnose a performance or liveness question under a debugger.** Use it to read state at a known-good stopping point, then re-measure timing and CPU with it detached. + +--- + +# ✅✅ The freeze REQUIRES the rasterizer — `--gpu=null` does not freeze + +**2026-08-26.** The cleanest control available, and it settles which side the bug +is on. Xenia has a null graphics backend (`--gpu=null`, `xenia_main.cc:415`). +Same ISO, same route, same presses: + +| | lavapipe (default) | **`--gpu=null`** | +|---|---|---| +| `Main XThread` CPU | **0 ms / 3 s** | **3 860 ms / 4 s** | +| `Main XThread` state | `S` | **`R` (running)** | +| `Main XThread` wchan | **`futex_do_wait`** | **`0` (not blocked)** | +| guest memory churn | ~0 (18 bytes / 8.2 MB) | **22.6 %** of 6 MB in 4 s | +| allocations across the content load | stall | **114 → 120, zero failures** | +| process CPU | 265 % (all `llvmpipe`) | 330 % (mostly the guest) | + +**With no rasterizer the guest does not freeze.** It runs at close to a full core +and walks through the content load — the exact point that hangs every rendered +run — without a single allocation failure. + +So the fault is in the **host rendering path**, and every game-side hypothesis +this page worked through was looking in the wrong place. That is now explained +rather than merely observed. + +## 🔴 Blocked: telling "stuck" from "pathologically slow" needs hardware Vulkan + +The remaining question about the rasterizer itself — whether `lavapipe` is +deadlocked or merely taking hours over one pathological draw — cannot be answered +here. This container has **software rendering only**, and that is one of the +limits `AGENT.md` names explicitly. Six minutes of nine saturated `llvmpipe` +threads with no frame produced is suggestive, not conclusive, and no amount of +further waiting settles it. **Recorded as a blocker rather than improvised +around.** + +## 🟡 `--gpu=null` is a promising oracle for memory-based work — with one gap + +Everything this project actually needs from a running game is read out of guest +memory: entity positions, the flight model, the world unit. None of it needs +pixels. `--gpu=null` supplies a live guest for exactly that. + +The gap is **navigation**. Menu-walking is currently driven by screenshots, and +with no rasterizer there is nothing to look at. Pressing Ⓐ blind got the guest +through several screens — allocations advanced 114 → 120 — but never into a +mission: a `DEF_VTABLE` / `INST_VTABLE` scan afterwards returns **0 / 0**, so no +units were ever loaded. + +❔ Next, and it is a tractable engineering task rather than a mystery: **navigate +by guest memory instead of by screen.** The menu state must be readable — the +cleared-stage mask at `0x828F40C0` is already known and pokeable, so the menu +layer keeps its state somewhere findable. A memory-driven `nav_to_flight` would +make `--gpu=null` a complete oracle for every measurement on the backlog.