feat(reports): the local bug report lists what it holds and what it left out in manifest.json #575

Open
mooki wants to merge 3 commits from mooki/Longshot:feat/problem-report-next-44 into main
Member

Type: feat · Risk: low · Tested on: Linux, RTX 4090 (game-free tests with GCC and Clang, one windowless run); Windows compile only · Needs: Windows (NVIDIA and AMD), and anyone with a game that crashed last time (T-RZPN, T-Y95P)

Why

A local bug report is a folder of loose files, and nothing in it says what is missing: a picture that never came, a log cut in the middle or a copy that failed look like a complete report until someone opens every file (#44). This adds manifest.json next to report.txt: every file with its size, whether it was included, left out or failed and why, and the categories that are never collected. Nothing new is collected and nothing is sent.

What is measured: a game-free test of the report writer fails on main and passes here with GCC and Clang; the Windows-target compile of its fixture passes; one windowless run on Linux (RTX 4090) made a report from the menu and its manifest agrees with the four files it wrote; the whole game-free suite on the final head (below). Not measured: anything on Windows (the fixture was only compiled for it), AMD, Intel, the Steam Deck, a report made in play (the run stood on the title screen of a new profile), a crash, a cut log or a failed copy in the game itself (the test covers them with made-up files), and speed.

What changed

This adds manifest.json next to report.txt in the local bug report: every file with its size, whether it was included, omitted or failed and why, and the categories that are never collected, written from the same list of entries that report.txt prints under "What this folder holds", so the two cannot disagree. The manifest is published last, so a report that cannot be completed leaves none. Nothing new is collected and nothing is sent; a second commit makes a missing log say log file not found.

  • gpu/vk/vk_bug_report.cpp: the existing writer keeps its collection (current and previous log, one picture, path redaction, the menu's current settings, the Forgejo form link) and now also keeps one list of what it did with each file: name, size, included, omitted (missing, or deliberately excluded) or failed, a reason, and whether the file is a candidate for attaching. report.txt prints that list under "What this folder holds" and writes manifest.json (schema 1: schema, report_id, when, files) from the same entries, so the two cannot disagree. Sizes are the bytes actually written, counted while the log is copied (no second read), and each copy's reads, writes and close are checked: a copy that failed is listed as failed and its file is removed, not listed as an attachment. A log shortened by the existing first 1 MiB plus last 9 MiB rule says middle omitted (bounded copy). A log that does not exist says log file not found, which is different from a failed copy.
  • The manifest is published last: written as manifest.json.new and renamed once report.txt is written. If either file cannot be written the existing failed-report message is shown (it names the file) and no completed manifest is left.
  • Deliberately excluded, listed as omitted and shareable: false with a reason beginning excluded;: save/, game-files/, the raw longshot_options.ini and longshot_env.txt, pending/, running/ and local-only/. None of these is scanned, copied or acknowledged. The crash and unclean-end texts in bug-reports/pending, the running markers and the local-only dumps (#75) stay separate and untouched.
  • The report says what it does not do: nothing is sent or opened, path redaction does not guarantee privacy, and register and nearby-memory rows in the logs are not filtered (so every included log says so in its reason). shareable means a candidate for a person to review, never permission to send.
  • gpu/vk/vk_bug_report.h: a comment on the two inventories. docs/development.md (new section "Local bug-report inventory": the schema, the statuses, who may read it) and README.md (the Bug report bullet, and its link to the Longshot issue form) describe the file.
  • tests/test_bug_report.py: the existing assertions stay (form fields, redaction, settings, NUL bytes, long log, picture lifecycle, wiring); added: an inventory() check run on every report the test makes (schema, identity, entries against the real files, sizes, human text equal to the manifest, no staged file left), an empty log (size 0, included), an absent log, a failed log copy, a report and a manifest that cannot be written (nothing completed is left), and the pending, running and local-only files unchanged afterwards. --source-root runs the same test against another source tree (used for the main comparison below).
  • docs/tested/2026-11-14-bug-report-manifest-mooki-run01.md: the run below, as the new one-file format asks.
  • Unchanged: what is collected, redaction, the one picture, the settings and switches text, the form link and its prefill, the menu row and its texts, the renderer interface, host code and everything per frame.

The manifest of the run described below, as written (its report.txt has the same twelve entries, one per line, under "What this folder holds"):

{
  "schema": 1,
  "report_id": "2026-11-14_13-06-14",
  "when": "2026-11-14T13:06:14-0600",
  "files": [
    {"name": "longshot_log.txt", "size": 213803, "status": "included", "reason": "this run so far; home/user paths redacted; diagnostic register and nearby-memory rows are not filtered", "shareable": true},
    {"name": "longshot_log.1.txt", "size": 0, "status": "omitted", "reason": "log file not found", "shareable": false},
    {"name": "picture.png", "size": 2765798, "status": "included", "reason": "next game-source frame, without the menu", "shareable": true},
    {"name": "save/", "size": 0, "status": "omitted", "reason": "excluded; no save content read or copied", "shareable": false},
    {"name": "game-files/", "size": 0, "status": "omitted", "reason": "excluded; no game files or keys collected", "shareable": false},
    {"name": "longshot_options.ini", "size": 0, "status": "omitted", "reason": "excluded; only the existing safe settings summary is collected", "shareable": false},
    {"name": "longshot_env.txt", "size": 0, "status": "omitted", "reason": "excluded; only the existing safe switch summary is collected", "shareable": false},
    {"name": "pending/", "size": 0, "status": "omitted", "reason": "excluded; crash and unclean-end texts remain separate in bug-reports/pending; not scanned or acknowledged", "shareable": false},
    {"name": "running/", "size": 0, "status": "omitted", "reason": "excluded; private running markers are not examined", "shareable": false},
    {"name": "local-only/", "size": 0, "status": "omitted", "reason": "excluded; private dumps and outcome notes are never collected", "shareable": false},
    {"name": "report.txt", "size": 5353, "status": "included", "reason": "issue-form answers and human-readable manifest", "shareable": true},
    {"name": "manifest.json", "size": 1943, "status": "included", "reason": "attachment metadata; published last", "shareable": true}
  ]
}

Reviewer notes:

  • Start with the item list, the two renderers (render_report, render_manifest) and the publication at the end of write() in gpu/vk/vk_bug_report.cpp, then inventory() in the test.
  • The schema and file name come from an earlier, larger local implementation of the same issue (ten commits, 9 files, +1,612/-188), whose first slice is taken here by hand. This change is 6 files, +286/-46 against main (three commits). It is not that work's first commit: that one mixes the inventory with the ZIP, new probes, incident intake and save metadata, so the inventory was taken out alone.
  • The second commit (log file not found) is separate on purpose and can be dropped without touching the first.
  • Overlaps, read on the diffs as retained from the public pull requests (applied to main and to this branch with git apply --check): #218 replaces the log copy's and report's fopen with no-follow helpers in the lines this change rewrites; that hunk applies on main and fails here, so whichever lands second keeps those helpers for the manifest's and report.txt's writes too. This change makes no link-hardening claim. #141 adds a bullet right after the Bug report bullet in README.md (context conflict only; its changes to vk_bug_report.cpp apply cleanly on both). #53 only adds historical docs/tested/ files and does not touch this branch's lines.
  • Not here on purpose: no sender, no launcher hand-off, no acknowledgement. MagicBeanDev/LongshotLauncher#46 and the other report proposals need one agreed path for consent and deduplication first.

Later work, not started here

Sizes are from the earlier implementation, as it was written (lines of runtime code in the writer unless noted), not estimates for a rebased patch. Each slice would carry its own tests and docs.

Order Slice Size in the earlier implementation
2 A ZIP of the included files, an issue-link file and an optional later picture about 55 lines (24 + 6 + 25), plus its tests
3 Bounded operating-system, storage, power and redaction text diagnostics about 314 lines (226 + 23 + 65), plus three follow-up fixes of 6, 51 and 22 lines
4 Renderer, frame-time and state snapshots from the existing counters about 153 lines (96 in the menu, 8 + 3 in the FPS history, 46 in the writer), plus a 16-line fix
5 Bounded intake of crash and unclean-end records with run matching and a notice at the next start about 196 lines (78 + 46 + 56 + 16), plus corrections of 5, 160 and 62 lines
6 Save metadata and an explicit local-only copy of a selected save, if still wanted about 54 lines, plus tests and docs
Separate A stall record with thread stacks already written elsewhere on an older base; a separate producer
Separate A control-bridge command that makes the same report a written proposal only
Separate A last-minute controller recording with its matching save a written proposal only
Separate A one-line player description in the menu a written proposal only
Separate A report for a startup or build failure, with no game running not started; the launcher already has its own copy of such a report

Measurements

Verdict: the new test of the report writer fails on main (the report folder holds no manifest.json) and passes with this PR with GCC and Clang, the Windows-target compile of its fixture passes (compile only), and one windowless Linux run (RTX 4090) made a report from the menu whose manifest agrees with the four files it wrote (all seven checks held). Not a speed change: the manifest is written only when a player makes a Bug report, so there is nothing to time. Windows execution, AMD, Intel, the Steam Deck, a report made in play and a crash, a cut log or a failed copy in the game itself are not measured.

Branch state: on main 7ff5256e000671d0fccf27f77ba41275916b21df; head 14223d6a32440dd6d03b666b543bd260aea9604d; whole game-free suite on this head: 553 passed, 2 failed, 16 skipped (main 7ff5256e000671d0fccf27f77ba41275916b21df: 553 passed, 2 failed, 16 skipped). The 2 failing tests fail on main the same way: tests/test_cpm_discovery.py, tests/test_walk_key.py. The commits are unchanged by rebases apart from the results table.

main: 543846ebb0 (2026-11-14)
this PR: feat/problem-report-next-44-m543846eb @ d05d8d52c
Hardware: Arch Linux, kernel 7.2.15, Core i9-13900K, 94 GB, RTX 4090 with NVIDIA 615.78.08 for the game run (the tests use no GPU); g++ 16.2.1 and clang++ 23.1.3
Scene: the test makes reports from made-up game folders and logs; the game run is the title screen of a new profile, not gameplay
Method: the new test compiles the real writer with a small driver and checks every report folder it writes; the same test file is run against main's source for the comparison. The game run used the Insert menu's own keys (RX_VK_MENU_SCRIPT), windowless, once. No timing is compared.
How to reproduce: python -I -B tests/test_bug_report.py --cxx g++ (and --cxx clang++); for the main column add --source-root with the path of a checkout of main; the game run needs a built game, a new profile and RX_VK_MENU_SCRIPT=55:INS,57:TABR,58:TABR,60:UP,61:UP,62:UP,65:ENTER,80:ESC (the menu opens at 55 s, goes two tabs right to Gameplay, up three rows from the top row to Bug report, and presses Enter at 65 s)

Before: main @ 543846ebb After: this PR @ d05d8d52c
tests/test_bug_report.py (the version of this PR) fails: the report folder holds no manifest.json passes with GCC and Clang
Machine-readable list of the report's files none schema 1, sizes equal the real files, report.txt lists the same entries
Windows-target compile of the fixture and the writer not run 2 translation units, 0 failures, 0 unjudged (compile only)
main's source, this PR's test:   bug report: the folder holds ['longshot_log.1.txt', 'longshot_log.txt', 'picture.png', 'report.txt']
this PR, g++ and clang++:        bug report: ok (report.txt as the issue form, both logs redacted, the picture, the long log, the terminal start, switch values, NUL bytes, the folder's reason, schema-1 manifest sizes/statuses, publication failures, private exclusions)
Windows-target compile:          PASS: 2 captured translation units, 0 failures, 0 unjudged drivers/files; Windows execution NOT TESTED

Which head each result was made at: the focused test runs, the Windows-target compile, the native build and the game run were made at 06e8c8d70 (the first two commits); d05d8d52c adds only the docs/tested/ file, so the compiled source is the same. The whole suite ran at d05d8d52c, where tests/test_bug_report.py and tests/test_tested_configurations.py both pass.

The second commit makes a missing log say log file not found instead of log could not be read or copied. Its two new assertions were run against the first commit's source: the one for the missing log fails there (bug report: a log file that does not exist is not said to be missing) and both pass here.

The game run (native Linux build of the first two commits, version v3.0.0-rc.3-79-g06e8c8d70 (source 9b23b78d), one run, windowless, an empty profile, RX_VK_PRECOMPILE=0):

windowless run: exit 0 after 74.1 s, no fatal, crash, device-lost or kernel lines (RTX 4090)
[hos Presentation Thread] menu: bug report asked for
[hos host] menu: bug report written to bug-reports/2026-11-14_13-06-14: report.txt, manifest.json, longshot_log.txt (209 KB), picture.png

The seven checks the run script made on the folder all held: schema 1 and report_id equal to the folder name; the included entries are exactly the four files in the folder; each included size equals the file's size on disk; report.txt lists every entry with the same status, size and reason; picture.png and longshot_log.txt are included; pending/, running/ and local-only/ are omitted and not shareable; no manifest.json.new is left. The folder's files were 213803 bytes (log), 2765798 (picture), 5353 (report.txt) and 1943 (manifest.json). No kernel or NVRM line, no core dump. The frame counts in the run's summary are not a measurement: the machine was shared and pipelines compiled on demand.

Screenshots

Nothing on screen changes. The Bug report row, its help and its saved message are the same as before.

Flags and settings

None. The existing Gameplay, Bug report row writes the extra file. Nothing is switched on or off and nothing new is collected.

Testing

Tested: the new test both ways (table above), with GCC and Clang, through the shared measuring lock; the compile of the fixture and the writer for the Windows target; a native Linux build of the first two commits and the one windowless game run described above (a new profile at the title screen, report made from the menu, folder and manifest read back and checked, the menu's saved message and the report's own picture looked at); the new docs/tested/ file builds into the assembled table (python -I scripts/tested_configurations.py, exit 0) and tests/test_tested_configurations.py passes. The whole game-free suite on the final head d05d8d52c (Clang for the C++ fixtures, a fresh home folder, idle class, 6 at once, --strict): 554 passed, 1 failed, 16 skipped in 158 s. The one failure, tests/test_walk_key.py (its fixture no longer links: undefined reference to hos_oot_autoload_input), fails the same way on main 543846ebb when run alone; #497 fixes it. The skipped tests are the ones the suite itself reports as Windows-only or missing a local prerequisite. No core dump came from the run.

Built for Windows and Linux at the current head, not run: At 14223d6a32440dd6d03b666b543bd260aea9604d, the Windows x86-64 Vulkan renderer DLL and all 50 selected host translation units were cross-built on Linux with llvm-mingw 20261104 (Clang 23.1.5), using the project's production flags and pinned dependencies (renderer: 35 newly compiled / 170 reused; host: 1 newly compiled / 49 reused; lifted C: 0 newly compiled / 80 reused; all Windows units: 36 newly compiled / 613 reused from matching object-cache entries), the renderer DLL linked and the full game executable linked; nothing was run on Windows or under Wine, and this is neither the project's hosted builder run nor a Windows UTF-8 run-time path test.

The exact same head 14223d6a32440dd6d03b666b543bd260aea9604d also compiled and linked its full native Linux executable and renderer with Clang 23.1.3 through the documented resume path (490 newly compiled units, 1 matching Linux-cache units, source stamp e545bf33), using the verified target-neutral C from lift 5c175a4727d82f85e425e85400dca17fea0750fb rather than carrying the patch onto another commit; neither Linux binary was run.

CPU target (this revision builds the game for the build PC's own CPU, #524; the two builds differ on purpose): the Windows cross-build keeps the builder's pinned -march=x86-64-v3 -ffp-contract=off (488 of its 649 compile commands carry it; the other 161 carry no -march flag; none carries -march=native, -mtune or -DLONGSHOT_NATIVE_CPU), so the Windows binaries are not built for this PC's CPU. The native Linux build used the revision's default -march=native, which clang resolved on this PC (13th Gen Intel(R) Core(TM) i9-13900K) to raptorlake_raptorlake_5fe3e3650f (build log line: build: the game is built for this PC's CPU (raptorlake_raptorlake_5fe3e3650f)), so the Linux binaries are built for that CPU's instruction set and tuning; neither binary was run.

Not tested: native Windows execution of the fixture or of the game; a Windows game build; AMD, Intel and the Steam Deck; a report made in play with a map, a previous log and a long log in the game itself (the test makes them with made-up files); a game that crashed or ended unclean before the report (the pending files are only checked in the test); a full disk or a read-only game folder in the game; a real window and a controller. The run was at the title screen, so longshot_log.1.txt was absent and listed as omitted.

Must be tested:

  • Windows (NVIDIA and AMD): make a Bug report from the menu and compare manifest.json with the files in the folder, expecting the same names and sizes and the excluded categories listed as omitted (test request T-RZPN; by hand).
  • Anyone with a game that crashed last time: make a report after the next start and check that bug-reports/pending is unchanged and pending/ is listed as omitted, expecting no pending text in the folder (test request T-Y95P; by hand).

Risks

What could break: A full or unwritable drive can stop the manifest from being written. The row then shows the existing failed message with the file's name, rather than claiming a complete report. The inventory adds nothing to what is collected, and the logs still carry the register and memory rows they carried before; shareable is a hint for a person reviewing the files, never consent to send them. The writer runs on its own thread when the menu asks for a report, not per frame.

Turning it off: Reverting the commits removes manifest.json and leaves existing report folders alone.

Compatibility:

  • Saves: untouched; save/ is excluded and listed as omitted, and no save content is read or copied. Existing report folders are left alone.
  • longshot_options.ini: no new key; nothing is switched on or off, and the raw options file stays excluded (only the existing safe settings summary is collected).
  • What a player notices: a report folder now holds manifest.json too, and report.txt lists the same entries under "What this folder holds".
  • Shader and pipeline caches: the text says nothing; the diff adds no shader file and does not touch the caches' code.
  • The vk ABI: unchanged; the text says the renderer interface is unchanged, and the diff does not touch gpu/vk/vk_api.h.
  • The builder's tools: the text says nothing; the diff touches none.

Issues

See #44. It stays open: the slices above, the launcher and the sending policy are still to do.

Checklist

Everyone

  • One topic.
  • The title is a Conventional Commit (type(scope): description) of the status line's type.
  • Why gives the reason plainly and links the issues that fit (the tracker searched).
  • Measurements has a verdict, or one line saying why there is nothing to measure. Not a speed change: the manifest is written only when a player makes a Bug report, never during play, so there is nothing to time.
  • Testing names what was tested, what wasn't, and what must still be tested, where and how. The two requests are open (T-RZPN, T-Y95P).
  • Rebased on current main.
  • python -I -B tests/run_all.py passes (any failure that also fails on main is named).
  • 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.

When it applies

  • AI assistance recorded with Assisted-by: / Co-Authored-By: trailers.
  • A file in docs/tested/ for each new measured run (format in docs/tested-configurations.md; no appended row or assembled view).
  • 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. Built and linked for both at 14223d6a32440dd6d03b666b543bd260aea9604d (under Testing); nothing was run on Windows at this head, so UTF-8 path behavior at run time is not claimed.
  • Docs updated.

New on this forge; not opened on GitHub.

**Type:** feat · **Risk:** low · **Tested on:** Linux, RTX 4090 (game-free tests with GCC and Clang, one windowless run); Windows compile only · **Needs:** Windows (NVIDIA and AMD), and anyone with a game that crashed last time (T-RZPN, T-Y95P) ## Why A local bug report is a folder of loose files, and nothing in it says what is missing: a picture that never came, a log cut in the middle or a copy that failed look like a complete report until someone opens every file (https://git.magicbean.dev/MagicBeanDev/Longshot/issues/44). This adds `manifest.json` next to `report.txt`: every file with its size, whether it was included, left out or failed and why, and the categories that are never collected. Nothing new is collected and nothing is sent. **What is measured:** a game-free test of the report writer fails on main and passes here with GCC and Clang; the Windows-target compile of its fixture passes; one windowless run on Linux (RTX 4090) made a report from the menu and its manifest agrees with the four files it wrote; the whole game-free suite on the final head (below). **Not measured:** anything on Windows (the fixture was only compiled for it), AMD, Intel, the Steam Deck, a report made in play (the run stood on the title screen of a new profile), a crash, a cut log or a failed copy in the game itself (the test covers them with made-up files), and speed. ## What changed This adds `manifest.json` next to `report.txt` in the local bug report: every file with its size, whether it was included, omitted or failed and why, and the categories that are never collected, written from the same list of entries that `report.txt` prints under "What this folder holds", so the two cannot disagree. The manifest is published last, so a report that cannot be completed leaves none. Nothing new is collected and nothing is sent; a second commit makes a missing log say `log file not found`. - `gpu/vk/vk_bug_report.cpp`: the existing writer keeps its collection (current and previous log, one picture, path redaction, the menu's current settings, the Forgejo form link) and now also keeps one list of what it did with each file: name, size, `included`, `omitted` (missing, or deliberately excluded) or `failed`, a reason, and whether the file is a candidate for attaching. `report.txt` prints that list under "What this folder holds" and writes `manifest.json` (schema 1: `schema`, `report_id`, `when`, `files`) from the same entries, so the two cannot disagree. Sizes are the bytes actually written, counted while the log is copied (no second read), and each copy's reads, writes and close are checked: a copy that failed is listed as `failed` and its file is removed, not listed as an attachment. A log shortened by the existing first 1 MiB plus last 9 MiB rule says `middle omitted (bounded copy)`. A log that does not exist says `log file not found`, which is different from a failed copy. - The manifest is published last: written as `manifest.json.new` and renamed once `report.txt` is written. If either file cannot be written the existing failed-report message is shown (it names the file) and no completed manifest is left. - Deliberately excluded, listed as `omitted` and `shareable: false` with a reason beginning `excluded;`: `save/`, `game-files/`, the raw `longshot_options.ini` and `longshot_env.txt`, `pending/`, `running/` and `local-only/`. None of these is scanned, copied or acknowledged. The crash and unclean-end texts in `bug-reports/pending`, the running markers and the local-only dumps (https://git.magicbean.dev/MagicBeanDev/Longshot/pulls/75) stay separate and untouched. - The report says what it does not do: nothing is sent or opened, path redaction does not guarantee privacy, and register and nearby-memory rows in the logs are not filtered (so every included log says so in its reason). `shareable` means a candidate for a person to review, never permission to send. - `gpu/vk/vk_bug_report.h`: a comment on the two inventories. `docs/development.md` (new section "Local bug-report inventory": the schema, the statuses, who may read it) and `README.md` (the Bug report bullet, and its link to the Longshot issue form) describe the file. - `tests/test_bug_report.py`: the existing assertions stay (form fields, redaction, settings, NUL bytes, long log, picture lifecycle, wiring); added: an `inventory()` check run on every report the test makes (schema, identity, entries against the real files, sizes, human text equal to the manifest, no staged file left), an empty log (size 0, included), an absent log, a failed log copy, a report and a manifest that cannot be written (nothing completed is left), and the pending, running and local-only files unchanged afterwards. `--source-root` runs the same test against another source tree (used for the main comparison below). - `docs/tested/2026-11-14-bug-report-manifest-mooki-run01.md`: the run below, as the new one-file format asks. - Unchanged: what is collected, redaction, the one picture, the settings and switches text, the form link and its prefill, the menu row and its texts, the renderer interface, host code and everything per frame. The manifest of the run described below, as written (its `report.txt` has the same twelve entries, one per line, under "What this folder holds"): ```json { "schema": 1, "report_id": "2026-11-14_13-06-14", "when": "2026-11-14T13:06:14-0600", "files": [ {"name": "longshot_log.txt", "size": 213803, "status": "included", "reason": "this run so far; home/user paths redacted; diagnostic register and nearby-memory rows are not filtered", "shareable": true}, {"name": "longshot_log.1.txt", "size": 0, "status": "omitted", "reason": "log file not found", "shareable": false}, {"name": "picture.png", "size": 2765798, "status": "included", "reason": "next game-source frame, without the menu", "shareable": true}, {"name": "save/", "size": 0, "status": "omitted", "reason": "excluded; no save content read or copied", "shareable": false}, {"name": "game-files/", "size": 0, "status": "omitted", "reason": "excluded; no game files or keys collected", "shareable": false}, {"name": "longshot_options.ini", "size": 0, "status": "omitted", "reason": "excluded; only the existing safe settings summary is collected", "shareable": false}, {"name": "longshot_env.txt", "size": 0, "status": "omitted", "reason": "excluded; only the existing safe switch summary is collected", "shareable": false}, {"name": "pending/", "size": 0, "status": "omitted", "reason": "excluded; crash and unclean-end texts remain separate in bug-reports/pending; not scanned or acknowledged", "shareable": false}, {"name": "running/", "size": 0, "status": "omitted", "reason": "excluded; private running markers are not examined", "shareable": false}, {"name": "local-only/", "size": 0, "status": "omitted", "reason": "excluded; private dumps and outcome notes are never collected", "shareable": false}, {"name": "report.txt", "size": 5353, "status": "included", "reason": "issue-form answers and human-readable manifest", "shareable": true}, {"name": "manifest.json", "size": 1943, "status": "included", "reason": "attachment metadata; published last", "shareable": true} ] } ``` **Reviewer notes:** - Start with the item list, the two renderers (`render_report`, `render_manifest`) and the publication at the end of `write()` in `gpu/vk/vk_bug_report.cpp`, then `inventory()` in the test. - The schema and file name come from an earlier, larger local implementation of the same issue (ten commits, 9 files, +1,612/-188), whose first slice is taken here by hand. This change is 6 files, +286/-46 against main (three commits). It is not that work's first commit: that one mixes the inventory with the ZIP, new probes, incident intake and save metadata, so the inventory was taken out alone. - The second commit (`log file not found`) is separate on purpose and can be dropped without touching the first. - Overlaps, read on the diffs as retained from the public pull requests (applied to main and to this branch with `git apply --check`): https://git.magicbean.dev/MagicBeanDev/Longshot/pulls/218 replaces the log copy's and report's `fopen` with no-follow helpers in the lines this change rewrites; that hunk applies on main and fails here, so whichever lands second keeps those helpers for the manifest's and `report.txt`'s writes too. This change makes no link-hardening claim. https://git.magicbean.dev/MagicBeanDev/Longshot/pulls/141 adds a bullet right after the Bug report bullet in `README.md` (context conflict only; its changes to `vk_bug_report.cpp` apply cleanly on both). https://git.magicbean.dev/MagicBeanDev/Longshot/pulls/53 only adds historical `docs/tested/` files and does not touch this branch's lines. - Not here on purpose: no sender, no launcher hand-off, no acknowledgement. https://git.magicbean.dev/MagicBeanDev/LongshotLauncher/pulls/46 and the other report proposals need one agreed path for consent and deduplication first. ### Later work, not started here Sizes are from the earlier implementation, as it was written (lines of runtime code in the writer unless noted), not estimates for a rebased patch. Each slice would carry its own tests and docs. | Order | Slice | Size in the earlier implementation | |---|---|---| | 2 | A ZIP of the included files, an issue-link file and an optional later picture | about 55 lines (24 + 6 + 25), plus its tests | | 3 | Bounded operating-system, storage, power and redaction text diagnostics | about 314 lines (226 + 23 + 65), plus three follow-up fixes of 6, 51 and 22 lines | | 4 | Renderer, frame-time and state snapshots from the existing counters | about 153 lines (96 in the menu, 8 + 3 in the FPS history, 46 in the writer), plus a 16-line fix | | 5 | Bounded intake of crash and unclean-end records with run matching and a notice at the next start | about 196 lines (78 + 46 + 56 + 16), plus corrections of 5, 160 and 62 lines | | 6 | Save metadata and an explicit local-only copy of a selected save, if still wanted | about 54 lines, plus tests and docs | | Separate | A stall record with thread stacks | already written elsewhere on an older base; a separate producer | | Separate | A control-bridge command that makes the same report | a written proposal only | | Separate | A last-minute controller recording with its matching save | a written proposal only | | Separate | A one-line player description in the menu | a written proposal only | | Separate | A report for a startup or build failure, with no game running | not started; the launcher already has its own copy of such a report | ## Measurements **Verdict:** the new test of the report writer fails on main (the report folder holds no `manifest.json`) and passes with this PR with GCC and Clang, the Windows-target compile of its fixture passes (compile only), and one windowless Linux run (RTX 4090) made a report from the menu whose manifest agrees with the four files it wrote (all seven checks held). Not a speed change: the manifest is written only when a player makes a Bug report, so there is nothing to time. Windows execution, AMD, Intel, the Steam Deck, a report made in play and a crash, a cut log or a failed copy in the game itself are not measured. <!-- branch-state --> Branch state: on main `7ff5256e000671d0fccf27f77ba41275916b21df`; head `14223d6a32440dd6d03b666b543bd260aea9604d`; whole game-free suite on this head: `553 passed, 2 failed, 16 skipped` (main `7ff5256e000671d0fccf27f77ba41275916b21df`: `553 passed, 2 failed, 16 skipped`). The 2 failing tests fail on main the same way: `tests/test_cpm_discovery.py`, `tests/test_walk_key.py`. The commits are unchanged by rebases apart from the results table. <!-- /branch-state --> main: 543846ebb08ded4ce75d364403bc4dcf24e83e85 (2026-11-14) this PR: feat/problem-report-next-44-m543846eb @ d05d8d52c Hardware: Arch Linux, kernel 7.2.15, Core i9-13900K, 94 GB, RTX 4090 with NVIDIA 615.78.08 for the game run (the tests use no GPU); g++ 16.2.1 and clang++ 23.1.3 Scene: the test makes reports from made-up game folders and logs; the game run is the title screen of a new profile, not gameplay Method: the new test compiles the real writer with a small driver and checks every report folder it writes; the same test file is run against main's source for the comparison. The game run used the Insert menu's own keys (`RX_VK_MENU_SCRIPT`), windowless, once. No timing is compared. How to reproduce: `python -I -B tests/test_bug_report.py --cxx g++` (and `--cxx clang++`); for the main column add `--source-root` with the path of a checkout of main; the game run needs a built game, a new profile and `RX_VK_MENU_SCRIPT=55:INS,57:TABR,58:TABR,60:UP,61:UP,62:UP,65:ENTER,80:ESC` (the menu opens at 55 s, goes two tabs right to Gameplay, up three rows from the top row to Bug report, and presses Enter at 65 s) | | Before: main @ 543846ebb | After: this PR @ d05d8d52c | |---|---|---| | `tests/test_bug_report.py` (the version of this PR) | fails: the report folder holds no `manifest.json` | passes with GCC and Clang | | Machine-readable list of the report's files | none | schema 1, sizes equal the real files, `report.txt` lists the same entries | | Windows-target compile of the fixture and the writer | not run | 2 translation units, 0 failures, 0 unjudged (compile only) | ``` main's source, this PR's test: bug report: the folder holds ['longshot_log.1.txt', 'longshot_log.txt', 'picture.png', 'report.txt'] this PR, g++ and clang++: bug report: ok (report.txt as the issue form, both logs redacted, the picture, the long log, the terminal start, switch values, NUL bytes, the folder's reason, schema-1 manifest sizes/statuses, publication failures, private exclusions) Windows-target compile: PASS: 2 captured translation units, 0 failures, 0 unjudged drivers/files; Windows execution NOT TESTED ``` Which head each result was made at: the focused test runs, the Windows-target compile, the native build and the game run were made at `06e8c8d70` (the first two commits); `d05d8d52c` adds only the `docs/tested/` file, so the compiled source is the same. The whole suite ran at `d05d8d52c`, where `tests/test_bug_report.py` and `tests/test_tested_configurations.py` both pass. The second commit makes a missing log say `log file not found` instead of `log could not be read or copied`. Its two new assertions were run against the first commit's source: the one for the missing log fails there (`bug report: a log file that does not exist is not said to be missing`) and both pass here. The game run (native Linux build of the first two commits, version `v3.0.0-rc.3-79-g06e8c8d70 (source 9b23b78d)`, one run, windowless, an empty profile, `RX_VK_PRECOMPILE=0`): ``` windowless run: exit 0 after 74.1 s, no fatal, crash, device-lost or kernel lines (RTX 4090) [hos Presentation Thread] menu: bug report asked for [hos host] menu: bug report written to bug-reports/2026-11-14_13-06-14: report.txt, manifest.json, longshot_log.txt (209 KB), picture.png ``` The seven checks the run script made on the folder all held: schema 1 and `report_id` equal to the folder name; the included entries are exactly the four files in the folder; each included size equals the file's size on disk; `report.txt` lists every entry with the same status, size and reason; `picture.png` and `longshot_log.txt` are included; `pending/`, `running/` and `local-only/` are omitted and not shareable; no `manifest.json.new` is left. The folder's files were 213803 bytes (log), 2765798 (picture), 5353 (`report.txt`) and 1943 (`manifest.json`). No kernel or NVRM line, no core dump. The frame counts in the run's summary are not a measurement: the machine was shared and pipelines compiled on demand. ### Screenshots Nothing on screen changes. The Bug report row, its help and its saved message are the same as before. ### Flags and settings None. The existing Gameplay, Bug report row writes the extra file. Nothing is switched on or off and nothing new is collected. ## Testing **Tested:** the new test both ways (table above), with GCC and Clang, through the shared measuring lock; the compile of the fixture and the writer for the Windows target; a native Linux build of the first two commits and the one windowless game run described above (a new profile at the title screen, report made from the menu, folder and manifest read back and checked, the menu's saved message and the report's own picture looked at); the new `docs/tested/` file builds into the assembled table (`python -I scripts/tested_configurations.py`, exit 0) and `tests/test_tested_configurations.py` passes. The whole game-free suite on the final head `d05d8d52c` (Clang for the C++ fixtures, a fresh home folder, idle class, 6 at once, `--strict`): `554 passed, 1 failed, 16 skipped in 158 s`. The one failure, `tests/test_walk_key.py` (its fixture no longer links: `undefined reference to hos_oot_autoload_input`), fails the same way on main `543846ebb` when run alone; https://git.magicbean.dev/MagicBeanDev/Longshot/pulls/497 fixes it. The skipped tests are the ones the suite itself reports as Windows-only or missing a local prerequisite. No core dump came from the run. **Built for Windows and Linux at the current head, not run:** At `14223d6a32440dd6d03b666b543bd260aea9604d`, the Windows x86-64 Vulkan renderer DLL and all 50 selected host translation units were cross-built on Linux with llvm-mingw 20261104 (Clang 23.1.5), using the project's production flags and pinned dependencies (renderer: 35 newly compiled / 170 reused; host: 1 newly compiled / 49 reused; lifted C: 0 newly compiled / 80 reused; all Windows units: 36 newly compiled / 613 reused from matching object-cache entries), the renderer DLL linked and the full game executable linked; nothing was run on Windows or under Wine, and this is neither the project's hosted builder run nor a Windows UTF-8 run-time path test. The exact same head `14223d6a32440dd6d03b666b543bd260aea9604d` also compiled and linked its full native Linux executable and renderer with Clang 23.1.3 through the documented resume path (490 newly compiled units, 1 matching Linux-cache units, source stamp `e545bf33`), using the verified target-neutral C from lift `5c175a4727d82f85e425e85400dca17fea0750fb` rather than carrying the patch onto another commit; neither Linux binary was run. CPU target (this revision builds the game for the build PC's own CPU, #524; the two builds differ on purpose): the Windows cross-build keeps the builder's pinned `-march=x86-64-v3 -ffp-contract=off` (488 of its 649 compile commands carry it; the other 161 carry no `-march` flag; none carries `-march=native`, `-mtune` or `-DLONGSHOT_NATIVE_CPU`), so the Windows binaries are not built for this PC's CPU. The native Linux build used the revision's default `-march=native`, which clang resolved on this PC (13th Gen Intel(R) Core(TM) i9-13900K) to `raptorlake_raptorlake_5fe3e3650f` (build log line: `build: the game is built for this PC's CPU (raptorlake_raptorlake_5fe3e3650f)`), so the Linux binaries are built for that CPU's instruction set and tuning; neither binary was run. **Not tested:** native Windows execution of the fixture or of the game; a Windows game build; AMD, Intel and the Steam Deck; a report made in play with a map, a previous log and a long log in the game itself (the test makes them with made-up files); a game that crashed or ended unclean before the report (the pending files are only checked in the test); a full disk or a read-only game folder in the game; a real window and a controller. The run was at the title screen, so `longshot_log.1.txt` was absent and listed as `omitted`. **Must be tested:** - Windows (NVIDIA and AMD): make a Bug report from the menu and compare `manifest.json` with the files in the folder, expecting the same names and sizes and the excluded categories listed as `omitted` (test request T-RZPN; by hand). - Anyone with a game that crashed last time: make a report after the next start and check that `bug-reports/pending` is unchanged and `pending/` is listed as `omitted`, expecting no pending text in the folder (test request T-Y95P; by hand). ## Risks **What could break:** A full or unwritable drive can stop the manifest from being written. The row then shows the existing failed message with the file's name, rather than claiming a complete report. The inventory adds nothing to what is collected, and the logs still carry the register and memory rows they carried before; `shareable` is a hint for a person reviewing the files, never consent to send them. The writer runs on its own thread when the menu asks for a report, not per frame. **Turning it off:** Reverting the commits removes `manifest.json` and leaves existing report folders alone. **Compatibility:** - Saves: untouched; `save/` is excluded and listed as `omitted`, and no save content is read or copied. Existing report folders are left alone. - `longshot_options.ini`: no new key; nothing is switched on or off, and the raw options file stays excluded (only the existing safe settings summary is collected). - What a player notices: a report folder now holds `manifest.json` too, and `report.txt` lists the same entries under "What this folder holds". - Shader and pipeline caches: the text says nothing; the diff adds no shader file and does not touch the caches' code. - The vk ABI: unchanged; the text says the renderer interface is unchanged, and the diff does not touch `gpu/vk/vk_api.h`. - The builder's tools: the text says nothing; the diff touches none. ## Issues See https://git.magicbean.dev/MagicBeanDev/Longshot/issues/44. It stays open: the slices above, the launcher and the sending policy are still to do. ## Checklist ### Everyone - [x] One topic. - [x] The title is a Conventional Commit (`type(scope): description`) of the status line's type. - [x] Why gives the reason plainly and links the issues that fit (the tracker searched). - [x] Measurements has a verdict, or one line saying why there is nothing to measure. Not a speed change: the manifest is written only when a player makes a Bug report, never during play, so there is nothing to time. - [x] Testing names what was tested, what wasn't, and what must still be tested, where and how. The two requests are open (T-RZPN, T-Y95P). - [x] Rebased on current `main`. - [x] `python -I -B tests/run_all.py` passes (any failure that also fails on `main` is named). - [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. ### When it applies - [x] AI assistance recorded with `Assisted-by:` / `Co-Authored-By:` trailers. - [x] A file in `docs/tested/` for each new measured run (format in `docs/tested-configurations.md`; no appended row or assembled view). - [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. Built and linked for both at `14223d6a32440dd6d03b666b543bd260aea9604d` (under Testing); nothing was run on Windows at this head, so UTF-8 path behavior at run time is not claimed. - [x] Docs updated. --- New on this forge; not opened on GitHub.
Extract the manifest.json schema, shared human inventory and last-publication pattern from the parked richer-report work at 675284de11229a0c9d119d0891c935a3b28d9b9e (original series beginning 07bec78fa0c113195ae9a49042ba1307ff9d36c8). Keep current main log locations, PC-dependent settings and one-picture collection. No ZIP, new diagnostic probes, pending-record intake, save scan or sender is carried.

Count actual copied bytes in the existing pass and reject incomplete copies and required-file publication failures. Pending crash/unclean records, private markers and dumps remain separate. Refs #44.

Assisted-by: GPT-6 Astra
Co-Authored-By: GPT-6 Astra <[email protected]>
The manifest and the human inventory gave one reason, "log could not be read or copied", for a log that simply does not exist (the first report after a fresh start has no earlier log) and for a copy that failed. The status already told them apart (omitted against failed); the reason now does too. Refs #44.

Assisted-by: Claude Sonnet 5.5
Co-Authored-By: Claude Sonnet 5.5 <[email protected]>
docs(tested): add the run that wrote a bug report with its manifest
Some checks are pending
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
Website / Website on Cloudflare (pull_request_target) Has been skipped
beanstalk/approval awaiting maintainer approval
CI / Conventional Commit title (pull_request) Successful in 4s
CI / Workflow lint (actionlint) (pull_request) Successful in 8s
Third-party parts / As their notes say (pull_request) Successful in 12s
PR description / Description follows the template (pull_request_target) Successful in 6s
d05d8d52cb
One windowless Linux run on an RTX 4090: the Insert menu's Bug report wrote report.txt, manifest.json, the log and the picture, and the manifest listed them with their real sizes. Refs #44.

Assisted-by: Claude Sonnet 5.5
Co-Authored-By: Claude Sonnet 5.5 <[email protected]>
Author
Member

Carried onto current main 7ff5256e0 (no conflict; main's new commits do not touch the bug report files). Head 14223d6a3; whole game-free suite on it: 553 passed, 2 failed, 16 skipped. The build for both systems follows.

Carried onto current main `7ff5256e0` (no conflict; main's new commits do not touch the bug report files). Head `14223d6a3`; whole game-free suite on it: 553 passed, 2 failed, 16 skipped. The build for both systems follows.
mooki force-pushed feat/problem-report-next-44 from d05d8d52cb
Some checks are pending
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
Website / Website on Cloudflare (pull_request_target) Has been skipped
beanstalk/approval awaiting maintainer approval
CI / Conventional Commit title (pull_request) Successful in 4s
CI / Workflow lint (actionlint) (pull_request) Successful in 8s
Third-party parts / As their notes say (pull_request) Successful in 12s
PR description / Description follows the template (pull_request_target) Successful in 6s
to 14223d6a32
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
CI / Conventional Commit title (pull_request) Successful in 4s
CI / Workflow lint (actionlint) (pull_request) Successful in 8s
Third-party parts / As their notes say (pull_request) Successful in 9s
PR description / Description follows the template (pull_request_target) Successful in 9s
beanstalk/approval Test farm not requested
2026-11-14 20:18:21 +00:00
Compare
mooki changed title from WIP: feat(reports): the local bug report lists what it holds and what it left out in manifest.json to feat(reports): the local bug report lists what it holds and what it left out in manifest.json 2026-11-14 21:29:42 +00:00
Author
Member

Built at the current head 14223d6a32440dd6d03b666b543bd260aea9604d for Windows (llvm-mingw cross-build) and Linux (native); both linked without errors, nothing was run. The build box is ticked for this head and the details are under Testing. Every box is done, so this is ready for review.

Built at the current head `14223d6a32440dd6d03b666b543bd260aea9604d` for Windows (llvm-mingw cross-build) and Linux (native); both linked without errors, nothing was run. The build box is ticked for this head and the details are under Testing. Every box is done, so this is ready for review.
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
CI / Conventional Commit title (pull_request) Successful in 4s
CI / Workflow lint (actionlint) (pull_request) Successful in 8s
Third-party parts / As their notes say (pull_request) Successful in 9s
PR description / Description follows the template (pull_request_target) Successful in 9s
beanstalk/approval Test farm not requested
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/problem-report-next-44:mooki-feat/problem-report-next-44'
git switch 'mooki-feat/problem-report-next-44'
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!575
No description provided.