WIP: feat(launcher): Send report, to the website's inbox #42

Draft
TrashPanda wants to merge 2 commits from TrashPanda/LongshotLauncher:feat/problem-reports into main
First-time contributor

Why

A crash or a stopped build should reach the developers without the player finding a log and filling in an issue. This adds Send report: the report, the player's consent, and sending it to the website's inbox.

Depends on #48 (the problems in plain words and the crash found at the next start), split out of this PR. This branch is #48's commit plus one commit for the reporting; review that commit (ff7228dc) until #48 merges.

What changed

  • (#48: Core/Problems.cs, CrashCheck and the problem page.)
  • Core: Core/ProblemReport.cs writes the report under the issue form's headings, as the game's Bug report does, with the log's end redacted by the game's own rule (home folder and user name out). The crash signature from #48 groups the reports.
  • Core: Core/ReportSender.cs POSTs one https report to the website's inbox, https://longshot.magicbean.dev/report (Longshot #251), which files it as an issue on Longshot, one issue per problem. If a send fails, Send stays available to try again, with Copy report for the issue form. LONGSHOT_REPORT_URL points it at another inbox (a website preview answers a dry run). Format and behaviour: docs/launcher-reports.md.
  • App: #48's problem page gains the report: consent asked once (Always send, Just this once, Never send), "What gets sent", Send and Copy report. The build's problem screen gets Send report, and Settings has Problem reports.
  • Tests: tests/launcher_core/ProblemChecks.cs adds the redaction, the report, the settings and the inbox rules.

Ported from Hookshot's feat/launcher-problem-reports, where it was written against the launcher in Hookshot's tree. Names, log files (longshot_log.txt) and the issue form are Longshot's.

Testing

Tested: on Linux (CachyOS, .NET 10.0.115), at ff7228dc (rebased on current main):

  • python -I tests/test_launcher_core.py --strict --longshot <Longshot main>: 702 checks pass.
  • dotnet build LongshotLauncher.slnx --configuration Release -p:RestoreLockedMode=true (CI's command): 0 errors, and 1 warning that main has too.

Not tested: the report and problem pages in the running launcher, since this port has not been run yet; Windows; a real send (the inbox has no token until #251 is merged and set up; #251 has its own end-to-end run against git.magicbean.dev).

Needs other testers: a Windows run with a crashed build's log in the build folder, expecting the problem page with Send report at the next start, once.

Screenshots

To come: the problem page with the report, and the problem screen, from a run of this branch.

Reviewer notes

The inbox is Longshot #251. Merge and set it up before a release carries this; until then a send fails as "could not be sent" and Copy report still works.

## Why A crash or a stopped build should reach the developers without the player finding a log and filling in an issue. This adds **Send report**: the report, the player's consent, and sending it to the website's inbox. **Depends on #48** (the problems in plain words and the crash found at the next start), split out of this PR. This branch is #48's commit plus one commit for the reporting; review that commit (ff7228dc) until #48 merges. ## What changed - (#48: `Core/Problems.cs`, `CrashCheck` and the problem page.) - Core: `Core/ProblemReport.cs` writes the report under the issue form's headings, as the game's Bug report does, with the log's end redacted by the game's own rule (home folder and user name out). The crash signature from #48 groups the reports. - Core: `Core/ReportSender.cs` POSTs one https report to the website's inbox, `https://longshot.magicbean.dev/report` (Longshot [#251](https://git.magicbean.dev/MagicBeanDev/Longshot/pulls/251)), which files it as an issue on Longshot, one issue per problem. If a send fails, Send stays available to try again, with Copy report for the issue form. `LONGSHOT_REPORT_URL` points it at another inbox (a website preview answers a dry run). Format and behaviour: `docs/launcher-reports.md`. - App: #48's problem page gains the report: consent asked once (Always send, Just this once, Never send), "What gets sent", Send and Copy report. The build's problem screen gets **Send report**, and Settings has **Problem reports**. - Tests: `tests/launcher_core/ProblemChecks.cs` adds the redaction, the report, the settings and the inbox rules. Ported from Hookshot's `feat/launcher-problem-reports`, where it was written against the launcher in Hookshot's tree. Names, log files (`longshot_log.txt`) and the issue form are Longshot's. ## Testing **Tested:** on Linux (CachyOS, .NET 10.0.115), at ff7228dc (rebased on current main): - `python -I tests/test_launcher_core.py --strict --longshot <Longshot main>`: 702 checks pass. - `dotnet build LongshotLauncher.slnx --configuration Release -p:RestoreLockedMode=true` (CI's command): 0 errors, and 1 warning that `main` has too. **Not tested:** the report and problem pages in the running launcher, since this port has not been run yet; Windows; a real send (the inbox has no token until #251 is merged and set up; #251 has its own end-to-end run against git.magicbean.dev). **Needs other testers:** a Windows run with a crashed build's log in the build folder, expecting the problem page with Send report at the next start, once. ## Screenshots To come: the problem page with the report, and the problem screen, from a run of this branch. ## Reviewer notes The inbox is Longshot [#251](https://git.magicbean.dev/MagicBeanDev/Longshot/pulls/251). Merge and set it up before a release carries this; until then a send fails as "could not be sent" and Copy report still works.
feat(launcher): problems in plain words, crashes found at the next start, and Send report
Some checks failed
CI / Conventional Commit title (pull_request) Has been cancelled
CI / Compile and test (pull_request) Has been cancelled
037be73783
A build that stops shows make_game.py's message as it is, and a crash leaves only a log a player has to
find and attach to an issue. Now:

- Core/Problems.cs: make_game.py's and the game's own messages mapped to a plain headline,
  what to do and a fix (antivirus removed the tools, another game version, an incomplete dump, a full
  drive, the build out of memory, a lost GPU, no mesh shaders); a crash's signature (exception code and
  module+offset, no folder) for grouping. A message it doesn't know stays "The build stopped".
- ProblemReport.cs: the report under the issue form's headings, as the game's Bug report writes them,
  the log's end with the home folder and user name taken out by the game's own rule; CrashCheck finds a
  crash in a build's last run (or the run before) at the launcher's next start, once per log.
- ReportSender.cs: one https POST to a report inbox (docs/launcher-reports.md); none is set up yet, so
  Send copies the report and opens the issue form. LONGSHOT_REPORT_URL for trying an inbox.
- The report page: what happened, the fix (the driver page for the card's maker), consent asked once
  (Always send, Just this once, Never send) with "What gets sent"; the build's problem screen uses the
  plain words and has Send report; the settings have Problem reports.

tests/launcher_core/ProblemChecks.cs covers the mapping, the redaction (the game's cases), the crash
found once, the report, the settings and the inbox rules. Built with warnings as errors; 480 checks
pass. The crash page checked on Linux with a crashed build's log.

Ported from Hookshot's feat/launcher-problem-reports (launcher/ there): names, the log files and the issue
form are Longshot's, and the issue form is on git.magicbean.dev.

Assisted-by: Claude Opus 5.5
HumanBean left a comment

A code-only review: I read the diff against main and the Longshot sources it matches on. I didn't build it or run the tests.

What's good

  • Nothing goes out today: DefaultInbox is null, the inbox has to be https, and the test proves an http inbox is refused before anything is sent.
  • The report is plain text the player can open with "What gets sent", and a choice in the settings that isn't one of the three is treated as no choice.
  • Redact follows the game's own rule (vk_bug_report.cpp). Reading it, Z:\home\<name>\… from a Proton log on a native Linux launcher loses the name through the user-name pass, and non-ASCII names count as name characters.
  • No config file, token, save or settings file goes into a report. The build report carries only the launcher's own build settings.
  • A message that isn't recognised stays "The build stopped" rather than getting a wrong fix. That's the right default.

Must change

  1. The log goes out with guest memory in it. report_crash (host/mkw_glue.c) logs the 31 registers and 9 rows of the memory that x0, x1 and x19 point to (CRASH: [x0+0x000] …). That is the game's memory, which counts as made from game files, and Make sends the whole 192 KB tail as it is. With a chosen microphone, the audio in: lines also carry the device's name. Filter the lines as nx2/crash_report.py in MagicBeanDev/Longshot#141 does: no register or memory rows, no device names. Add a test with those lines in the fixture.

  2. "No mesh shaders" is a warning, not a crash. vk_main.cpp logs vk: this GPU has no mesh shaders: … and the game carries on ("Said once, on its own thread, and the game goes on"). Each run writes a new log, so a player on such a card is shown "Your graphics card can't draw this game" after every session, even though nothing crashed. Report it only together with a real end (CRASH, FATAL or device lost), or leave it out of FromLog.

  3. The plain words hide the real error, and some of them are wrong. For a recognised kind, Body drops It said: {Why}. Two of the matches go wrong on make_game.py's own messages:

    • "Could not clear … A file in it is in use: close any window showing that folder, wait for your antivirus to finish" (make_game.py:1182) is shown as "Your antivirus removed some of Longshot's files".
    • "symbolic links and reparse points are not supported" (make_game.py:576) is shown as "These game files are a different version".

    Keep make_game.py's message on screen under the plain words. Match whole phrases ("Longshot supports build", "Your antivirus most likely removed them") rather than "antivirus" or "not supported", and add those two messages to the tests as cases that must not match.

  4. This sets up a second report pipeline beside the one in use. MagicBeanDev/Longshot#81 already has a relay and a crash-bot that groups reports by signature. MagicBeanDev/Longshot#141 posts to it with a format that is already settled (version, release flag, OS, CPU and RAM, GPU, renderer, map, the CRASH lines, the 150 lines before them) and keeps the addresses in nx2/addresses.ini. Its review suggested the crash window move to the launcher. This PR instead says no inbox exists, and docs/launcher-reports.md defines a new JSON format (format/kind/text) and asks for a new service. Send the relay's format, or agree the format on #81 first, so there is one inbox and one signature, not two.

  5. "Always send" with no inbox, and sending from the constructor. With Always chosen, ReportViewModel's constructor calls Send(). At the next start that runs inside MainViewModel's constructor, before Host is set (MainWindow.axaml.cs:42). With no inbox, which is every player today, Copy() copies nothing and opens no form, yet the toast still says "Copied the report". Once Host is set, the same path overwrites the clipboard and opens a browser without a click. Offer Always only when an inbox is set up, and start an automatic send once the page is on screen.

Should change

  • The first choice is made without seeing the text. The preview is closed while the player picks Always, Just this once or Never. The doc says the choice comes after "a What gets sent preview", and the class comment says "with the exact text shown first". Open it by default on the first ask.
  • The ends the game logs as FATAL: aren't found (hos_fatal, vk: FATAL: from replay_fatal). The game's own Bug report counts FATAL:, CRASH: and device lost as trouble (vk_bug_report.cpp:177).
  • The driver link uses the wrong graphics card, or none. Service.Gpus.FirstOrDefault() is always empty on Windows (GpuVendors returns nothing there), so Windows players never get the driver link. On Linux it is the first card*, which on a laptop may not be the card the game ran on. Take the maker from the log's vk: <name>, Vulkan … line.
  • A space in a path breaks the signature on Linux. Linux CRASH lines carry the module's full realpath (win32_posix.c GetModuleFileNameA), so a space in the path (…/My Games/longshot+0x10) makes (\S+) stop at …/My. The signature becomes 0xc0000005 my, which groups wrongly and sends a folder name's fragment unredacted in signature. Take the text after the last separator up to +0x….
  • A long run loses its start. Tail keeps only the last 192 KB, so the longshot vX (source …) line and the vk: … GPU line are gone and the report says "not in the log". Keep the head as well, as copy_log does.
  • A failed report build leaves the page stuck on "Sending". If report.Value throws (the log deleted or unreadable between the check and Send), sending stays true, the button stays disabled and the status stays "Sending the report..." for good. The task is discarded, so nobody sees the exception. Wrap it in try/finally and turn the failure into a status.
  • The fixes aren't wired. Repair, Pick other game files, Build to another folder and Use less memory are in Problems but no screen shows them; only DriverPage has a button. The problem screen still says "Then build again: what was built so far is kept" under every problem, including a wrong game version. Wire them, or drop them and the doc's "Each has a fix button".
  • The doc doesn't match the code:
    • The paths are Hookshot's (launcher/Core/…).
    • The choices are "Always send / Ask each time / Never" in the doc but "Just this once" in the window.
    • The doc says "the home screen then says so", but it is a page of its own.
    • It describes a picture "when the player ticks it", but there is no tick.
    • The ProblemChecks header promises "an inbox of our own on localhost", which the test doesn't have.
  • Tests worth adding: a Z:\home\<name> line, a non-ASCII user name, a log with only the mesh warning (must be no problem), the register and memory rows left out, and the two make_game.py messages above.
  • Every start, clean logs are read again: SeenCrashLogs only moves on a crash, and this runs on the UI thread before the window shows. Recording the newest log's time per folder even when it's clean avoids that.
A code-only review: I read the diff against main and the Longshot sources it matches on. I didn't build it or run the tests. **What's good** - Nothing goes out today: `DefaultInbox` is null, the inbox has to be https, and the test proves an http inbox is refused before anything is sent. - The report is plain text the player can open with "What gets sent", and a choice in the settings that isn't one of the three is treated as no choice. - `Redact` follows the game's own rule (`vk_bug_report.cpp`). Reading it, `Z:\home\<name>\…` from a Proton log on a native Linux launcher loses the name through the user-name pass, and non-ASCII names count as name characters. - No config file, token, save or settings file goes into a report. The build report carries only the launcher's own build settings. - A message that isn't recognised stays "The build stopped" rather than getting a wrong fix. That's the right default. **Must change** 1. **The log goes out with guest memory in it.** `report_crash` (`host/mkw_glue.c`) logs the 31 registers and 9 rows of the memory that x0, x1 and x19 point to (`CRASH: [x0+0x000] …`). That is the game's memory, which counts as made from game files, and `Make` sends the whole 192 KB tail as it is. With a chosen microphone, the `audio in:` lines also carry the device's name. Filter the lines as `nx2/crash_report.py` in https://git.magicbean.dev/MagicBeanDev/Longshot/pulls/141 does: no register or memory rows, no device names. Add a test with those lines in the fixture. 2. **"No mesh shaders" is a warning, not a crash.** `vk_main.cpp` logs `vk: this GPU has no mesh shaders: …` and the game carries on ("Said once, on its own thread, and the game goes on"). Each run writes a new log, so a player on such a card is shown "Your graphics card can't draw this game" after every session, even though nothing crashed. Report it only together with a real end (CRASH, FATAL or device lost), or leave it out of `FromLog`. 3. **The plain words hide the real error, and some of them are wrong.** For a recognised kind, `Body` drops `It said: {Why}`. Two of the matches go wrong on make_game.py's own messages: - "Could not clear … A file in it is in use: close any window showing that folder, wait for your antivirus to finish" (`make_game.py:1182`) is shown as "Your antivirus removed some of Longshot's files". - "symbolic links and reparse points are not supported" (`make_game.py:576`) is shown as "These game files are a different version". Keep make_game.py's message on screen under the plain words. Match whole phrases ("Longshot supports build", "Your antivirus most likely removed them") rather than "antivirus" or "not supported", and add those two messages to the tests as cases that must not match. 4. **This sets up a second report pipeline beside the one in use.** https://git.magicbean.dev/MagicBeanDev/Longshot/issues/81 already has a relay and a crash-bot that groups reports by signature. https://git.magicbean.dev/MagicBeanDev/Longshot/pulls/141 posts to it with a format that is already settled (version, release flag, OS, CPU and RAM, GPU, renderer, map, the CRASH lines, the 150 lines before them) and keeps the addresses in `nx2/addresses.ini`. Its review suggested the crash window move to the launcher. This PR instead says no inbox exists, and `docs/launcher-reports.md` defines a new JSON format (`format`/`kind`/`text`) and asks for a new service. Send the relay's format, or agree the format on #81 first, so there is one inbox and one signature, not two. 5. **"Always send" with no inbox, and sending from the constructor.** With Always chosen, `ReportViewModel`'s constructor calls `Send()`. At the next start that runs inside `MainViewModel`'s constructor, before `Host` is set (`MainWindow.axaml.cs:42`). With no inbox, which is every player today, `Copy()` copies nothing and opens no form, yet the toast still says "Copied the report". Once `Host` is set, the same path overwrites the clipboard and opens a browser without a click. Offer Always only when an inbox is set up, and start an automatic send once the page is on screen. **Should change** - **The first choice is made without seeing the text.** The preview is closed while the player picks Always, Just this once or Never. The doc says the choice comes after "a What gets sent preview", and the class comment says "with the exact text shown first". Open it by default on the first ask. - **The ends the game logs as `FATAL:` aren't found** (`hos_fatal`, `vk: FATAL:` from `replay_fatal`). The game's own Bug report counts `FATAL:`, `CRASH:` and `device lost` as trouble (`vk_bug_report.cpp:177`). - **The driver link uses the wrong graphics card, or none.** `Service.Gpus.FirstOrDefault()` is always empty on Windows (`GpuVendors` returns nothing there), so Windows players never get the driver link. On Linux it is the first `card*`, which on a laptop may not be the card the game ran on. Take the maker from the log's `vk: <name>, Vulkan …` line. - **A space in a path breaks the signature on Linux.** Linux CRASH lines carry the module's full realpath (`win32_posix.c` `GetModuleFileNameA`), so a space in the path (`…/My Games/longshot+0x10`) makes `(\S+)` stop at `…/My`. The signature becomes `0xc0000005 my`, which groups wrongly and sends a folder name's fragment unredacted in `signature`. Take the text after the last separator up to `+0x…`. - **A long run loses its start.** `Tail` keeps only the last 192 KB, so the `longshot vX (source …)` line and the `vk: …` GPU line are gone and the report says "not in the log". Keep the head as well, as `copy_log` does. - **A failed report build leaves the page stuck on "Sending".** If `report.Value` throws (the log deleted or unreadable between the check and Send), `sending` stays true, the button stays disabled and the status stays "Sending the report..." for good. The task is discarded, so nobody sees the exception. Wrap it in try/finally and turn the failure into a status. - **The fixes aren't wired.** Repair, Pick other game files, Build to another folder and Use less memory are in `Problems` but no screen shows them; only `DriverPage` has a button. The problem screen still says "Then build again: what was built so far is kept" under every problem, including a wrong game version. Wire them, or drop them and the doc's "Each has a fix button". - **The doc doesn't match the code:** - The paths are Hookshot's (`launcher/Core/…`). - The choices are "Always send / Ask each time / Never" in the doc but "Just this once" in the window. - The doc says "the home screen then says so", but it is a page of its own. - It describes a picture "when the player ticks it", but there is no tick. - The `ProblemChecks` header promises "an inbox of our own on localhost", which the test doesn't have. - **Tests worth adding:** a `Z:\home\<name>` line, a non-ASCII user name, a log with only the mesh warning (must be no problem), the register and memory rows left out, and the two make_game.py messages above. - Every start, clean logs are read again: `SeenCrashLogs` only moves on a crash, and this runs on the UI thread before the window shows. Recording the newest log's time per folder even when it's clean avoids that.
@ -530,0 +538,4 @@
public string Head => Problem.Kind == ProblemKind.Unknown ? "make_game.py stopped" : Problem.Headline;
public string Body => Problem.Kind == ProblemKind.Unknown
? $"Building {build.Job.Shown} stopped in {Stage}, {Percent}% of the way through. It said: {Why}"
: $"{Problem.Detail} (Building {build.Job.Shown} stopped in {Stage}, {Percent}% of the way through.)";
Owner

For a recognised kind, make_game.py's own message (Why) disappears from the screen. Keep it under the plain words so a wrong match can't hide the real error.

For a recognised kind, make_game.py's own message (`Why`) disappears from the screen. Keep it under the plain words so a wrong match can't hide the real error.
@ -42,0 +48,4 @@
var s = Service.Settings;
foreach (var b in Service.Registry.Builds)
{
var found = CrashCheck.Find(b.Folder, s.SeenCrashLogs.GetValueOrDefault(b.Folder), Service.Gpus.FirstOrDefault());
Owner

Gpus is always empty on Windows (SystemInfo.GpuVendors returns nothing there), so Windows players never get the driver link. On a Linux laptop the first card* may not be the card the game ran on. Take the maker from the log's vk: <name>, Vulkan … line.

`Gpus` is always empty on Windows (`SystemInfo.GpuVendors` returns nothing there), so Windows players never get the driver link. On a Linux laptop the first `card*` may not be the card the game ran on. Take the maker from the log's `vk: <name>, Vulkan …` line.
@ -0,0 +29,4 @@
NeverCommand = new Command(() => { Choose(ReportConsent.Never); Close(); });
CopyCommand = new Command(() => _ = Copy());
CloseCommand = new Command(Close);
if (Consent == ReportConsent.Always) _ = Send();
Owner

At the next start this runs inside MainViewModel's constructor, before Host is set (MainWindow.axaml.cs:42). With no inbox, Copy() copies nothing and opens no form, but the toast still says "Copied the report". Once Host is set, it would overwrite the clipboard and open a browser without a click. Offer Always only when an inbox is set up, and send once the page is shown.

At the next start this runs inside MainViewModel's constructor, before `Host` is set (MainWindow.axaml.cs:42). With no inbox, `Copy()` copies nothing and opens no form, but the toast still says "Copied the report". Once Host is set, it would overwrite the clipboard and open a browser without a click. Offer Always only when an inbox is set up, and send once the page is shown.
@ -0,0 +79,4 @@
main.Host?.Open(ReportSender.IssueForm);
return;
}
sending = true;
Owner

If report.Value throws below (the log gone or unreadable), sending stays true and the page shows "Sending the report..." for good; the discarded task hides the exception. Use try/finally and show the failure as the status.

If `report.Value` throws below (the log gone or unreadable), `sending` stays true and the page shows "Sending the report..." for good; the discarded task hides the exception. Use try/finally and show the failure as the status.
@ -0,0 +15,4 @@
<!-- (the first time: the player's choice, which the settings keep) -->
<Button Content="Never send" Command="{Binding NeverCommand}" IsVisible="{Binding AskConsent}"/>
<Button Content="Just this once" Command="{Binding OnceCommand}" IsVisible="{Binding AskConsent}"/>
<Button Classes="primary" Content="Always send" Command="{Binding AlwaysCommand}" IsVisible="{Binding AskConsent}"/>
Owner

The first choice is made with the preview closed, though the doc and the class comment say the text is shown first. Open "What gets sent" by default while AskConsent is true, and don't offer Always while there is no inbox.

The first choice is made with the preview closed, though the doc and the class comment say the text is shown first. Open "What gets sent" by default while AskConsent is true, and don't offer Always while there is no inbox.
@ -0,0 +60,4 @@
}
/// The end of a file, at most max bytes, from the start of a line
public static string Tail(string path, int max = LogTailBytes)
Owner

Only the end is kept, so in a long run the longshot vX (source …) line and the vk: … GPU line drop out, and the report says "not in the log". Keep the head too, as copy_log in vk_bug_report.cpp does.

Only the end is kept, so in a long run the `longshot vX (source …)` line and the `vk: …` GPU line drop out, and the report says "not in the log". Keep the head too, as `copy_log` in vk_bug_report.cpp does.
@ -0,0 +97,4 @@
t.Append("### Longshot version\n\n").Append(version).Append("\n\n");
t.Append("### Graphics card and driver version\n\n").Append(GpuLine(lines) ?? "not in the log").Append("\n\n");
t.Append("### CPU, RAM and operating system\n\n").Append(system).Append("\n\n");
if (logText != null) t.Append("### longshot_log.txt\n\n```\n").Append(R(logText)).Append("\n```\n\n");
Owner

The whole tail goes out as it is, including report_crash's register rows and the guest-memory rows (CRASH: [x0+0x000] …, host/mkw_glue.c), which are the game's memory, plus audio in: lines that name a chosen microphone. Filter these like nx2/crash_report.py in MagicBeanDev/Longshot#141 does, and add the lines to the test fixture.

The whole tail goes out as it is, including `report_crash`'s register rows and the guest-memory rows (`CRASH: [x0+0x000] …`, host/mkw_glue.c), which are the game's memory, plus `audio in:` lines that name a chosen microphone. Filter these like `nx2/crash_report.py` in https://git.magicbean.dev/MagicBeanDev/Longshot/pulls/141 does, and add the lines to the test fixture.
Core/Problems.cs Outdated
@ -0,0 +50,4 @@
{
var w = why ?? "";
bool Has(string s) => w.Contains(s, StringComparison.OrdinalIgnoreCase);
if (Has("antivirus") || Has("quarantine"))
Owner

make_game.py:1182 ("Could not clear … A file in it is in use … wait for your antivirus to finish") lands here and is shown as "Your antivirus removed some of Longshot's files" with Repair. Match the removal message itself ("Your antivirus most likely removed them").

make_game.py:1182 ("Could not clear … A file in it is in use … wait for your antivirus to finish") lands here and is shown as "Your antivirus removed some of Longshot's files" with Repair. Match the removal message itself ("Your antivirus most likely removed them").
Core/Problems.cs Outdated
@ -0,0 +55,4 @@
"This is a false alarm: Longshot's build tools aren't signed, so some antivirus programs flag them. Restore the " +
"files from your antivirus's quarantine (Windows Security: Protection history), or allow Longshot's folder, then " +
"repair and build again.", [new Fix(FixKind.Repair, "Repair and build again")]);
if (Has("Longshot supports build") || Has("isn't supported") || Has("not supported"))
Owner

"not supported" also matches make_game.py:576 ("symbolic links and reparse points are not supported"), which then shows as "These game files are a different version". "Longshot supports build" alone is enough.

"not supported" also matches make_game.py:576 ("symbolic links and reparse points are not supported"), which then shows as "These game files are a different version". "Longshot supports build" alone is enough.
Core/Problems.cs Outdated
@ -0,0 +75,4 @@
"Something went wrong that Longshot doesn't recognise. Sending a report helps us fix it.", [BuildAgain]);
}
[GeneratedRegex(@"CRASH: exception (0x[0-9a-fA-F]+) \((read|write)[^)]*\) at (\S+)")]
Owner

On Linux the module is a full realpath (win32_posix.c GetModuleFileNameA). With a space in the path (…/My Games/longshot+0x10), \S+ stops at …/My, so the signature becomes 0xc0000005 my: it groups wrongly and sends a folder name's fragment unredacted. Take the name after the last separator up to +0x….

On Linux the module is a full realpath (win32_posix.c `GetModuleFileNameA`). With a space in the path (`…/My Games/longshot+0x10`), `\S+` stops at `…/My`, so the signature becomes `0xc0000005 my`: it groups wrongly and sends a folder name's fragment unredacted. Take the name after the last separator up to `+0x…`.
Core/Problems.cs Outdated
@ -0,0 +93,4 @@
}
if (line.Contains("device lost", StringComparison.OrdinalIgnoreCase) ||
line.Contains("VK_ERROR_DEVICE_LOST", StringComparison.Ordinal)) lost = true;
if (line.Contains("this GPU has no mesh shaders", StringComparison.Ordinal)) noMesh = true;
Owner

This line is a warning: vk_main.cpp says "Said once, on its own thread, and the game goes on." Each run writes a new log, so a player on such a card gets "can't draw this game" after every session without a crash. Report it only with a real end (CRASH, FATAL or device lost).

This line is a warning: vk_main.cpp says "Said once, on its own thread, and the game goes on." Each run writes a new log, so a player on such a card gets "can't draw this game" after every session without a crash. Report it only with a real end (CRASH, FATAL or device lost).
Core/Problems.cs Outdated
@ -0,0 +103,4 @@
return new Problem(ProblemKind.GpuLost, "The graphics driver stopped responding",
"This is often fixed by the latest graphics driver. If it keeps happening, sending a report helps us find the cause.",
[DriverFix(vendor)], Signature(crash, module, "device lost"));
if (crash == null) return null;
Owner

Runs that ended with FATAL: (hos_fatal, vk: FATAL: from replay_fatal) aren't found. The game's Bug report counts FATAL, CRASH and device lost (vk_bug_report.cpp:177).

Runs that ended with `FATAL:` (`hos_fatal`, `vk: FATAL:` from `replay_fatal`) aren't found. The game's Bug report counts FATAL, CRASH and device lost (vk_bug_report.cpp:177).
@ -0,0 +17,4 @@
public static class ReportSender
{
/// The inbox; LONGSHOT_REPORT_URL over it (for trying an inbox out). https only
public const string? DefaultInbox = null;
Owner

MagicBeanDev/Longshot#81 already has a relay and crash-bot, and MagicBeanDev/Longshot#141 posts to it in a settled format, with the address in nx2/addresses.ini. Send that format to that relay, or settle a format on #81 first, rather than defining a second inbox and JSON contract.

https://git.magicbean.dev/MagicBeanDev/Longshot/issues/81 already has a relay and crash-bot, and https://git.magicbean.dev/MagicBeanDev/Longshot/pulls/141 posts to it in a settled format, with the address in `nx2/addresses.ini`. Send that format to that relay, or settle a format on #81 first, rather than defining a second inbox and JSON contract.
@ -0,0 +2,4 @@
When a build stops or the game closes unexpectedly, the launcher explains what happened in plain words, offers the fix it
knows, and can send a report to the developers with one button, so a player needs no forge account and no idea where the
log is. This page is the contract between the launcher (`launcher/Core/Problems.cs`, `ProblemReport.cs`,
Owner

These are Hookshot's paths (launcher/Core/…); here they are Core/…. Other places in this doc don't match the code either: "Ask each time" (the window says "Just this once"), "the home screen then says so" (it is a page of its own), "Each has a fix button" (none are wired), and the picture tick (there isn't one).

These are Hookshot's paths (`launcher/Core/…`); here they are `Core/…`. Other places in this doc don't match the code either: "Ask each time" (the window says "Just this once"), "the home screen then says so" (it is a page of its own), "Each has a fix button" (none are wired), and the picture tick (there isn't one).
feat(launcher): reports go to the website's inbox
Some checks failed
CI / Conventional Commit title (pull_request) Has been cancelled
CI / Compile and test (pull_request) Has been cancelled
d523d46805
ReportSender.DefaultInbox is https://longshot.magicbean.dev/report, the
website Worker's inbox (Longshot, website/worker/report.ts), which files
each report as an issue on Longshot, one issue per problem. A report that
could not be sent says to try Send again or copy it for the issue form.
docs/launcher-reports.md describes the inbox as it is.

Assisted-by: Claude Opus 5.5
Author
First-time contributor

Pushed d523d468: reports now go to the website's inbox, https://longshot.magicbean.dev/report (ReportSender.DefaultInbox). The inbox is Longshot #251: it files each report as an issue on Longshot, one issue per problem (the same crash from another PC becomes a comment). docs/launcher-reports.md now describes the inbox as it is, and a report that fails to send says to try Send again or copy it for the issue form.

Order: merge and set up #251 (the bot token as a Worker secret) before a release carries this. Until then a send gets "could not be sent" and the copy path, as before.

Tested: python -I tests/test_launcher_core.py --strict (663 checks pass, with the new inbox checks), and the app builds (Release). Not tested: a real send. The inbox has no token until #251 is set up; its own end-to-end run against git.magicbean.dev is in #251.

Pushed d523d468: reports now go to the website's inbox, `https://longshot.magicbean.dev/report` (`ReportSender.DefaultInbox`). The inbox is Longshot [#251](https://git.magicbean.dev/MagicBeanDev/Longshot/pulls/251): it files each report as an issue on Longshot, one issue per problem (the same crash from another PC becomes a comment). `docs/launcher-reports.md` now describes the inbox as it is, and a report that fails to send says to try **Send** again or copy it for the issue form. Order: merge and set up #251 (the bot token as a Worker secret) before a release carries this. Until then a send gets "could not be sent" and the copy path, as before. Tested: `python -I tests/test_launcher_core.py --strict` (663 checks pass, with the new inbox checks), and the app builds (Release). Not tested: a real send. The inbox has no token until #251 is set up; its own end-to-end run against git.magicbean.dev is in #251.
HumanBean left a comment

A second code-only review, of d523d468: I read the diff against main, the earlier review, and Longshot MagicBeanDev/Longshot#251 (the inbox). I didn't build it or run the tests.

The new commit turns sending on: DefaultInbox is now https://longshot.magicbean.dev/report, and each report becomes a public issue on Longshot. None of the earlier points were addressed in the code, so the unfiltered log would now leave every player's PC and be posted in public.

The earlier points

  1. The log goes out unfiltered (register rows, guest-memory CRASH: [x0+…] rows, the microphone's name): open, and now it matters for real (see Must change 1).
  2. "No mesh shaders" counted as a crash: open. Main now says the same thing as the earlier review: #44 reports a card without mesh shaders as "using the slower compute fallback", while this PR tells that player "Your graphics card can't draw this game".
  3. The plain words replace make_game.py's message, and two mappings are wrong: open. Body still drops Why for a known kind, and "antivirus" and "not supported" still match the two make_game.py messages.
  4. A second inbox instead of the crash bot in MagicBeanDev/Longshot#81: open, and now built. MagicBeanDev/Longshot#251 is a second live pipeline. It has its own key and its own issues, separate from the #81 relay and the format MagicBeanDev/Longshot#141 uses (see Must change 3).
  5. "Always send" with no inbox, sending from the constructor: partly. With an inbox set by default, the copy-without-Host path no longer runs. But the send still starts inside MainViewModel's constructor, and after a failed Always send there is no Send button (see Should change).
  6. The first choice is made with the preview closed: open.
  7. FATAL: isn't detected: open.
  8. No driver link on Windows, and the wrong card on a Linux laptop: open.
  9. A space in a Linux module path leaks part of a folder name: open. The signature now also goes into a public issue title.
  10. Long logs lose the version and GPU lines: open.
  11. The page stuck on "Sending" when the report can't be built: open. report.Value is still outside a try/finally (ReportViewModel.cs:86).
  12. Unused fix kinds, and "Then build again" under every problem: open.
  13. The docs don't match the code: partly. The inbox section now describes MagicBeanDev/Longshot#251 correctly. Still wrong:
    • launcher/Core/… paths
    • "Ask each time"
    • "the home screen then says so"
    • "Each has a fix button"
    • the picture tick
    • the ProblemChecks header's "inbox of our own on localhost"
    • the new "with Send to try again", which isn't true after Always (see Should change)
  14. Missing tests: open. Only two inbox-URL checks were added. None covers Z:\home, non-ASCII names, a log with only the mesh warning, filtered register and memory rows, or the two make_game.py messages.

Also still open: clean logs are read again at every start, on the UI thread.

The new endpoint

  • Host: longshot.magicbean.dev is the team's website Worker (its custom domain in website/wrangler.jsonc), not a personal domain. Good.
  • TLS: https only. Inbox() refuses http, and .NET's HttpClient doesn't follow an https→http redirect. Good.
  • Timeout, retries, failure: 30 s, no automatic retry, and any non-2xx shows "could not be sent" with Copy report. The fallback is right, apart from the missing Send button after Always.
  • Size: the inbox takes at most 256 KB of text. The launcher doesn't cap it: today it is a 192 KB tail plus headings and redaction, so it fits, but nothing guarantees it.
  • Rate limiting: 3 a minute per address and 20 a minute in total, in MagicBeanDev/Longshot#251. See Should change.

Must change

  1. Don't turn the inbox on before the log is filtered. With DefaultInbox set, "Always send" and "Send report" post the whole 192 KB tail, guest-memory rows included, as a public Longshot issue. That breaks the rule that nothing made from game files leaves the PC. Keep DefaultInbox null until earlier point 1 is fixed and tested. It also needs MagicBeanDev/Longshot#251 merged and its token set first, or a release sends every report into a 404 or 503.
  2. Tell the player the report is public. The consent text says "send a report about this to the developers", and the settings text says the same. The report is filed as a public issue on git.magicbean.dev, with the full log. Say so where they choose, and in the settings.
  3. One crash, two reports. MagicBeanDev/Longshot#141 opens a crash window when the game crashes, and offers again at --play and --launch. It sends to the #81 relay. This PR offers the same crash at the launcher's next start and files it somewhere else, with a different signature. A player who says yes to both is asked twice, and we get two records that don't link. Agree on one path on MagicBeanDev/Longshot#81 before either merges. For example, the launcher could skip game crashes and keep build problems, or post game crashes to the relay in #141's format.

Should change

  • After a failed "Always send" there is no Send button. The status says "Try Send again later", but AskEach is false when the consent is Always, so only Close and Copy report show. Show Send whenever a send failed. docs/launcher-reports.md promises the same.
  • No release flag. Local and modified builds would file public kind/bug issues next to real ones. #141 sends a release flag, and the crash bot marks such reports "[not a release]". Send the same, and let the inbox label or drop those reports.
  • Fence the log safely. The log goes inside a plain ``` fence. A log line that holds ``` ends the block, and the rest renders as Markdown on a public issue. Use a fence longer than any run of backticks in the text.
  • Cap the text in the launcher at the inbox's 256 KB, so a long build output can't come back as a 413 the player can do nothing about.
  • Abuse, for MagicBeanDev/Longshot#251: anyone can POST to /report and open public issues. 20 a minute in total is up to 28,800 issues a day, and changing the signature opens a new issue every time. A daily cap, or a cap on new issues per hour (with comments still allowed), would bound it. REPORTS_OFF is a good kill switch.
  • Small: the inbox's url is never used. A link to the issue after "Sent as report #123" would let the player follow it.

Merging origin/main (0e6e1d7) gives no textual conflicts. The overlap with main is the meaning of the mesh-shader warning (earlier point 2).

A second code-only review, of d523d468: I read the diff against main, the earlier review, and Longshot https://git.magicbean.dev/MagicBeanDev/Longshot/pulls/251 (the inbox). I didn't build it or run the tests. The new commit turns sending on: `DefaultInbox` is now `https://longshot.magicbean.dev/report`, and each report becomes a **public** issue on Longshot. None of the earlier points were addressed in the code, so the unfiltered log would now leave every player's PC and be posted in public. **The earlier points** 1. The log goes out unfiltered (register rows, guest-memory `CRASH: [x0+…]` rows, the microphone's name): **open**, and now it matters for real (see Must change 1). 2. "No mesh shaders" counted as a crash: **open**. Main now says the same thing as the earlier review: https://git.magicbean.dev/MagicBeanDev/LongshotLauncher/pulls/44 reports a card without mesh shaders as "using the slower compute fallback", while this PR tells that player "Your graphics card can't draw this game". 3. The plain words replace make_game.py's message, and two mappings are wrong: **open**. `Body` still drops `Why` for a known kind, and `"antivirus"` and `"not supported"` still match the two make_game.py messages. 4. A second inbox instead of the crash bot in https://git.magicbean.dev/MagicBeanDev/Longshot/issues/81: **open, and now built.** https://git.magicbean.dev/MagicBeanDev/Longshot/pulls/251 is a second live pipeline. It has its own key and its own issues, separate from the #81 relay and the format https://git.magicbean.dev/MagicBeanDev/Longshot/pulls/141 uses (see Must change 3). 5. "Always send" with no inbox, sending from the constructor: **partly.** With an inbox set by default, the copy-without-`Host` path no longer runs. But the send still starts inside `MainViewModel`'s constructor, and after a failed Always send there is no Send button (see Should change). 6. The first choice is made with the preview closed: **open.** 7. `FATAL:` isn't detected: **open.** 8. No driver link on Windows, and the wrong card on a Linux laptop: **open.** 9. A space in a Linux module path leaks part of a folder name: **open.** The signature now also goes into a public issue title. 10. Long logs lose the version and GPU lines: **open.** 11. The page stuck on "Sending" when the report can't be built: **open.** `report.Value` is still outside a try/finally (ReportViewModel.cs:86). 12. Unused fix kinds, and "Then build again" under every problem: **open.** 13. The docs don't match the code: **partly.** The inbox section now describes https://git.magicbean.dev/MagicBeanDev/Longshot/pulls/251 correctly. Still wrong: - `launcher/Core/…` paths - "Ask each time" - "the home screen then says so" - "Each has a fix button" - the picture tick - the `ProblemChecks` header's "inbox of our own on localhost" - the new "with Send to try again", which isn't true after Always (see Should change) 14. Missing tests: **open.** Only two inbox-URL checks were added. None covers `Z:\home`, non-ASCII names, a log with only the mesh warning, filtered register and memory rows, or the two make_game.py messages. Also still open: clean logs are read again at every start, on the UI thread. **The new endpoint** - **Host:** `longshot.magicbean.dev` is the team's website Worker (its custom domain in `website/wrangler.jsonc`), not a personal domain. Good. - **TLS:** https only. `Inbox()` refuses http, and .NET's HttpClient doesn't follow an https→http redirect. Good. - **Timeout, retries, failure:** 30 s, no automatic retry, and any non-2xx shows "could not be sent" with Copy report. The fallback is right, apart from the missing Send button after Always. - **Size:** the inbox takes at most 256 KB of text. The launcher doesn't cap it: today it is a 192 KB tail plus headings and redaction, so it fits, but nothing guarantees it. - **Rate limiting:** 3 a minute per address and 20 a minute in total, in https://git.magicbean.dev/MagicBeanDev/Longshot/pulls/251. See Should change. **Must change** 1. **Don't turn the inbox on before the log is filtered.** With `DefaultInbox` set, "Always send" and "Send report" post the whole 192 KB tail, guest-memory rows included, as a public Longshot issue. That breaks the rule that nothing made from game files leaves the PC. Keep `DefaultInbox` null until earlier point 1 is fixed and tested. It also needs https://git.magicbean.dev/MagicBeanDev/Longshot/pulls/251 merged and its token set first, or a release sends every report into a 404 or 503. 2. **Tell the player the report is public.** The consent text says "send a report about this to the developers", and the settings text says the same. The report is filed as a public issue on git.magicbean.dev, with the full log. Say so where they choose, and in the settings. 3. **One crash, two reports.** https://git.magicbean.dev/MagicBeanDev/Longshot/pulls/141 opens a crash window when the game crashes, and offers again at `--play` and `--launch`. It sends to the #81 relay. This PR offers the same crash at the launcher's next start and files it somewhere else, with a different signature. A player who says yes to both is asked twice, and we get two records that don't link. Agree on one path on https://git.magicbean.dev/MagicBeanDev/Longshot/issues/81 before either merges. For example, the launcher could skip game crashes and keep build problems, or post game crashes to the relay in #141's format. **Should change** - **After a failed "Always send" there is no Send button.** The status says "Try Send again later", but `AskEach` is false when the consent is Always, so only Close and Copy report show. Show Send whenever a send failed. `docs/launcher-reports.md` promises the same. - **No release flag.** Local and modified builds would file public `kind/bug` issues next to real ones. #141 sends a release flag, and the crash bot marks such reports "[not a release]". Send the same, and let the inbox label or drop those reports. - **Fence the log safely.** The log goes inside a plain ```` ``` ```` fence. A log line that holds ```` ``` ```` ends the block, and the rest renders as Markdown on a public issue. Use a fence longer than any run of backticks in the text. - **Cap the text in the launcher** at the inbox's 256 KB, so a long build output can't come back as a `413` the player can do nothing about. - **Abuse, for https://git.magicbean.dev/MagicBeanDev/Longshot/pulls/251:** anyone can POST to `/report` and open public issues. 20 a minute in total is up to 28,800 issues a day, and changing the signature opens a new issue every time. A daily cap, or a cap on new issues per hour (with comments still allowed), would bound it. `REPORTS_OFF` is a good kill switch. - Small: the inbox's `url` is never used. A link to the issue after "Sent as report #123" would let the player follow it. Merging origin/main (0e6e1d7) gives no textual conflicts. The overlap with main is the meaning of the mesh-shader warning (earlier point 2).
@ -0,0 +86,4 @@
var r = await ReportSender.Send(report.Value, inbox);
sending = false;
sent = r.Sent;
Status = r.Sent ? r.Message : r.Message + " Try Send again later, or Copy report and paste it into the issue form.";
Owner

With Always chosen, AskEach is false, so after a failed send there is no Send button, only Close and Copy report, yet the status says "Try Send again later". The doc promises "Send to try again" too. Show Send whenever a send failed.

With Always chosen, `AskEach` is false, so after a failed send there is no Send button, only Close and Copy report, yet the status says "Try Send again later". The doc promises "Send to try again" too. Show Send whenever a send failed.
@ -0,0 +42,4 @@
<TextBlock Text="{Binding Detail}" Foreground="{StaticResource InkSoft}" TextWrapping="Wrap" MaxWidth="680" HorizontalAlignment="Left"/>
<Button HorizontalAlignment="Left" Content="{Binding Fix.Label}" Command="{Binding FixCommand}" IsVisible="{Binding Fix, Converter={x:Static ObjectConverters.IsNotNull}}"/>
<TextBlock Foreground="{StaticResource InkSoft}" TextWrapping="Wrap" MaxWidth="680" HorizontalAlignment="Left" IsVisible="{Binding AskConsent}"
Text="Can we send a report about this to the developers? It holds your Longshot version, your graphics card, system and the game's log, with your user name taken out. No saves, no game files. You choose once; the launcher's settings can change it."/>
Owner

The report becomes a public issue on git.magicbean.dev, with the log, but this says "send a report about this to the developers". Tell the player it is posted publicly before they choose Always or Just this once.

The report becomes a public issue on git.magicbean.dev, with the log, but this says "send a report about this to the developers". Tell the player it is posted publicly before they choose Always or Just this once.
@ -92,0 +93,4 @@
<StackPanel VerticalAlignment="Center">
<TextBlock Text="Problem reports" FontWeight="SemiBold"/>
<TextBlock FontSize="12" Foreground="{StaticResource InkSoft}" TextWrapping="Wrap" MaxWidth="460"
Text="When a build stops or the game closes unexpectedly: the version, your graphics card and system, and the log, with your user name taken out. No saves or game files."/>
Owner

Same as on the report page: say that reports are posted publicly as issues on git.magicbean.dev.

Same as on the report page: say that reports are posted publicly as issues on git.magicbean.dev.
@ -0,0 +94,4 @@
t.Append("### What happened\n\n").Append(problem.Headline);
if (problem.Signature != null) t.Append(" (").Append(problem.Signature).Append(')');
t.Append("\n\nSent from the Longshot Launcher").Append(log != null ? " after the game closed unexpectedly" : " after a build stopped").Append(".\n\n");
t.Append("### Longshot version\n\n").Append(version).Append("\n\n");
Owner

There's no release flag. A local or modified build would file a public kind/bug issue that looks like a release's. MagicBeanDev/Longshot#141 sends one, and the #81 crash bot marks such reports "[not a release]".

There's no release flag. A local or modified build would file a public `kind/bug` issue that looks like a release's. https://git.magicbean.dev/MagicBeanDev/Longshot/pulls/141 sends one, and the #81 crash bot marks such reports "[not a release]".
@ -0,0 +97,4 @@
t.Append("### Longshot version\n\n").Append(version).Append("\n\n");
t.Append("### Graphics card and driver version\n\n").Append(GpuLine(lines) ?? "not in the log").Append("\n\n");
t.Append("### CPU, RAM and operating system\n\n").Append(system).Append("\n\n");
if (logText != null) t.Append("### longshot_log.txt\n\n```\n").Append(R(logText)).Append("\n```\n\n");
Owner

On a public issue a plain ``` fence isn't safe: a log line that holds ``` ends the block, and the rest renders as Markdown. Use a fence longer than any run of backticks in the text. Cap the text at the inbox's 256 KB here too, so the inbox can't answer 413 to something the player can't shorten.

On a public issue a plain ```` ``` ```` fence isn't safe: a log line that holds ```` ``` ```` ends the block, and the rest renders as Markdown. Use a fence longer than any run of backticks in the text. Cap the text at the inbox's 256 KB here too, so the inbox can't answer `413` to something the player can't shorten.
@ -0,0 +96,4 @@
if (line.Contains("this GPU has no mesh shaders", StringComparison.Ordinal)) noMesh = true;
}
if (noMesh)
return new Problem(ProblemKind.NoMeshShaders, "Your graphics card can't draw this game",
Owner

Main now says the same thing: #44 reports a card without mesh shaders as "using the slower compute fallback". After merging, the same player would see the requirements check say the game runs and this page say "can't draw this game".

Main now says the same thing: https://git.magicbean.dev/MagicBeanDev/LongshotLauncher/pulls/44 reports a card without mesh shaders as "using the slower compute fallback". After merging, the same player would see the requirements check say the game runs and this page say "can't draw this game".
@ -0,0 +18,4 @@
public static class ReportSender
{
/// The inbox; LONGSHOT_REPORT_URL over it (for trying an inbox out). https only
public const string? DefaultInbox = "https://longshot.magicbean.dev/report";
Owner

This turns sending on for every player while the log still goes out unfiltered: the guest-memory CRASH: [x0+…] rows and the microphone's name (the comment on ProblemReport.cs). The inbox in MagicBeanDev/Longshot#251 posts the report as a public issue on Longshot. Keep this null until the filter and its test are in, and until #251 is merged and has its token. Without that, a release sends every report into a 404 or 503.

This turns sending on for every player while the log still goes out unfiltered: the guest-memory `CRASH: [x0+…]` rows and the microphone's name (the comment on ProblemReport.cs). The inbox in https://git.magicbean.dev/MagicBeanDev/Longshot/pulls/251 posts the report as a public issue on Longshot. Keep this null until the filter and its test are in, and until #251 is merged and has its token. Without that, a release sends every report into a 404 or 503.
TrashPanda force-pushed feat/problem-reports from d523d46805
Some checks failed
CI / Conventional Commit title (pull_request) Has been cancelled
CI / Compile and test (pull_request) Has been cancelled
to ff7228dc4b
Some checks are pending
CI / Conventional Commit title (pull_request) Blocked by required conditions
CI / Compile and test (pull_request) Blocked by required conditions
2026-11-13 17:46:57 +00:00
Compare
TrashPanda changed title from WIP: feat(launcher): problems in plain words, crashes found at the next start, and Send report to WIP: feat(launcher): Send report, to the website's inbox 2026-11-13 17:47:38 +00:00
Author
First-time contributor

Split at HumanBean's request. The problems in plain words, the crash found at the next start and its page are now #48. This branch is #48 plus one commit for the reporting (ff7228dc), rebased on current main. I force-pushed the branch; the final code is the same as before plus main's new commits. Merge #48 first.

Split at HumanBean's request. The problems in plain words, the crash found at the next start and its page are now #48. This branch is #48 plus one commit for the reporting (ff7228dc), rebased on current main. I force-pushed the branch; the final code is the same as before plus main's new commits. Merge #48 first.
Some checks are pending
CI / Conventional Commit title (pull_request) Blocked by required conditions
CI / Compile and test (pull_request) Blocked by required conditions
This pull request is marked as a work in progress.
Some workflows are waiting to be reviewed.
View command line instructions

Checkout

From your project repository, check out a new branch and test the changes.
git fetch -u 'feat/problem-reports:TrashPanda-feat/problem-reports'
git switch 'TrashPanda-feat/problem-reports'
Sign in to join this conversation.
No reviewers
No milestone
No project
No assignees
2 participants
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/LongshotLauncher!42
No description provided.