# ADR 0042: Guarded Editor Shutdown And Document Savepoints

## Status

Accepted

## Context

Bevy's default native-window policy closes a requested window and exits after the final window is
gone. That policy bypasses Blacksite's scene-tab and project-switch confirmations, so a compositor
close request could silently discard dirty authored work. Reading `WindowCloseRequested` in another
system is insufficient because Bevy's default close system has its own message cursor and still
despawns the window.

Scene dirtiness was also independent of editor history. Every undo or redo marked the active scene
dirty, even when undo restored the exact state that had last loaded or saved. Undo depth alone is
not a valid savepoint: editor commands contain runtime entity IDs and are intentionally cleared when
tabs switch, while saves may establish a clean point in the middle of a timeline.

## Decision

- The full editor disables Bevy's automatic close-on-request behavior. The game and Project Browser
  keep their existing native-window policy.
- One editor shutdown coordinator owns native window close, **File > Quit**, project switching, and
  programmatic editor-exit requests. It coalesces duplicate requests and is the only normal path
  authorized to emit `AppExit`.
- Final authorization runs in a dedicated main schedule after Bevy's `Last` schedule. The guard
  rechecks dirty scene state after every editor authoring system, then clean-session persistence
  runs after that finalizer in the same post-`Last` schedule.
- A clean editor exits immediately. Dirty scene tabs enter one non-blocking native decision with
  explicit **Save All**, **Discard**, and **Cancel** actions. Save completion, including an untitled
  tab's Save As picker, is applied on the main thread. The coordinator exits only after every dirty
  tab saves or the user explicitly discards; cancel or failure retains the live session.
- Clean-session persistence accepts only an exit authorized by the coordinator. Crashes, forced
  termination, and unguarded `AppExit` retain the abnormal-session marker.
- Every scene tab owns a canonical authored-content checkpoint established by a successful load or
  save. The projection uses stable actor IDs, stable parent actor IDs, sorted component identities,
  and scene composition; it excludes transient Bevy entity numbers and runtime hydration.
- A committed edit marks the active tab dirty. Successful undo or redo compares the current
  canonical authored projection with that tab's checkpoint. Equality clears the dirty marker;
  divergence sets it. Failed saves and recovery restores do not advance the checkpoint.
- Editor command stacks remain active-document runtime state and are still cleared on tab switches.
  Checkpoint ownership belongs to the document tab, so dirty truth survives those clears.

## Consequences

- Native close can no longer silently discard authored scene tabs, and the editor remains responsive
  while confirmation or Save As dialogs are open.
- A normal exit requires an explicit editor-owned authorization. New code must request shutdown
  through the coordinator instead of writing `AppExit` directly.
- Undoing to the last saved authored state clears title and tab dirty indicators, including after a
  save at nonzero history depth. Redo or a divergent branch marks the document dirty again.
- Reconciliation serializes the authored projection after undo and redo. This is more work than a
  depth comparison, but it is bounded to explicit history navigation and remains correct across
  direct non-history repairs, entity respawns, and tab switches.
- Operating-system process kill and power loss cannot be confirmed; recovery and abnormal-session
  handling remain the safety boundary for those cases.
