The Banner That Hands Your Set Back
Lux has been quietly writing a snapshot of your patch every time it dies. Now the next launch actually tells you, with a Restore button, instead of leaving the file in a cache folder for you to find on your own.

Lux has been taking a snapshot of your project every time it crashes for a while
now. Panic mid-frame, and the last serialized version of your patch lands in
~/.cache/lux/ under a filename made of a timestamp. Diligent. Thorough.
Completely useless, because nothing ever told you it was there.
The recovery half of that feature did not exist. There was a flag in the code
called banner_visible, set on startup by a scan of the crash directory, and
read by absolutely nobody. The entire “offer” was a line of terminal output. If
your show died ten minutes into a set, the path back to your work ran through a
hidden folder, a filename you had to decode, and the assumption that you knew any
of this existed. Most artists do not read the terminal. Most artists do not have
a terminal open. That is rather the point of a visual programming environment.
So now the launch after a crash greets you like this:

Amber, across the top, above everything. Restore loads the snapshot back into the editor. Dismiss puts it away. That is the whole interface, and it is roughly one interaction more than the previous design, which was zero.
Restore does not touch your file
The snapshot is a graph that died mid-frame. It is probably newer than your last save, and it is definitely not something you consciously committed to. So a restored document comes back untitled and unsaved: your patch is on the canvas, the title bar says it is dirty, and the first Ctrl+S opens Save As and asks you where you want it.
That is deliberate. The one thing a recovery feature must never do is quietly overwrite the last file you deliberately saved with a snapshot of the moment everything went wrong. Restore hands you the work back and lets you decide where it lands.
Dismiss does not delete anything
Clicking Dismiss archives the snapshot rather than deleting it. It gets renamed
out of the way so the banner stops offering it on every launch, and it stays in
the crash directory under an .archived name.
An artist clicking Dismiss at two in the morning after a rough show is not carefully deciding to shred the only surviving copy of that show. They are making a banner go away. Those two things should not be the same button.
The banner only promises what it can deliver
The crash handler writes one of two things when the process dies: your project
bytes, or a small forensic marker file when the crash happened before the app had
any project bytes to save. Both landed in the same directory with the same
crash-*.lux naming, and the old scan happily treated both as recoverable.
A banner that offers to restore a file containing no graph is worse than no banner. So the scan now reads its candidates: markers, empty files, and already archived snapshots are skipped, and the banner is only raised for a snapshot that can actually come back. If the offer appears, the set is there.
The crashes that do not get to say goodbye
There is a flattering assumption buried in every crash handler: that the program will be alive long enough to notice it is dying. That holds for a Rust panic, which unwinds politely and gives the handler a moment to write your work out.
It does not hold for any of the ways a GPU application actually dies. A driver segfault, a device-lost abort, the OOM killer, or the classic venue special where somebody finds the power strip with their heel: none of these run a single line of your code. The handler never fires. The crash directory stays empty. A banner that depends on it has nothing to show you, which is a poor result for the class of crash you are most likely to have.
What does survive a power cut is whatever is already on the disk, and Lux has been autosaving your patch every sixty seconds while it is dirty for a while now. So the startup scan now looks at both: the snapshot the dying process wrote, and the autosave nobody had to be alive to write, and offers whichever is newer. A clean exit files the autosave away on its way out, which is what makes the thing still being there at launch mean something. If Lux finds it, Lux did not exit. It was stopped.
The practical upshot: pull the plug mid-set, relaunch, and the banner is there with your set behind it.
An offer you have not answered yet is not litter
There is a trap hiding in that last paragraph. The file rescuing you from a power cut is the autosave, and the autosave is a file Lux writes to. Leave the banner offering it while you get on with your evening, and sixty dirty seconds later the autosave comes round again and writes your new session straight over the old dead one. The banner is still up. It is still offering to restore your set. It would now hand you back the patch you are already looking at.
So by the time that banner is in front of you, the file behind it has already been claimed: moved out of the autosave’s path and into a name nothing else writes to, stamped with the time your set actually died. Nothing can overwrite it after that. Take an hour to decide. Close the window and go home and decide next week: an unanswered offer comes back on the next launch, and if you manage to crash twice without ever answering, both sets are still there, waiting, each in its own file.
The claiming happens as the window comes up, and only as the window comes up. Looking for a crashed set is a read, and reading is all it does. That distinction sounds like bookkeeping, and it is, right up until the day a stray bit of tooling goes looking on your behalf and quietly moves a file you were still using.
Nothing on the disk is thrown away because you did not click a button.
Underneath it all, the tests now kill a real process with a real SIGKILL, holding a real wired graph, and assert that the next launch is offered the recovery and that Restore brings back every node, every wire, and the pin values you had dialled in. It also asserts that the crash handler wrote nothing at all, because a test that quietly proves the polite path twice would be no test. The panic path gets the same treatment separately, and the banner is gated by a pixel test that rasterizes the actual widget and checks that the amber strip is on screen and confined to the top, and that a clean launch paints no banner at all. The pretty picture above is that test’s output, not a mock-up.
Crash recovery was previously a feature that worked perfectly as long as nobody needed it. Now it works when they do.