# ADR 0038: Non-Blocking Native Dialog Broker

## Status

Accepted

## Context

Blacksite opens native file, folder, Save As, and confirmation dialogs from editor workflows. Calling
the synchronous `rfd` API inside a Bevy/egui system stops window event processing until the dialog
returns. On Wayland compositors this can trigger an application-not-responding prompt even though
the native dialog is operating normally.

Path selection precedes stateful main-thread work such as scene serialization, imports, history
changes, prefab relinking, collaborative revision checks, and project activation. Moving those
operations to arbitrary worker threads would violate ECS ownership and weaken existing guards.

## Decision

The editor owns one `NativeDialogBroker` resource. A workflow submits native dialog construction and
a typed completion callback. The broker runs only the blocking native dialog wait on a worker thread,
then queues the result. An exclusive Bevy system drains the queue and invokes each completion exactly
once with `&mut World`.

Only one native dialog may be active. Additional requests fail immediately with explicit status.
Cancellation is delivered as the dialog API's empty or cancel result and remains non-mutating.
Initiating workflows capture stable entity IDs or paths and revalidate them before applying a result.

Native confirmation dialogs use the same broker. A requested close or project switch proceeds only
after the confirmation result and any required save have completed; an incomplete asynchronous save
pauses the transition rather than discarding content.

## Consequences

- Blacksite continues rendering and answering compositor pings while native dialogs are open.
- Project and ECS mutations remain on the Bevy main thread with their existing history, validation,
  and collaborative file-revision boundaries.
- Workflows split dialog acquisition from result application and handle stale initiating state.
- The one-dialog policy is intentionally global across the editor and Project Browser.
- A future platform-specific async backend can replace the worker without changing completions.
