docs: the title does act on (A) - the loader thread it spawns is what stalls
"The title screen ignores (A)" is withdrawn. First-divergence across three boots of the same binary says otherwise. A slot-(1F) guest thread is spawned BY the press: exactly once per run, immediately after the keydown, same stack base 70880000-70900000 in both runs that got one, and never at all in the run that never accepted a press - which rules out a periodic worker starting around the same time. prm6, reached the menu: (A) at line 6498, (1F) at 6500, 6 ResolvePath after opt2, stuck on the title: (A) at line 1287, (1F) at 1288, 0 ResolvePath after opt, stalled before title: no (A) ever, no (1F) thread at all In the successful run the loader immediately reads six paths out of the on-disc cache and the menu appears. In the failed run the same thread starts and performs no file I/O ever again. Total ResolvePath for the three boots is 90/84/78 - the successful run's extra six are exactly the ones after the press, so the boots are otherwise identical in I/O. Refuted as the cause: the cache-flush std::out_of_range. All four of today's runs have zero GUEST-THROW, zero CRASH DUMP and zero Access Violation, and the guest stays alive throughout with its keystroke-poll counter climbing past 15000. Next probe is neither input nor the crash: what the (1F) thread waits on.
This commit is contained in:
@@ -143,10 +143,17 @@ See [`structures/ui-composable-bundles.md`](structures/ui-composable-bundles.md)
|
|||||||
measured screen with a tied group — not more static guessing at fields that
|
measured screen with a tied group — not more static guessing at fields that
|
||||||
have all now been checked. 🔴 **Attempted 2026-08-19 and blocked:** advancing
|
have all now been checked. 🔴 **Attempted 2026-08-19 and blocked:** advancing
|
||||||
past the title is intermittent — **1 success in 3 attempts**, same binary,
|
past the title is intermittent — **1 success in 3 attempts**, same binary,
|
||||||
same profile, same procedure. Input is excluded for the third time (every
|
same profile, same procedure. ✅ **And now diagnosed one layer deeper:** the
|
||||||
press logged as delivered, `vk=5800`/`vk=5814`); one failure stalled *before
|
title *does* act on Ⓐ — the press spawns a slot-`(1F)` loader thread (exactly
|
||||||
the title was built at all*, with the guest alive and polling and only the
|
once per run, at the keydown, never in a run that got no press). In the
|
||||||
splash object resident. Next probe must be guest-side, not input-side.
|
successful boot that thread immediately reads six paths from the on-disc cache
|
||||||
|
and the menu appears; in a failed boot it starts and issues **no file I/O
|
||||||
|
ever**. So "the title ignores Ⓐ" is **withdrawn** — the loader stalls.
|
||||||
|
🔴 Refuted as the cause: the cache-flush crash. All four of today's runs have
|
||||||
|
**zero** `GUEST-THROW`, `CRASH DUMP` and `Access Violation`; the guest stays
|
||||||
|
alive and polling. **Next probe:** what the `(1F)` thread waits on — an event
|
||||||
|
or file-system trace on that thread, not input, not the crash.
|
||||||
|
See [`canary-scripted-input-traps.md`](canary-scripted-input-traps.md).
|
||||||
* ❔ **Blend mode.** Everything is straight alpha-over. The near-white flash
|
* ❔ **Blend mode.** Everything is straight alpha-over. The near-white flash
|
||||||
quads (`0xf0ffffff`) and coloured ones (`0x60ff0000`) may be additive. The
|
quads (`0xf0ffffff`) and coloured ones (`0x60ff0000`) may be additive. The
|
||||||
title capture cannot separate the two — its resting elements are all
|
title capture cannot separate the two — its resting elements are all
|
||||||
|
|||||||
@@ -381,3 +381,66 @@ Also confirmed on the way: the screen after NEW GAME is **DIFFICULTY** — its
|
|||||||
whole-image signature `(9.7, 19.5, 53.9)` matches the earlier capture of that
|
whole-image signature `(9.7, 19.5, 53.9)` matches the earlier capture of that
|
||||||
screen exactly — so the menu path is understood even though the run dies after
|
screen exactly — so the menu path is understood even though the run dies after
|
||||||
it.
|
it.
|
||||||
|
|
||||||
|
|
||||||
|
## ✅ The title *does* act on Ⓐ — what stalls is the loader thread (2026-08-19)
|
||||||
|
|
||||||
|
**Status:** ✅ `CONFIRMED` by first-divergence across three boots of the same
|
||||||
|
binary. 🔴 The stall itself is unexplained. ⚠️ **"the title screen ignores Ⓐ" is
|
||||||
|
withdrawn** — it was the wrong description of the symptom, and it sent two
|
||||||
|
iterations looking at the input path, which is fine.
|
||||||
|
|
||||||
|
Advancing past the title is intermittent — **1 success in 3** on 2026-08-19 with
|
||||||
|
the same binary, profile and procedure — and the input path had already been
|
||||||
|
excluded three ways (the press is logged as delivered to the guest). Comparing
|
||||||
|
the successful boot against the failed ones line by line says what actually
|
||||||
|
differs.
|
||||||
|
|
||||||
|
**A slot-`(1F)` guest thread is spawned by the press.** It starts exactly once
|
||||||
|
per run, immediately after the Ⓐ keydown, at the same stack base
|
||||||
|
(`70880000-70900000`) in both runs that got one:
|
||||||
|
|
||||||
|
| run | Ⓐ delivered at line | `(1F)` thread starts | `ResolvePath` calls after |
|
||||||
|
|---|---|---|---|
|
||||||
|
| `prm6` — **reached the menu** | 6498 | 6500 | **6** |
|
||||||
|
| `opt2` — stuck on the title | 1287 | 1288 | **0** |
|
||||||
|
| `opt` — stalled before the title | never | **never starts** | — |
|
||||||
|
|
||||||
|
The run that never accepted a press never creates a `(1F)` thread at all, which
|
||||||
|
rules out "a periodic worker that happens to start around then".
|
||||||
|
|
||||||
|
So the game **does** act on the button: it spawns its loader. In the successful
|
||||||
|
run that loader immediately reads six paths out of the on-disc cache —
|
||||||
|
|
||||||
|
```
|
||||||
|
HostPathDevice::ResolvePath(\aab216c3\a\c7e701e)
|
||||||
|
HostPathDevice::ResolvePath(\d5faa9db\e\b80b1a0)
|
||||||
|
HostPathDevice::ResolvePath(\d5faa9db\c\9f11f8b)
|
||||||
|
```
|
||||||
|
|
||||||
|
— and the menu appears. In the failed run the same thread starts and performs
|
||||||
|
**no file I/O ever again**
|
||||||
|
([log](captures/title-loader-thread-stalls.log)). Total `ResolvePath` counts for
|
||||||
|
the three boots are 90 / 84 / 78: the successful run's extra six are exactly the
|
||||||
|
ones after the press, so the boots are otherwise identical in I/O.
|
||||||
|
|
||||||
|
### Refuted: it is not the cache-flush crash
|
||||||
|
|
||||||
|
The obvious suspect was the `std::out_of_range` in the cache flush
|
||||||
|
([`title-crash-stl-tree.md`](title-crash-stl-tree.md)), which that page shows an
|
||||||
|
incomplete on-disc cache triggers ~100 s into a boot. **All four of today's runs
|
||||||
|
have zero** `GUEST-THROW`, zero `CRASH DUMP` and zero `Access Violation`. The
|
||||||
|
guest is alive throughout — RSS steady, the keystroke-poll counter climbing past
|
||||||
|
15 000 — it simply stops loading.
|
||||||
|
|
||||||
|
### Where the next probe goes
|
||||||
|
|
||||||
|
Not at input, and not at the crash. At the `(1F)` thread: it is created, it is
|
||||||
|
scheduled (the guest keeps running), and it issues no I/O. Whatever it waits on
|
||||||
|
first is the thing to find — a `KeSetEvent` / `NtWaitForSingleObject` trace on
|
||||||
|
that thread, or the file-system call it never reaches.
|
||||||
|
|
||||||
|
Worth noting for anyone scripting boots meanwhile: **retry whole boots**. Nothing
|
||||||
|
about the failed state recovers — four further presses over four minutes changed
|
||||||
|
nothing, which is consistent with a loader that is stuck rather than a screen
|
||||||
|
that is not listening.
|
||||||
|
|||||||
1421
docs/re/captures/title-loader-thread-stalls.log
Normal file
1421
docs/re/captures/title-loader-thread-stalls.log
Normal file
File diff suppressed because it is too large
Load Diff
Reference in New Issue
Block a user