re: the A-press dialog is the SIGN-IN dialog -- and the corpus already knew

Answers the open half of the A-press diagnosis, and most of the answer was
already in the tree.

The faulting runs booted with logged_profile_slot_0_xuid = "" -- their own
config dump -- while a profile existed (Found 1 Profiles). With nobody signed
in, A takes the state-0 branch of sub_821D03A0 and calls XamShowSigninUI(1,1);
Canary raises its Sign In dialog with a no-op close handler and nothing in an
unattended run dismisses it. 85 instructions verified against the image, 0
mismatches; the state-3 branch is XamShowDeviceSelectorUI, already ruled out by
storage_selection_dialog = false.

The correlation runs through the tooling: boot_menu.sh passes the profile flag
and Q4/Q5 pressed all five buttons; frame_clock.sh, which produced the faulting
run, does not.

So there is no blocker -- boot with boot_menu.sh. Flagged as retrodicted rather
than A/B tested, since I have not myself booted both ways and pressed A.

The uncomfortable half: canary-scripted-input-traps.md section 3 already named
the sign-in dialog WITH a committed capture, and boot_menu.sh's header already
carried the mechanism and the 8.4 million figure. The fault page searched for
the cause it had hypothesised and never searched for its own symptom. Added to
METHOD.md, along with the more expensive lesson -- a measurement whose only
record is a script comment is invisible to the document that needs it.

What this session did add is the join: that the known blackout is what drives an
unbounded guest queue into a failed 128 MB allocation.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Wuu56cE8vJGTBtn1ppsk8v
This commit is contained in:
sylph-decoder
2026-08-30 07:21:18 +00:00
parent 15d9037774
commit 8dfa0ebac5
3 changed files with 126 additions and 34 deletions

View File

@@ -141,42 +141,86 @@ Evidence: [`../data/a-press-fault-log-extract.txt`](../data/a-press-fault-log-ex
crash makes Xenia call `ImGuiDialog::ShowMessageBox` (`emulator.cc:1487`), which is
itself a UI — so the swallow can only get worse after the first fault.
## 🟡 What is still open: *which* dialog
## ✅ ANSWERED — it is the **sign-in** dialog, and the run had no profile signed in
`is_xam_dialog_present_` is a single bool with no logging on the setting side, so the
log says a XAM dialog exists and not which one. The static reach:
Not a new measurement: **the corpus already had this**, and this page failed to
connect to it. [`canary-scripted-input-traps.md`](../canary-scripted-input-traps.md)
§3 says it outright — *"With no profile, Ⓐ **is** handled: the guest calls
`XamShowSigninUI` and Xenia pops its Sign In dialog"* — with a committed capture,
[`title-signin-dialog.png`](../captures/title-signin-dialog.png). And
`tools/re-capture/boot_menu.sh`'s own header has carried the mechanism, **including
the 8.4 million figure**, since before this page was written.
* `XamShowDeviceSelectorUI`**ruled out**. The run's own config dump carries
`storage_selection_dialog = false`, and `xam_ui.cc:550` takes the headless path in
that case, which never sets the flag.
* `XamShowSigninUI` and `XamShowMessageBoxUIEx` — both set it, both are imported, and
both reach the guest. `sub_821D03A0` calls the game's `XamShowSigninUI` **and**
`XamShowDeviceSelectorUI` wrappers, which is the shape of a "sign in, then pick
storage" flow — exactly what a title screen's Ⓐ would start.
* `XamShowKeyboardUI`, `XamShowDirtyDiscErrorUI` — imported; not excluded, but neither
fits the moment.
### The run's own config dump says the profile was not signed in
**The experiment that settles it** is one line of Canary, not another blind boot: log
the function name at each `is_xam_dialog_present_.store(true)` site in `xam_ui.cc`.
Recorded rather than done, because it is an emulator change and this iteration's
budget went to the diagnosis.
```
[Profiles]
create_profile_if_none = ""
logged_profile_slot_0_xuid = "" ← nobody logged in
...
i> FindProfiles: Adding profile B13EBABEBABEBABE to profile list
i> ProfileManager: Found 1 Profiles ← a profile EXISTS, it is just not signed in
```
### And the call site is now located in the image, not only observed
`sub_821D03A0` is the state machine that raises it, verified byte-for-byte
(**85 instructions, 0 mismatches**):
| state at `[[r31+8]+4]` | branch | call |
|---|---|---|
| **0** | `0x821D04CC` | `li r4,1; li r3,1; bl 0x824A9068` → thunk `0x8284DA8C` = **`XamShowSigninUI(1, 1)`** |
| **3** | `0x821D04A4` | `bl 0x824A9080``0x8284DABC` = `XamShowDeviceSelectorUI` |
| other | — | nothing |
So the two candidates this page listed are both real branches of one function, and
the run took the **state-0** one. The device selector was already ruled out by
`storage_selection_dialog = false`; this identifies the other by address rather
than by elimination.
Canary's `xeXamShowSigninUI` then sets the flag and dispatches `ui::SigninUI`
**asynchronously with a no-op close handler** — so in an unattended run nothing
ever dismisses it, and the swallow is permanent.
### The correlation runs through the tooling, not just this one log
| launcher | passes `--logged_profile_slot_0_xuid` | Ⓐ outcome |
|---|---|---|
| `boot_menu.sh` | **yes** | Q4/Q5 pressed all five menu buttons |
| `frame_clock.sh` (this run) | **no** | faulted, 4/4 |
### 🔴 The process failure, which is the part worth keeping
This page said *"it does not explain how Q4/Q5 pressed Ⓐ successfully; what differs
is unfound."* **It was found, twice, and written down in two places this page did
not read** — a sibling `docs/re/` page and a tool header. The corpus knew the
swallow and knew the profile requirement; nobody had joined either to the crash.
What this session actually adds is the **join**: that the known input blackout is
what drives an unbounded guest queue into a failed 128 MB allocation, with the
counter and the register file agreeing to 7. Recorded in
[`METHOD.md`](../METHOD.md).
## What this unblocks, and how
The blocked list — main-menu sweeps, whether a `.tbm` draws pixels, `pbafc.prm`'s
blend — needs a screen behind an Ⓐ press. Three routes now exist where before there
were none, in cost order:
blend — needs a screen behind an Ⓐ press.
1. **Dismiss the dialog.** It is an ImGui window on the emulator surface; the run had
a display. If it can be clicked or key-dismissed, the flag clears and the pump
drains normally. Cheapest, and testable in one boot.
2. **`--headless`.** Both `xeXamShowSigninUI` and `XamShowMessageBoxUIEx` take a
dispatch-headless path that never sets the flag. ⚠️ It also removes the window the
capture harness grabs, so this trades the fault for a different blocker.
3. **Patch the swallow.** Returning `X_ERROR_EMPTY` instead of `X_ERROR_SUCCESS` at
`xam_input.cc:217` terminates the pump immediately and is closer to hardware
(a real Xbox does not hand a game an infinite run of empty keystrokes). This is
an emulator change and needs to be recorded as one wherever it is used.
**There is no blocker. Boot with `tools/re-capture/boot_menu.sh`**, which signs
the existing profile in, and the state-0 branch never fires. That is the launcher
Q4 and Q5 used, and it has been in the tree the whole time.
⚠️ **This is a prediction retrodicted, not an A/B I ran.** The mechanism is measured
and the launcher difference is documented, and Q4/Q5 are the oracle evidence that
Ⓐ works under `boot_menu.sh` — but I have not myself booted both ways and pressed Ⓐ.
Until someone does, treat "signing the profile in prevents the fault" as strongly
supported rather than demonstrated.
If it ever needs a belt-and-braces second route, patching `xam_input.cc:217` to
return `X_ERROR_EMPTY` instead of `X_ERROR_SUCCESS` terminates the pump immediately
and is closer to hardware — a real Xbox does not hand a game an infinite run of
empty keystrokes. That is an emulator change and must be recorded as one wherever
it is used.
⚠️ **Whichever route is taken, keep `tools/re-capture/frame_clock.sh`'s size guard.**
It killed this run at its 300 MB cap and worked exactly as designed; without it the