Blacksite/docs/adr/0042-guarded-editor-shutdown-and-document-savepoints.md

3.9 KiB

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.
  • ADR 0047 extends the guarded decision to dirty asset documents and project settings while derived processing remains resumable after source save.