feat: a crash window that shows the crash report and sends it only on Send Help #141

Open
gab9281 wants to merge 8 commits from gab9281/Longshot:feat/crash-report-window into main
Member

Why

When Longshot crashes, the player gets nothing and the team learns nothing unless someone digs out
longshot_log.txt and posts it. With this PR, a window opens after a crash. It shows exactly what a report holds, and
sends it to #81 only when the player presses Send Help. I am sorry sends nothing.

What changed

  • docs: docs/crash-report-window.md: what the player sees, what a report holds and never holds, the release flag,
    how the parts fit, Always send, the steps left, and what testing on real builds found. Icons:
    assets/crash-bean.png (the report page) and assets/magicbean-report-sent.png (the Sent page; the Qt builder ships byte-identical copies of both, which its test checks).
  • nx2: nx2/crash_report.py, shared by both builders and the tests:
    • pending() finds the crashed run's log through crash_pending.txt, including after a rotation.
    • build() makes the report:
      • Fields: version, release flag, OS, CPU and RAM, GPU and driver, renderer, map.
      • Settings: every setting, defaults included.
      • Crash: the CRASH: lines without the register and memory rows, and the 150 log lines before them.
      • Folders are shown as ~, and the user name is redacted wherever it appears as a word (e.g. -home-<user>- in a
        path written with dashes), in its own case: a Steam Deck's user is deck, and its report must still say "Steam
        Deck". Every field stays within the relay's limits. The OS and CPU come from the machine when the log has no line.
      • The crash's place is one the relay takes: libc.so.6+0x… without the library's path, and unknown+0x10 for a
        place in no module.
    • send() posts it to the relay. An answer it can't read keeps the report for next time.
    • The relay's and #81's addresses are in nx2/addresses.ini, not in the code (one place to edit when a service moves).
    • Device names (the microphone's from the options, the audio output's) never reach the log lines.
    • card(), settings_text(), log_text(): the window's rows and Show texts, shared by both builders.
    • clear(folder, when) drops only the marker of the crash a window opened for.
    • always_send() and set_always_send() are the launcher's tick.
    • comment_link() is the Sent page's link.
  • host: host/hos_crash_window.c:
    • hos_crash_window_init() builds the command once at startup, from longshot_version.txt's builder= and
      builder_args=.
    • hos_crash_window_open() runs in report_crash (host/mkw_glue.c) after the log is flushed. It writes
      crash_pending.txt, then starts <builder> --crash <folder>.
      • Windows: CreateProcessW, detached.
      • Linux: vfork and execve from the signal handler, with output to /dev/null.
    • It runs once per process. LONGSHOT_NO_CRASH_WINDOW follows the switches' rule (env_on: 0, false, off, no are off).
  • host/vk: report: gpu|cpu|os|renderer lines in the startup log, which the report reads:
    • cpu_text() and os_text() in gpu/vk/vk_bug_report.cpp;
    • the log lines in gpu/vk/vk_main.cpp and host/rx_backend.c.
  • builder (Linux):
    • builder/linux/longshot_builder.py --crash <folder> (show_crash, crash_send_help, crash_sorry,
      show_crash_sent).
    • A report the window never showed is offered at --play and --launch (then on to the launcher page or Play,
      from the Sent page's Close too, as on Qt).
    • The launcher page gets an "Always send crash reports" tick.
  • builder (Windows):
    • builder/py/longshot_builder/crash.py is the same window in Qt. It doesn't use winreg or window.py, so its
      test runs on Linux.
    • longshot_builder_start.py --crash <folder>.
    • A waiting report is offered before the launcher's page.
    • The tick is in window.py.
  • tests:
    • tests/test_crash_report.py: 23 tests on the report.
    • tests/test_crash_window.py: compiles hos_crash_window.c with a stand-in builder.
    • tests/test_crash_window_qt.py: opens the Qt window offscreen.

Flags and settings

Flag What it does Default now Recommendation Helps on Doesn't help on Untested on
crash_reports (longshot_options.ini) 0: a crash opens no window and writes no marker on (absent counts as on) On by default: nothing is sent without a click all — the menu row doesn't exist yet: it's set by hand
LONGSHOT_NO_CRASH_WINDOW=1 turns the crash window off for a run unset Set for tests, benchmarks and CI automated runs — —
longshot_crash.ini always_send=1 the launcher's "Always send crash reports" tick: the window still shows the report, and sends it without waiting for Send Help off Off by default: it's the player's choice players who always want to send — Windows outside Wine
--crash <folder> (both builders) opens only the crash window for that folder — Started by the game; not for players — — —

Measurements

The new code runs at startup (it builds one command) and at a crash, so the check is that startup and play are
unchanged, and how long the window takes after a crash. Measured with RX_VK_FRAME_LOG, the game started as the
launcher starts it, 60 s each, no input (the title and the attract demo), frames from 20 s on; interleaved main, PR,
main, PR in the same folder layout (work/game-linux-main and work/game-linux, built the same way). RTX 3060 Laptop
(NVIDIA 620.70.06), Ryzen 7 6800H, 15 GB, CachyOS (Linux 7.3.3), KDE Wayland, the default settings.

main: 6b7fa356 (2026-11-13)
this PR: feat/crash-report-window @ bb847be7 (the same code as 77609f45, rebased after on main @ 36a12f6f: the website, the
compile-shaders choice, the builders' self-update removal; none of it in the game's start or play measured here)

main @ 6b7fa356 this PR @ bb847be7
First present after the start (s), median (runs) 3.06 (3.36, 2.76) 2.74 (2.81, 2.66)
Frame time (ms), median (runs) 33.84 (33.73, 33.95) 33.83 (33.75, 33.90)
Average fps (runs) 29.45 (29.6, 29.3) 29.45 (29.6, 29.3)
1% low fps (runs) 27.9 (28.8, 27.0) 27.75 (28.6, 26.9)
A crash (kill -SEGV at 25 s) to builder --crash running (s), median (runs) none: nothing opens (no marker either) 0.11 (0.09, 0.13), the marker written

Startup and play are the same within run-to-run noise (the title runs at its 30 fps either way). The crash row is when
the builder's process is running; its window is drawn a moment after (Tk's start).

Testing

Tested:

  • Game-free: RX_CPM=<the CPM cache> python -I -B tests/run_all.py --jobs 12 on 77609f45 (rebased on main @ 36a12f6f):
    520 passed, 1 failed, 19 skipped (Windows only). The failure, tests/test_prepare_cache_save.py (compile_all
    undeclared in its fixture), fails the same on main @ 36a12f6f: it comes with #158, not this PR. Before that rebase, on
    35ee48e1 (main @ 6b7fa356): 522 passed, 0 failed. The new checks are test_crash_report.py,
    test_crash_window.py and test_crash_window_qt.py.
  • In the game, Linux: OoT built from this branch, on an RTX 3060 Laptop (NVIDIA 620.70.06), a Ryzen 7 6800H with
    15 GB, CachyOS (Linux 7.3.3), KDE Wayland.
    • Rebuilt at 608dd588 (the game's code is the same at 715cf050: only the bean image and the rebase on a CI-only
      change came after), and again at bb847be7 for the Measurements above. The game was started as the launcher starts it, then sent kill -SEGV during startup.
    • The window opened within a few seconds with the real GPU, CPU and OS.
    • Send Help posted to #81, and a second report of the same crash was added to the same comment.
    • I am sorry sent nothing.
    • The Sent page's link opens the report's own comment.
  • In the game, Windows: the same game built with llvm-mingw, run under Wine 11.21 with the Windows Python 3.12 and
    PySide6 6.8.
    • Built at 752ff889 (same code as 715cf050). An access violation in the game (a thread started at a bad address) opened the Qt window.
    • Send Help posted to #81. This test is where the ?+0x10 place came up, which the relay refused before the
      fix: the window now shows and sends it as unknown+0x10.
  • The crash relay's own parser (Bean-Ops) accepts the reports from both real crashes.

Not tested:

  • Windows itself, rather than Wine, with the packaged Qt builder and the game in bin\.
  • A real crash in play: these crashes were a signal sent from outside (Linux) and a thread started at a bad
    address (Windows), both during startup. So the map and renderer fields show "not known".
  • The release flag on a release: CI doesn't write source= yet (a step left), so every report is "not a release"
    for now.

Needs other testers:

  • Windows 10/11, not Wine: a crash opens the window from the Longshot shortcut, Send Help posts to #81, expecting
    the window within a few seconds and the comment's link working (T-YFML).
  • AMD and Intel GPUs: the report: gpu line names the card and driver, expecting both in the window's Graphics card
    row (T-FTCD).

Screenshots

main @ 39647e1a has no crash window: a crash ends the game with nothing on screen. Everything below is this PR. Home
folders are blurred on the launcher shots; nothing else is edited.

Linux (this PR @ 608dd588, a real crash: kill -SEGV on the running game)

The crash window Show (the log) Show (the settings)
crash window show log show settings
Sent The launcher's tick
sent launcher

Windows (this PR @ 752ff889 under Wine 11.21, a real access violation in the game)

The crash window Sent The launcher's tick
crash window sent launcher

The Sent pages were drawn without sending (this report was already on #81 from earlier runs); the link and text are
the ones a real send shows.

Risk and rollback

  • The crash path itself: hos_crash_window_open() runs inside the crash handler. On Linux that's a signal
    handler, so it uses only open/write/vfork/execve and allocates nothing. If it fails, the crash ends as it
    does on main, with the marker left for the next launch.
  • Turning it off: crash_reports=0 or LONGSHOT_NO_CRASH_WINDOW=1. Reverting the PR is enough otherwise.
  • Privacy: the window shows everything before it sends, and sends only on a click. Paths are redacted to ~,
    and settings like bindings and the microphone's name are never sent.

Reviewer notes

  • Start with host/hos_crash_window.c (what runs in the crash handler), then nx2/crash_report.py build() (what
    leaves the PC).
  • Folders built from a checkout get no longshot_version.txt, so no builder= line and no window. Releases have
    one.
  • The game writes longshot_log.txt only when it isn't started from a terminal. Started from a terminal, it logs
    there, and the window finds no crash to report.
  • Left for follow-ups on purpose, listed in the doc's Steps:
    • CI's source= line (the release flag);
    • longshot_defaults.ini;
    • the Crash reports row in the in-game menu and in recomplauncher.json;
    • the AGENTS.md rule.
  • The relay's side (the release field, [not a release]) is already deployed in Bean-Ops.

Issues

See #81

Checklist

For everyone

  • One topic.
  • The title is a Conventional Commit (type(scope): description).
  • Rebased on current main.
  • python -I -B tests/run_all.py run and passing (any failure that also fails on main is named above).
  • Tested in the game, or what wasn't is named under Testing.
  • Testing filled in: what was tested, what wasn't, and what needs other testers (with test requests).
  • Measured: main and this PR at named commits, on the same PC, scene and settings, at least 2 interleaved runs each, the median reported.
  • No game files, dumps, build output or generated files.
  • third_party/ untouched (a new folder with a PROVENANCE.md instead).
  • The license is OK: GPL-3.0-or-later, nothing incompatible and nothing decompiled. (Both beans are Magic Bean's own art.)

If applicable

  • AI assistance recorded with Assisted-by: / Co-Authored-By: trailers.
  • Flags noted, and the switch reference updated (docs/development.md, the README).
  • Screenshots for a change that shows on screen.
  • A game-free test added for the fix, failing on main and passing here.
  • A check under tests/ that reads changed source updated in this PR, not weakened.
  • Host code builds on both Windows (llvm-mingw) and Linux, with UTF-8 paths. (After the review fixes: hos_crash_window.c again with llvm-mingw -Werror; the rx_backend.c change is one log line.)
  • Docs updated.

🤖 Generated with Claude Code

https://claude.ai/code/session_015KgSKoUqUvce5UXG89NBgi

## Why When Longshot crashes, the player gets nothing and the team learns nothing unless someone digs out `longshot_log.txt` and posts it. With this PR, a window opens after a crash. It shows exactly what a report holds, and sends it to #81 only when the player presses **Send Help**. **I am sorry** sends nothing. ## What changed - docs: `docs/crash-report-window.md`: what the player sees, what a report holds and never holds, the release flag, how the parts fit, Always send, the steps left, and what testing on real builds found. Icons: `assets/crash-bean.png` (the report page) and `assets/magicbean-report-sent.png` (the Sent page; the Qt builder ships byte-identical copies of both, which its test checks). - nx2: `nx2/crash_report.py`, shared by both builders and the tests: - `pending()` finds the crashed run's log through `crash_pending.txt`, including after a rotation. - `build()` makes the report: - Fields: version, release flag, OS, CPU and RAM, GPU and driver, renderer, map. - Settings: every setting, defaults included. - Crash: the `CRASH:` lines without the register and memory rows, and the 150 log lines before them. - Folders are shown as `~`, and the user name is redacted wherever it appears as a word (e.g. `-home-<user>-` in a path written with dashes), in its own case: a Steam Deck's user is `deck`, and its report must still say "Steam Deck". Every field stays within the relay's limits. The OS and CPU come from the machine when the log has no line. - The crash's place is one the relay takes: `libc.so.6+0x…` without the library's path, and `unknown+0x10` for a place in no module. - `send()` posts it to the relay. An answer it can't read keeps the report for next time. - The relay's and #81's addresses are in `nx2/addresses.ini`, not in the code (one place to edit when a service moves). - Device names (the microphone's from the options, the audio output's) never reach the log lines. - `card()`, `settings_text()`, `log_text()`: the window's rows and Show texts, shared by both builders. - `clear(folder, when)` drops only the marker of the crash a window opened for. - `always_send()` and `set_always_send()` are the launcher's tick. - `comment_link()` is the Sent page's link. - host: `host/hos_crash_window.c`: - `hos_crash_window_init()` builds the command once at startup, from `longshot_version.txt`'s `builder=` and `builder_args=`. - `hos_crash_window_open()` runs in `report_crash` (`host/mkw_glue.c`) after the log is flushed. It writes `crash_pending.txt`, then starts `<builder> --crash <folder>`. - Windows: `CreateProcessW`, detached. - Linux: `vfork` and `execve` from the signal handler, with output to `/dev/null`. - It runs once per process. `LONGSHOT_NO_CRASH_WINDOW` follows the switches' rule (`env_on`: 0, false, off, no are off). - host/vk: `report: gpu|cpu|os|renderer` lines in the startup log, which the report reads: - `cpu_text()` and `os_text()` in `gpu/vk/vk_bug_report.cpp`; - the log lines in `gpu/vk/vk_main.cpp` and `host/rx_backend.c`. - builder (Linux): - `builder/linux/longshot_builder.py --crash <folder>` (`show_crash`, `crash_send_help`, `crash_sorry`, `show_crash_sent`). - A report the window never showed is offered at `--play` and `--launch` (then on to the launcher page or Play, from the Sent page's Close too, as on Qt). - The launcher page gets an "Always send crash reports" tick. - builder (Windows): - `builder/py/longshot_builder/crash.py` is the same window in Qt. It doesn't use `winreg` or `window.py`, so its test runs on Linux. - `longshot_builder_start.py --crash <folder>`. - A waiting report is offered before the launcher's page. - The tick is in `window.py`. - tests: - `tests/test_crash_report.py`: 23 tests on the report. - `tests/test_crash_window.py`: compiles `hos_crash_window.c` with a stand-in builder. - `tests/test_crash_window_qt.py`: opens the Qt window offscreen. ## Flags and settings | Flag | What it does | Default now | Recommendation | Helps on | Doesn't help on | Untested on | |---|---|---|---|---|---|---| | `crash_reports` (`longshot_options.ini`) | `0`: a crash opens no window and writes no marker | on (absent counts as on) | On by default: nothing is sent without a click | all | — | the menu row doesn't exist yet: it's set by hand | | `LONGSHOT_NO_CRASH_WINDOW=1` | turns the crash window off for a run | unset | Set for tests, benchmarks and CI | automated runs | — | — | | `longshot_crash.ini` `always_send=1` | the launcher's "Always send crash reports" tick: the window still shows the report, and sends it without waiting for Send Help | off | Off by default: it's the player's choice | players who always want to send | — | Windows outside Wine | | `--crash <folder>` (both builders) | opens only the crash window for that folder | — | Started by the game; not for players | — | — | — | ## Measurements The new code runs at startup (it builds one command) and at a crash, so the check is that startup and play are unchanged, and how long the window takes after a crash. Measured with `RX_VK_FRAME_LOG`, the game started as the launcher starts it, 60 s each, no input (the title and the attract demo), frames from 20 s on; interleaved main, PR, main, PR in the same folder layout (`work/game-linux-main` and `work/game-linux`, built the same way). RTX 3060 Laptop (NVIDIA 620.70.06), Ryzen 7 6800H, 15 GB, CachyOS (Linux 7.3.3), KDE Wayland, the default settings. main: 6b7fa356 (2026-11-13) this PR: feat/crash-report-window @ bb847be7 (the same code as 77609f45, rebased after on main @ 36a12f6f: the website, the compile-shaders choice, the builders' self-update removal; none of it in the game's start or play measured here) | | main @ 6b7fa356 | this PR @ bb847be7 | |---|---|---| | First present after the start (s), median (runs) | 3.06 (3.36, 2.76) | 2.74 (2.81, 2.66) | | Frame time (ms), median (runs) | 33.84 (33.73, 33.95) | 33.83 (33.75, 33.90) | | Average fps (runs) | 29.45 (29.6, 29.3) | 29.45 (29.6, 29.3) | | 1% low fps (runs) | 27.9 (28.8, 27.0) | 27.75 (28.6, 26.9) | | A crash (`kill -SEGV` at 25 s) to `builder --crash` running (s), median (runs) | none: nothing opens (no marker either) | 0.11 (0.09, 0.13), the marker written | Startup and play are the same within run-to-run noise (the title runs at its 30 fps either way). The crash row is when the builder's process is running; its window is drawn a moment after (Tk's start). ## Testing **Tested:** - Game-free: `RX_CPM=<the CPM cache> python -I -B tests/run_all.py --jobs 12` on 77609f45 (rebased on main @ 36a12f6f): 520 passed, 1 failed, 19 skipped (Windows only). The failure, `tests/test_prepare_cache_save.py` (`compile_all` undeclared in its fixture), fails the same on main @ 36a12f6f: it comes with #158, not this PR. Before that rebase, on 35ee48e1 (main @ 6b7fa356): 522 passed, 0 failed. The new checks are `test_crash_report.py`, `test_crash_window.py` and `test_crash_window_qt.py`. - In the game, Linux: OoT built from this branch, on an RTX 3060 Laptop (NVIDIA 620.70.06), a Ryzen 7 6800H with 15 GB, CachyOS (Linux 7.3.3), KDE Wayland. - Rebuilt at 608dd588 (the game's code is the same at 715cf050: only the bean image and the rebase on a CI-only change came after), and again at bb847be7 for the Measurements above. The game was started as the launcher starts it, then sent `kill -SEGV` during startup. - The window opened within a few seconds with the real GPU, CPU and OS. - **Send Help** posted to #81, and a second report of the same crash was added to the same comment. - **I am sorry** sent nothing. - The Sent page's link opens the report's own comment. - In the game, Windows: the same game built with llvm-mingw, run under Wine 11.21 with the Windows Python 3.12 and PySide6 6.8. - Built at 752ff889 (same code as 715cf050). An access violation in the game (a thread started at a bad address) opened the Qt window. - **Send Help** posted to #81. This test is where the `?+0x10` place came up, which the relay refused before the fix: the window now shows and sends it as `unknown+0x10`. - The crash relay's own parser (Bean-Ops) accepts the reports from both real crashes. **Not tested:** - Windows itself, rather than Wine, with the packaged Qt builder and the game in `bin\`. - A real crash in play: these crashes were a signal sent from outside (Linux) and a thread started at a bad address (Windows), both during startup. So the map and renderer fields show "not known". - The release flag on a release: CI doesn't write `source=` yet (a step left), so every report is "not a release" for now. **Needs other testers:** - Windows 10/11, not Wine: a crash opens the window from the Longshot shortcut, Send Help posts to #81, expecting the window within a few seconds and the comment's link working (T-YFML). - AMD and Intel GPUs: the `report: gpu` line names the card and driver, expecting both in the window's Graphics card row (T-FTCD). ## Screenshots main @ 39647e1a has no crash window: a crash ends the game with nothing on screen. Everything below is this PR. Home folders are blurred on the launcher shots; nothing else is edited. **Linux** (this PR @ 608dd588, a real crash: `kill -SEGV` on the running game) | The crash window | Show (the log) | Show (the settings) | |---|---|---| | ![crash window](https://git.magicbean.dev/attachments/636bf950-c431-4875-90d8-def85eef7a56) | ![show log](https://git.magicbean.dev/attachments/cd2a1a0a-d549-44d1-ba29-4a181b8b31e5) | ![show settings](https://git.magicbean.dev/attachments/3f5ec094-53c4-4648-9b36-9391f375942b) | | Sent | The launcher's tick | |---|---| | ![sent](https://git.magicbean.dev/attachments/902b3e4f-a38f-472f-9d8f-33ac46810d35) | ![launcher](https://git.magicbean.dev/attachments/8170864d-dc06-4569-bb6a-cdaf1ad5497b) | **Windows** (this PR @ 752ff889 under Wine 11.21, a real access violation in the game) | The crash window | Sent | The launcher's tick | |---|---|---| | ![crash window](https://git.magicbean.dev/attachments/e7db8ee7-374f-4186-b513-a3e988bc1105) | ![sent](https://git.magicbean.dev/attachments/964f0bbd-4b5d-4586-8e36-cc67ce14d9c4) | ![launcher](https://git.magicbean.dev/attachments/c2ada3ea-8069-480c-b19f-3e7920677f29) | The Sent pages were drawn without sending (this report was already on #81 from earlier runs); the link and text are the ones a real send shows. ## Risk and rollback - **The crash path itself:** `hos_crash_window_open()` runs inside the crash handler. On Linux that's a signal handler, so it uses only `open`/`write`/`vfork`/`execve` and allocates nothing. If it fails, the crash ends as it does on `main`, with the marker left for the next launch. - **Turning it off:** `crash_reports=0` or `LONGSHOT_NO_CRASH_WINDOW=1`. Reverting the PR is enough otherwise. - **Privacy:** the window shows everything before it sends, and sends only on a click. Paths are redacted to `~`, and settings like bindings and the microphone's name are never sent. ## Reviewer notes - Start with `host/hos_crash_window.c` (what runs in the crash handler), then `nx2/crash_report.py` `build()` (what leaves the PC). - Folders built from a checkout get no `longshot_version.txt`, so no `builder=` line and no window. Releases have one. - The game writes `longshot_log.txt` only when it isn't started from a terminal. Started from a terminal, it logs there, and the window finds no crash to report. - Left for follow-ups on purpose, listed in the doc's Steps: - CI's `source=` line (the release flag); - `longshot_defaults.ini`; - the Crash reports row in the in-game menu and in `recomplauncher.json`; - the AGENTS.md rule. - The relay's side (the `release` field, `[not a release]`) is already deployed in Bean-Ops. ## Issues See #81 ## Checklist ### For everyone - [x] One topic. - [x] The title is a Conventional Commit (`type(scope): description`). - [x] Rebased on current `main`. - [x] `python -I -B tests/run_all.py` run and passing (any failure that also fails on `main` is named above). - [x] Tested in the game, or what wasn't is named under Testing. - [x] Testing filled in: what was tested, what wasn't, and what needs other testers (with test requests). - [x] Measured: main and this PR at named commits, on the same PC, scene and settings, at least 2 interleaved runs each, the median reported. - [x] No game files, dumps, build output or generated files. - [x] `third_party/` untouched (a new folder with a `PROVENANCE.md` instead). - [x] The license is OK: GPL-3.0-or-later, nothing incompatible and nothing decompiled. (Both beans are Magic Bean's own art.) ### If applicable - [x] AI assistance recorded with `Assisted-by:` / `Co-Authored-By:` trailers. - [x] Flags noted, and the switch reference updated (docs/development.md, the README). - [x] Screenshots for a change that shows on screen. - [x] A game-free test added for the fix, failing on `main` and passing here. - [x] A check under `tests/` that reads changed source updated in this PR, not weakened. - [x] Host code builds on both Windows (llvm-mingw) and Linux, with UTF-8 paths. (After the review fixes: `hos_crash_window.c` again with llvm-mingw `-Werror`; the `rx_backend.c` change is one log line.) - [x] Docs updated. 🤖 Generated with [Claude Code](https://claude.com/claude-code) https://claude.ai/code/session_015KgSKoUqUvce5UXG89NBgi
gab9281 self-assigned this 2026-11-13 06:22:43 +00:00
docs/crash-report-window.md: what the player sees (the crying bean,
assets/crash-bean.png; the happy bean on the Sent page, assets/thanks-bean.png),
what a report holds and never holds, the release flag and the agents' rule for
reports that aren't from a release, how the game, the builders and
nx2/crash_report.py share the work, Always send, the steps left and what
testing on real builds found.

Co-Authored-By: Claude Opus 5.5 <[email protected]>
Claude-Session: https://claude.ai/code/session_015KgSKoUqUvce5UXG89NBgi
Built from what is on disk after a crash: the crashed run's log (its version
and source fingerprint, report: lines, map, CRASH: lines without the memory
rows) and every setting, defaults included. User names redacted, every field
within the relay's limits, the crash's place one the relay takes. send() posts
it to the crash relay; clear() drops only the marker of the crash a window
opened for; always_send for the launcher's tick; comment_link for the Sent
page.

Co-Authored-By: Claude Opus 5.5 <[email protected]>
Claude-Session: https://claude.ai/code/session_015KgSKoUqUvce5UXG89NBgi
host/hos_crash_window.c: the command from longshot_version.txt's builder= and
builder_args= at startup; at a crash nothing handles, after report_crash
flushes the log, crash_pending.txt and <builder> --crash <folder>
(CreateProcessW detached on Windows; vfork and execve from the signal handler
on Linux, output to /dev/null). Once per process; off with crash_reports=0,
LONGSHOT_NO_CRASH_WINDOW or no builder= line.

The startup log gains report: gpu, cpu, os and renderer lines
(vk_bug_report's cpu_text and os_text), which the report reads.

Co-Authored-By: Claude Opus 5.5 <[email protected]>
Claude-Session: https://claude.ai/code/session_015KgSKoUqUvce5UXG89NBgi
longshot_builder.py --crash <folder>: what the report holds, Show for the
settings and the log as sent, Send Help or I am sorry, then Sent. Thank you
with a link to the report's comment on #81. A report the window never showed
is offered at --play and --launch. The launcher's Always send crash reports
tick.

Co-Authored-By: Claude Opus 5.5 <[email protected]>
Claude-Session: https://claude.ai/code/session_015KgSKoUqUvce5UXG89NBgi
feat(builder): the crash window in the Qt builder (Windows)
Some checks failed
CI / Python source checks (ubuntu-24.04, part 1/2) (pull_request) Has been skipped
CI / Python source checks (ubuntu-24.04, part 2/2) (pull_request) Has been skipped
CI / SPIR-V fixtures (global narrow load/store, direct surface atomics, F2I immediate) (pull_request) Has been skipped
Third-party parts / The same as upstream (pull_request) Has been skipped
PR description / Description follows the template (pull_request_target) Failing after 9s
CI / Conventional Commit title (pull_request) Failing after 7s
CI / Workflow lint (actionlint) (pull_request) Failing after 9s
Third-party parts / As their notes say (pull_request) Successful in 16s
1f0e9dc5f5
builder/py/longshot_builder/crash.py, the same window in Qt without winreg so
tests/test_crash_window_qt.py opens it offscreen on Linux too;
longshot_builder_start.py --crash <folder>, and a waiting report offered
before the launcher's page; the launcher's Always send crash reports tick.
The icons are copies of assets/, checked by the test.

Co-Authored-By: Claude Opus 5.5 <[email protected]>
Claude-Session: https://claude.ai/code/session_015KgSKoUqUvce5UXG89NBgi
gab9281 force-pushed feat/crash-report-window from 1f0e9dc5f5
Some checks failed
CI / Python source checks (ubuntu-24.04, part 1/2) (pull_request) Has been skipped
CI / Python source checks (ubuntu-24.04, part 2/2) (pull_request) Has been skipped
CI / SPIR-V fixtures (global narrow load/store, direct surface atomics, F2I immediate) (pull_request) Has been skipped
Third-party parts / The same as upstream (pull_request) Has been skipped
PR description / Description follows the template (pull_request_target) Failing after 9s
CI / Conventional Commit title (pull_request) Failing after 7s
CI / Workflow lint (actionlint) (pull_request) Failing after 9s
Third-party parts / As their notes say (pull_request) Successful in 16s
to edfc1ef3e1
Some checks failed
CI / Python source checks (ubuntu-24.04, part 1/2) (pull_request) Has been skipped
CI / Python source checks (ubuntu-24.04, part 2/2) (pull_request) Has been skipped
CI / SPIR-V fixtures (global narrow load/store, direct surface atomics, F2I immediate) (pull_request) Has been skipped
Third-party parts / The same as upstream (pull_request) Has been skipped
PR description / Description follows the template (pull_request_target) Failing after 9s
CI / Conventional Commit title (pull_request) Has been cancelled
CI / Workflow lint (actionlint) (pull_request) Has been cancelled
Third-party parts / As their notes say (pull_request) Has been cancelled
2026-11-13 06:42:09 +00:00
Compare
gab9281 force-pushed feat/crash-report-window from edfc1ef3e1
Some checks failed
CI / Python source checks (ubuntu-24.04, part 1/2) (pull_request) Has been skipped
CI / Python source checks (ubuntu-24.04, part 2/2) (pull_request) Has been skipped
CI / SPIR-V fixtures (global narrow load/store, direct surface atomics, F2I immediate) (pull_request) Has been skipped
Third-party parts / The same as upstream (pull_request) Has been skipped
PR description / Description follows the template (pull_request_target) Failing after 9s
CI / Conventional Commit title (pull_request) Has been cancelled
CI / Workflow lint (actionlint) (pull_request) Has been cancelled
Third-party parts / As their notes say (pull_request) Has been cancelled
to 468fe236df
Some checks failed
CI / Python source checks (ubuntu-24.04, part 1/2) (pull_request) Has been skipped
CI / Python source checks (ubuntu-24.04, part 2/2) (pull_request) Has been skipped
CI / SPIR-V fixtures (global narrow load/store, direct surface atomics, F2I immediate) (pull_request) Has been skipped
Third-party parts / The same as upstream (pull_request) Has been skipped
PR description / Description follows the template (pull_request_target) Failing after 8s
CI / Conventional Commit title (pull_request) Failing after 8s
CI / Workflow lint (actionlint) (pull_request) Failing after 10s
Third-party parts / As their notes say (pull_request) Successful in 15s
2026-11-13 06:42:20 +00:00
Compare
gab9281 force-pushed feat/crash-report-window from 468fe236df
Some checks failed
CI / Python source checks (ubuntu-24.04, part 1/2) (pull_request) Has been skipped
CI / Python source checks (ubuntu-24.04, part 2/2) (pull_request) Has been skipped
CI / SPIR-V fixtures (global narrow load/store, direct surface atomics, F2I immediate) (pull_request) Has been skipped
Third-party parts / The same as upstream (pull_request) Has been skipped
PR description / Description follows the template (pull_request_target) Failing after 8s
CI / Conventional Commit title (pull_request) Failing after 8s
CI / Workflow lint (actionlint) (pull_request) Failing after 10s
Third-party parts / As their notes say (pull_request) Successful in 15s
to 752ff88994
Some checks failed
CI / Python source checks (ubuntu-24.04, part 1/2) (pull_request) Has been skipped
CI / Python source checks (ubuntu-24.04, part 2/2) (pull_request) Has been skipped
CI / SPIR-V fixtures (global narrow load/store, direct surface atomics, F2I immediate) (pull_request) Has been skipped
Third-party parts / The same as upstream (pull_request) Has been skipped
CI / Conventional Commit title (pull_request) Failing after 6s
CI / Workflow lint (actionlint) (pull_request) Failing after 10s
Third-party parts / As their notes say (pull_request) Successful in 13s
PR description / Description follows the template (pull_request_target) Failing after 7s
2026-11-13 06:52:13 +00:00
Compare
gab9281 force-pushed feat/crash-report-window from 752ff88994
Some checks failed
CI / Python source checks (ubuntu-24.04, part 1/2) (pull_request) Has been skipped
CI / Python source checks (ubuntu-24.04, part 2/2) (pull_request) Has been skipped
CI / SPIR-V fixtures (global narrow load/store, direct surface atomics, F2I immediate) (pull_request) Has been skipped
Third-party parts / The same as upstream (pull_request) Has been skipped
CI / Conventional Commit title (pull_request) Failing after 6s
CI / Workflow lint (actionlint) (pull_request) Failing after 10s
Third-party parts / As their notes say (pull_request) Successful in 13s
PR description / Description follows the template (pull_request_target) Failing after 7s
to 715cf050da
Some checks failed
CI / Python source checks (ubuntu-24.04, part 1/2) (pull_request) Has been skipped
CI / Python source checks (ubuntu-24.04, part 2/2) (pull_request) Has been skipped
CI / SPIR-V fixtures (global narrow load/store, direct surface atomics, F2I immediate) (pull_request) Has been skipped
Third-party parts / The same as upstream (pull_request) Has been skipped
CI / Conventional Commit title (pull_request) Failing after 6s
CI / Workflow lint (actionlint) (pull_request) Successful in 9s
Third-party parts / As their notes say (pull_request) Successful in 11s
PR description / Description follows the template (pull_request_target) Failing after 3s
2026-11-13 07:00:35 +00:00
Compare
gab9281 changed title from feat/crash-report-window to WIP: feat: a crash window that shows the crash report and sends it only on Send Help 2026-11-13 07:00:55 +00:00
Author
Member

Updated to 715cf050, rebased on main @ 39647e1a (a CI-only change).

  • The Sent page's icon is now assets/magicbean-report-sent.png, Magic Bean's own art, which replaces the earlier
    bean; the license box is ticked.
  • The Sent page says "Your crash report has been submitted to the team, thank you!" and its link opens the report's
    own comment on #81.
  • The report redacts the user name wherever it appears as a word, not only in home paths.
  • A window left open no longer drops the marker of a later crash, and a report the server couldn't receive is kept.
  • python -I -B tests/run_all.py: 477 passed, 0 failed, 64 skipped.
  • New screenshots in the description, from real crashes on Linux and on Windows under Wine.

🤖 Generated with Claude Code

Updated to 715cf050, rebased on main @ 39647e1a (a CI-only change). - The Sent page's icon is now `assets/magicbean-report-sent.png`, Magic Bean's own art, which replaces the earlier bean; the license box is ticked. - The Sent page says "Your crash report has been submitted to the team, thank you!" and its link opens the report's own comment on #81. - The report redacts the user name wherever it appears as a word, not only in home paths. - A window left open no longer drops the marker of a later crash, and a report the server couldn't receive is kept. - `python -I -B tests/run_all.py`: 477 passed, 0 failed, 64 skipped. - New screenshots in the description, from real crashes on Linux and on Windows under Wine. 🤖 Generated with [Claude Code](https://claude.com/claude-code)
gab9281 changed title from WIP: feat: a crash window that shows the crash report and sends it only on Send Help to feat: a crash window that shows the crash report and sends it only on Send Help 2026-11-13 07:02:26 +00:00
gab9281 force-pushed feat/crash-report-window from 715cf050da
Some checks failed
CI / Python source checks (ubuntu-24.04, part 1/2) (pull_request) Has been skipped
CI / Python source checks (ubuntu-24.04, part 2/2) (pull_request) Has been skipped
CI / SPIR-V fixtures (global narrow load/store, direct surface atomics, F2I immediate) (pull_request) Has been skipped
Third-party parts / The same as upstream (pull_request) Has been skipped
CI / Conventional Commit title (pull_request) Failing after 6s
CI / Workflow lint (actionlint) (pull_request) Successful in 9s
Third-party parts / As their notes say (pull_request) Successful in 11s
PR description / Description follows the template (pull_request_target) Failing after 3s
to bb847be7c1
Some checks failed
CI / Python source checks (ubuntu-24.04, part 1/2) (pull_request) Has been skipped
CI / Python source checks (ubuntu-24.04, part 2/2) (pull_request) Has been skipped
CI / SPIR-V fixtures (global narrow load/store, direct surface atomics, F2I immediate) (pull_request) Has been skipped
Third-party parts / The same as upstream (pull_request) Has been skipped
CI / Conventional Commit title (pull_request) Successful in 3s
CI / Workflow lint (actionlint) (pull_request) Successful in 4s
Third-party parts / As their notes say (pull_request) Successful in 5s
PR description / Description follows the template (pull_request_target) Failing after 7s
2026-11-13 08:12:58 +00:00
Compare
Author
Member

Updated to bb847be7, rebased on main @ 6b7fa356 (#148).

  • A /code-review (high) of the whole PR found 10 things, all fixed:
    • send() keeps the report when the answer can't be read.
    • A marker cut short still counts.
    • The OS and CPU come from the machine when the log has no line for them.
    • The WebGPU log line now says why it was picked.
    • LONGSHOT_NO_CRASH_WINDOW follows env_on.
    • Device names (microphone, audio output) are kept out of the log lines.
    • The user name is matched case-sensitively (a Steam Deck's user is deck).
    • Linux builder:
      • --launch with a crash waiting goes on to the launcher page.
      • With no crash waiting, the window is no longer destroyed inside __init__.
      • The Sent page's Close goes on as on Qt.
      • The always-send timer is cancelled once the player answers.
    • The window's rows and Show texts are shared in nx2/crash_report.py.
  • The relay's address and #81's address moved out of the code into nx2/addresses.ini.
  • Measured (table above):
    • Startup and play are unchanged.
    • A crash has the builder running in about 0.1 s.
  • run_all: 522 passed, 0 failed.
  • Test requests opened: T-YFML (Windows, not Wine) and T-FTCD (AMD/Intel GPUs). They need the testing wanted label before anyone can claim them.
Updated to bb847be7, rebased on main @ 6b7fa356 (#148). - A `/code-review` (high) of the whole PR found 10 things, all fixed: - `send()` keeps the report when the answer can't be read. - A marker cut short still counts. - The OS and CPU come from the machine when the log has no line for them. - The WebGPU log line now says why it was picked. - `LONGSHOT_NO_CRASH_WINDOW` follows `env_on`. - Device names (microphone, audio output) are kept out of the log lines. - The user name is matched case-sensitively (a Steam Deck's user is `deck`). - Linux builder: - `--launch` with a crash waiting goes on to the launcher page. - With no crash waiting, the window is no longer destroyed inside `__init__`. - The Sent page's Close goes on as on Qt. - The always-send timer is cancelled once the player answers. - The window's rows and Show texts are shared in `nx2/crash_report.py`. - The relay's address and #81's address moved out of the code into `nx2/addresses.ini`. - Measured (table above): - Startup and play are unchanged. - A crash has the builder running in about 0.1 s. - `run_all`: 522 passed, 0 failed. - Test requests opened: T-YFML (Windows, not Wine) and T-FTCD (AMD/Intel GPUs). They need the `testing wanted` label before anyone can claim them.
Author
Member

Rebased on main @ 36a12f6f (#161 removed the builders' self-update: the crash window's lines kept on top of it, in the Linux builder's docstring, Builder() and the launcher page, and the Qt start's docstring). run_all: 520 passed, 1 failed (test_prepare_cache_save, which fails the same on main @ 36a12f6f). The Measurements' main and PR lines added.

Rebased on main @ 36a12f6f (#161 removed the builders' self-update: the crash window's lines kept on top of it, in the Linux builder's docstring, Builder() and the launcher page, and the Qt start's docstring). run_all: 520 passed, 1 failed (test_prepare_cache_save, which fails the same on main @ 36a12f6f). The Measurements' main and PR lines added.
gab9281 force-pushed feat/crash-report-window from bb847be7c1
Some checks failed
CI / Python source checks (ubuntu-24.04, part 1/2) (pull_request) Has been skipped
CI / Python source checks (ubuntu-24.04, part 2/2) (pull_request) Has been skipped
CI / SPIR-V fixtures (global narrow load/store, direct surface atomics, F2I immediate) (pull_request) Has been skipped
Third-party parts / The same as upstream (pull_request) Has been skipped
CI / Conventional Commit title (pull_request) Successful in 3s
CI / Workflow lint (actionlint) (pull_request) Successful in 4s
Third-party parts / As their notes say (pull_request) Successful in 5s
PR description / Description follows the template (pull_request_target) Failing after 7s
to 77609f451d
All checks were successful
CI / Python source checks (ubuntu-24.04, part 1/2) (pull_request) Has been skipped
CI / Python source checks (ubuntu-24.04, part 2/2) (pull_request) Has been skipped
CI / SPIR-V fixtures (global narrow load/store, direct surface atomics, F2I immediate) (pull_request) Has been skipped
Third-party parts / The same as upstream (pull_request) Has been skipped
Website / Website on Cloudflare (pull_request) Has been skipped
PR description / Description follows the template (pull_request_target) Successful in 3s
CI / Conventional Commit title (pull_request) Successful in 5s
CI / Workflow lint (actionlint) (pull_request) Successful in 4s
Third-party parts / As their notes say (pull_request) Successful in 5s
2026-11-13 08:28:14 +00:00
Compare
All checks were successful
CI / Python source checks (ubuntu-24.04, part 1/2) (pull_request) Has been skipped
CI / Python source checks (ubuntu-24.04, part 2/2) (pull_request) Has been skipped
CI / SPIR-V fixtures (global narrow load/store, direct surface atomics, F2I immediate) (pull_request) Has been skipped
Third-party parts / The same as upstream (pull_request) Has been skipped
Website / Website on Cloudflare (pull_request) Has been skipped
PR description / Description follows the template (pull_request_target) Successful in 3s
CI / Conventional Commit title (pull_request) Successful in 5s
CI / Workflow lint (actionlint) (pull_request) Successful in 4s
Third-party parts / As their notes say (pull_request) Successful in 5s
This pull request doesn't have enough approvals yet. 0 of 1 approvals granted.
This branch is out-of-date with the base branch
You are not authorized to merge this pull request.
View command line instructions

Checkout

From your project repository, check out a new branch and test the changes.
git fetch -u 'feat/crash-report-window:gab9281-feat/crash-report-window'
git switch 'gab9281-feat/crash-report-window'
Sign in to join this conversation.
No reviewers
No milestone
No project
No assignees
1 participant
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set

Reference
MagicBeanDev/Longshot!141
No description provided.