feat: a crash window that shows the crash report and sends it only on Send Help #141
No reviewers
Labels
No labels
area/accessibility
area/audio
area/input
area/install
area/menu
area/renderer
area/saves
area/upscaling
good first issue
gpu/amd
gpu/intel
gpu/nvidia
help wanted
kind
bug
kind
chore
kind
docs
kind
feature
kind
performance
kind
question
needs measurements
platform/linux
platform/steam-deck
platform/windows
preview
priority
critical
priority
high
priority
low
status
blocked
status
confirmed
status
duplicate
status
invalid
status
needs-info
status
wontfix
testing wanted
No milestone
No project
No assignees
1 participant
Notifications
Due date
No due date set.
Dependencies
No dependencies set
Reference
MagicBeanDev/Longshot!141
Loading…
Reference in a new issue
No description provided.
Delete branch "gab9281/Longshot:feat/crash-report-window"
Deleting a branch is permanent. Although the deleted branch may continue to exist for a short time before it actually gets removed, it CANNOT be undone in most cases. Continue?
Why
When Longshot crashes, the player gets nothing and the team learns nothing unless someone digs out
longshot_log.txtand posts it. With this PR, a window opens after a crash. It shows exactly what a report holds, andsends it to #81 only when the player presses Send Help. I am sorry sends nothing.
What changed
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) andassets/magicbean-report-sent.png(the Sent page; the Qt builder ships byte-identical copies of both, which its test checks).nx2/crash_report.py, shared by both builders and the tests:pending()finds the crashed run's log throughcrash_pending.txt, including after a rotation.build()makes the report:CRASH:lines without the register and memory rows, and the 150 log lines before them.~, and the user name is redacted wherever it appears as a word (e.g.-home-<user>-in apath written with dashes), in its own case: a Steam Deck's user is
deck, and its report must still say "SteamDeck". Every field stays within the relay's limits. The OS and CPU come from the machine when the log has no line.
libc.so.6+0x…without the library's path, andunknown+0x10for aplace in no module.
send()posts it to the relay. An answer it can't read keeps the report for next time.nx2/addresses.ini, not in the code (one place to edit when a service moves).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()andset_always_send()are the launcher's tick.comment_link()is the Sent page's link.host/hos_crash_window.c:hos_crash_window_init()builds the command once at startup, fromlongshot_version.txt'sbuilder=andbuilder_args=.hos_crash_window_open()runs inreport_crash(host/mkw_glue.c) after the log is flushed. It writescrash_pending.txt, then starts<builder> --crash <folder>.CreateProcessW, detached.vforkandexecvefrom the signal handler, with output to/dev/null.LONGSHOT_NO_CRASH_WINDOWfollows the switches' rule (env_on: 0, false, off, no are off).report: gpu|cpu|os|rendererlines in the startup log, which the report reads:cpu_text()andos_text()ingpu/vk/vk_bug_report.cpp;gpu/vk/vk_main.cppandhost/rx_backend.c.builder/linux/longshot_builder.py --crash <folder>(show_crash,crash_send_help,crash_sorry,show_crash_sent).--playand--launch(then on to the launcher page or Play,from the Sent page's Close too, as on Qt).
builder/py/longshot_builder/crash.pyis the same window in Qt. It doesn't usewinregorwindow.py, so itstest runs on Linux.
longshot_builder_start.py --crash <folder>.window.py.tests/test_crash_report.py: 23 tests on the report.tests/test_crash_window.py: compileshos_crash_window.cwith a stand-in builder.tests/test_crash_window_qt.py: opens the Qt window offscreen.Flags and settings
crash_reports(longshot_options.ini)0: a crash opens no window and writes no markerLONGSHOT_NO_CRASH_WINDOW=1longshot_crash.inialways_send=1--crash <folder>(both builders)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 thelauncher 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-mainandwork/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 as77609f45, rebased after on main @36a12f6f: the website, thecompile-shaders choice, the builders' self-update removal; none of it in the game's start or play measured here)
6b7fa356bb847be7kill -SEGVat 25 s) tobuilder --crashrunning (s), median (runs)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:
RX_CPM=<the CPM cache> python -I -B tests/run_all.py --jobs 12on77609f45(rebased on main @36a12f6f):520 passed, 1 failed, 19 skipped (Windows only). The failure,
tests/test_prepare_cache_save.py(compile_allundeclared in its fixture), fails the same on main @
36a12f6f: it comes with #158, not this PR. Before that rebase, on35ee48e1(main @6b7fa356): 522 passed, 0 failed. The new checks aretest_crash_report.py,test_crash_window.pyandtest_crash_window_qt.py.15 GB, CachyOS (Linux 7.3.3), KDE Wayland.
715cf050: only the bean image and the rebase on a CI-onlychange came after), and again at
bb847be7for the Measurements above. The game was started as the launcher starts it, then sentkill -SEGVduring startup.PySide6 6.8.
752ff889(same code as715cf050). An access violation in the game (a thread started at a bad address) opened the Qt window.?+0x10place came up, which the relay refused before thefix: the window now shows and sends it as
unknown+0x10.Not tested:
bin\.address (Windows), both during startup. So the map and renderer fields show "not known".
source=yet (a step left), so every report is "not a release"for now.
Needs other testers:
the window within a few seconds and the comment's link working (T-YFML).
report: gpuline names the card and driver, expecting both in the window's Graphics cardrow (T-FTCD).
Screenshots
main @
39647e1ahas no crash window: a crash ends the game with nothing on screen. Everything below is this PR. Homefolders are blurred on the launcher shots; nothing else is edited.
Linux (this PR @ 608dd588, a real crash:
kill -SEGVon the running game)Windows (this PR @
752ff889under Wine 11.21, a real access violation in the game)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
hos_crash_window_open()runs inside the crash handler. On Linux that's a signalhandler, so it uses only
open/write/vfork/execveand allocates nothing. If it fails, the crash ends as itdoes on
main, with the marker left for the next launch.crash_reports=0orLONGSHOT_NO_CRASH_WINDOW=1. Reverting the PR is enough otherwise.~,and settings like bindings and the microphone's name are never sent.
Reviewer notes
host/hos_crash_window.c(what runs in the crash handler), thennx2/crash_report.pybuild()(whatleaves the PC).
longshot_version.txt, so nobuilder=line and no window. Releases haveone.
longshot_log.txtonly when it isn't started from a terminal. Started from a terminal, it logsthere, and the window finds no crash to report.
source=line (the release flag);longshot_defaults.ini;recomplauncher.json;releasefield,[not a release]) is already deployed in Bean-Ops.Issues
See #81
Checklist
For everyone
type(scope): description).main.python -I -B tests/run_all.pyrun and passing (any failure that also fails onmainis named above).third_party/untouched (a new folder with aPROVENANCE.mdinstead).If applicable
Assisted-by:/Co-Authored-By:trailers.mainand passing here.tests/that reads changed source updated in this PR, not weakened.hos_crash_window.cagain with llvm-mingw-Werror; therx_backend.cchange is one log line.)🤖 Generated with Claude Code
https://claude.ai/code/session_015KgSKoUqUvce5UXG89NBgi
1f0e9dc5f5edfc1ef3e1edfc1ef3e1468fe236df468fe236df752ff88994752ff88994715cf050dafeat/crash-report-windowto WIP: feat: a crash window that shows the crash report and sends it only on Send HelpUpdated to
715cf050, rebased on main @39647e1a(a CI-only change).assets/magicbean-report-sent.png, Magic Bean's own art, which replaces the earlierbean; the license box is ticked.
own comment on #81.
python -I -B tests/run_all.py: 477 passed, 0 failed, 64 skipped.🤖 Generated with Claude Code
WIP: feat: a crash window that shows the crash report and sends it only on Send Helpto feat: a crash window that shows the crash report and sends it only on Send Help715cf050dabb847be7c1Updated to
bb847be7, rebased on main @6b7fa356(#148)./code-review(high) of the whole PR found 10 things, all fixed:send()keeps the report when the answer can't be read.LONGSHOT_NO_CRASH_WINDOWfollowsenv_on.deck).--launchwith a crash waiting goes on to the launcher page.__init__.nx2/crash_report.py.nx2/addresses.ini.run_all: 522 passed, 0 failed.testing wantedlabel before anyone can claim them.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.bb847be7c177609f451dView command line instructions
Checkout
From your project repository, check out a new branch and test the changes.