SQLBI Whiteboard 1.5.0 (dev 3333)
Pre-release
Pre-release
Autosave the board and restore it at the next start (#123) Closes #121. Closes #122. The board is copied into a session slot every thirty seconds and again on the way out, and the next start brings it back. **Nothing on this path writes to the `.wboard` the person named** — that file changes when they ask for it to change, and every call below follows from it. The reasoning is decision 30 in `docs/decisions.md`. ## Knowing whether the board has changed came first All three parts of #121 need it, and the application could not answer it. `ConfirmDiscardUnsaved` stood in by asking whether the board was empty, so it nagged right after a save and said nothing when everything had just been erased. It is two signals, because one cannot cover it: - **`CommandHistory` carries a save point** — the command on top of the undo stack when the file was written. Undoing back to what was saved stops counting as a change; undoing *past* it starts counting again. A counter cannot express that, since undo moves it the same way drawing does. - **A flag covers what never reaches a command.** In practice only one caller survived the audit: a `.wimport` opened as a new board, which clears the history around content no file holds. The LiveView paths deliberately set neither signal, so a frame arriving on its own cannot put an unasked question in front of someone who left the application running beside a feed. The window title now shows the board and an asterisk, so the question asked on the way out has something on screen explaining it. ## The exit question Four answers, each a row carrying its own one-line consequence: Save, **Keep for next time**, Discard changes, Cancel. There is no prose above them — an earlier draft explained the four in two paragraphs, which made the reader map sentences onto buttons before they could act. The LiveView line appears only on a board that has a LiveView container. Keep is `IsDefault`, which decision 24 refused for the mouse mode offer. The difference is that there both answers changed something, so neither could be primed; here Keep decides nothing — the file is untouched and the board returns — so Enter landing on it is never the wrong outcome. Decision 30 records this so it does not read as an oversight to be tidied up. **Cancel stays, and LiveView is the reason.** Keep and Cancel look interchangeable, but a restored LiveView container comes back as its last frame and has to be reconnected by hand. Cancel is the only answer that keeps a feed live — which matters most in the case where the window gets closed by accident, mid-recording. The camera position is carried in the session to narrow what is left of the gap. ## One slot per running copy Each copy takes a slot named by a GUID and holds a lock file open while it runs, so two windows never write to the same files. Forbidding a second window was considered and rejected: two boards side by side is a real thing to want. A slot whose lock can be taken belonged to a copy that has gone, and its sidecar says whether it went on purpose — which is what separates a silent restore from an offer of recovery. Declining a recovery discards that slot, and the question says so. The alternative is asking the same person the same thing at every start for thirty days. ## Opening a board asks the slots too (#122) The startup offer only covers the newest slot, so without this the moment somebody most wants their recovered work — opening the very board they lost — is the moment the application says nothing. Every route into a board goes through `OpenPathAsync`, so the Open dialog, a drop, and a double-click in Explorer are covered once rather than three times. Yes takes the changes, No opens the saved file and discards them, Cancel opens neither and keeps the slot. ## Checks `dotnet build Whiteboard.sln -c Release` clean, both smoke harnesses pass. The Core harness covers the save point through the cases that actually come up — save, undo, redo, undo back onto the point, a different action at the same depth — plus the snapshot autosave writes, the sidecar round-trip and what it does with damaged input, and the clamping on a restored camera. Also walked through the built application rather than trusting the tests: - A crafted session slot restored on launch with the title reading `Untitled board *`, the camera where the sidecar put it, the slot re-homed into this copy's own before the old one was released, and the sidecar flipping to `exitedCleanly` on the way out. - For #122: a saved board holding one stroke, and a crashed slot holding five for that same file. Opening the file offered the changes; answering Yes gave `demo.wboard *` in the title and a board of five strokes, while **the file on disk still held one**. Killing the process then left a slot that correctly read as a crash. - One thing only that found: an empty lock file survived each launch, so `Prune` now sweeps orphans. `VersionPrefix` moves to 1.5.0 with the matching `CHANGELOG.md` section, and `site/guide.html` gets one paragraph. 🤖 Generated with [Claude Code](https://claude.com/claude-code) --------- Co-authored-by: Claude Opus 5 <noreply@anthropic.com>