# ADR 0026: Stable Scene Composition And Active Document

## Status

Accepted

## Context

One monolithic dynamic scene does not scale to daily content production. Multiple authors and
disciplines need geometry, lighting, gameplay, and set dressing to remain separable, but Bevy
`Entity` identifiers are allocated at runtime and cannot identify actors or ownership across files.
The editor also materializes one authored document into the live ECS world, where hydration,
selection, history, PIE, and rendering operate.

## Decision

- Persist one reflected `SceneComposition` resource in each dynamic scene. It owns a stable
  `scene_id` and project-relative `SubsceneReference` entries with stable reference IDs plus loaded
  and locked flags.
- Reject absolute/escaping paths, empty or duplicate reference IDs, missing targets, duplicate
  scene IDs, and cyclic graphs through the same `scene` crate validator used by editor load,
  project inspection, and `cargo validate-levels`.
- Keep one scene tab materialized in the ECS world. Inactive tabs retain normalized authored RON,
  path, dirty state, and recovery location in memory. Switching serializes the outgoing authored
  roots and hydrates the incoming snapshot.
- Tag hydrated subscene actors with runtime-only `ComposedSceneMember` ownership. They participate
  in the active composition and PIE but are excluded from the owner scene's save and recovery
  payload.
- Treat an unloaded reference as absent from the world. Loaded references inherit their authored
  visibility; locked references enter the hierarchy's existing read-only lock path. Nested locks
  propagate downward.
- Composition add/remove/load/lock changes are ordinary undoable history commands. Because existing
  entity-edit history stores runtime entity IDs, activating another tab clears that tab's history
  instead of retaining commands that could target rematerialized entities incorrectly.

## Consequences

- Cross-scene identity is stable and reviewable without leaking runtime entity IDs into files.
- PIE, viewport rendering, and build validation see the same active materialized composition.
- Saved dirty tabs, including inactive ones, receive independent bounded recovery generations.
- Legacy scenes load without a composition resource using a deterministic path-derived identity;
  their next save promotes that identity into the scene resource.
- The open tab set is session-local; safe restart resumes the last active authored scene. Unsaved
  untitled tabs remain outside automatic recovery until a future session schema can restore them
  without guessing a destination.
- Preserving entity-edit undo stacks across tab materialization requires stable-ID history commands
  and is future work; clearing them is explicit and safe.
