Journal Workspace transfers first; keep standalone state private and updates approved - #894
Conversation
Deploying mouseterm with
|
| Latest commit: |
17718de
|
| Status: | ✅ Deploy successful! |
| Preview URL: | https://72ad06b2.mouseterm.pages.dev |
| Branch Preview URL: | https://spec-cleanup-standalone.mouseterm.pages.dev |
dormouse-bot
left a comment
There was a problem hiding this comment.
A return whose reverse journal keeps failing now blocks quit with no bound. hand_back_arrival leaves the arrival Returning in the queue, and retry_arrival_return re-runs it every second until the write succeeds. While any record is queued, defer_quit (quit_state.rs) returns Some, and request_quit returns early with "transfer in progress; quit queued until settlement". It doesn't spawn its watchdog in that case. So if the sessions directory becomes permanently unwritable (disk full, read-only volume, revoked permission) while a Workspace is being handed back, every Quit trigger is swallowed and only a force-kill ends the app. Before this PR the record left the queue whatever the write result.
Blocking quit here doesn't seem to protect anything. A failed reverse write leaves the initial journal record in place, unchanged per commit_arrival_return_with. restore_arrivals already recovers that record into the target on the next launch. Bounding the retry chain, or letting a deferred quit proceed past a Returning arrival whose write keeps failing, would keep recovery without trapping the user. This is a design call for whoever owns the "retain a failed return as an in-flight blocker" rule in standalone.md.
The original change answered two local disk-write failures with about 1,000 lines of new state: four arrival phases, commit_*_with helpers, 5x1s return retries, RecoveryPending parking, CloseCommit with snapshot rollback, retainWindowAfterFailure/retryLatest, and new teardown-modal states. Both failures need the app-data write itself to fail (disk full, antivirus holding the rename), and the transfer case also needs a crash inside a sub-second window. Meanwhile the machinery added ways to get stuck: an undismissable close-commit-uncertain modal with saves refused, RecoveryPending blocking closes and transfers at both windows until restart, a drag that now failed when the settled-journal write did, and (until review caught it) a quit that could hang forever. Close retention also kept a window open behind a Retry modal after the user asked to close it, where the old outcome was only that window reopening on the next launch with nothing lost. Return to the base behaviour; the following commits keep the small, independent fixes and replace the transfer guard with journal-first. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…be locked On Windows the Node stores' file modes are no-ops, so a refused DACL on the state directory used to leave burrowToken written under the inherited ACL with only a warning. prepare_owner_only_dir now publishes a directory only after restrict_to_owner succeeds; otherwise the sidecar gets no directory and keeps that state in memory. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
runUpdateCheck awaited the 5 s delay and the network-policy read, then called check() regardless, so an update approved through Check now in that window was offered for approval a second time. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Node's --import needs a file URL on Windows, and kill('SIGTERM') there
terminates the child without running its JS handler, so the agent-browser
harness test delivers the signal over IPC on win32. standalone.md named the
retired AGENT_BROWSER_TIMEOUT (30s); the constant is BROWSER_REQUEST_TIMEOUT
(40s).
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Destroyed used to drop the save refusal, but a save_session dispatched before Destroyed can take the disk lock after it and recreate the removed snapshot. Labels are never reused within a process, so the refusal now lasts until exit. The debounced geometry flush now rechecks that refusal under the same disk lock close removal holds, so a flush captured before the close cannot write the geometry file back. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
begin_arrival moved the shells to the target and only then wrote sessions/arrivals.json, logging a failed write and carrying on, so a crash after that failure restored the in-flight Workspace in neither window. journal_and_open_arrival now writes the record first and refuses the move with nothing changed if the write fails. The write runs outside the arrivals lock, whose waits reach the main thread, so admission is checked again under that lock and a refusal there withdraws the record. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Audit the standalone and updater specs against both sides of the bridge. Journal Workspace transfers before changing ownership, fence late snapshot and geometry writes after a Window closes, and fall back to memory when private Burrow/recovery storage cannot be prepared. Preserve an approved updater download when a delayed launch check completes.
The specs retain the shipped transfer and close behavior and point to the native implementation. Validation: current macOS/Windows platform checks, standalone smoke test, and bot review pass; updater regressions cover the delayed check. Stacked on #893.