# ADR 0047: Editor Authored-Asset Documents and Two-Phase Publication ## Status Accepted ## Context Material controls previously updated the viewport immediately but also wrote source when a pointer interaction ended. That publication could trigger file guards, Git refresh, watcher work, thumbnail invalidation, and whole-project processing on the editor frame thread. A slider release therefore behaved like an implicit save and could freeze the editor. Project RON files and registry metadata are already suitable authoritative source documents. The editor needs a fast, durable edit boundary without adding an opaque asset database or conflating editor-dirty documents with source-control status. ## Decision The editor owns an `AuthoredAssetDocumentStore` keyed by stable asset ID and document kind. It holds clean and current values, source path, loaded file revision, editor revision, publication error, recovery state, and derived-processing state for Materials, Material Instances, model import settings, Texture import settings, and project content defaults. Interactive controls mutate the current document and `blacksite_surface`'s stable-ID-keyed `LiveMaterialDocumentOverlay` in the same tick. `SurfaceMaterialCache` is the sole owner of project Material and Material Instance handles; resolution is overlay-first and disk-second. Controls perform no source write, watcher refresh, Git query, thumbnail invalidation, or derived processing, including when the pointer is released. Dirtiness is derived from `current != clean` and remains distinct from Git `MODIFIED`, `UNTRACKED`, and `CONFLICT` state. The cache never polls file metadata or reparses a project Material for every bound entity. Explicit Save and accepted watcher events invalidate the disk generation once; interactive overlay revisions mutate the existing cached handle in place. Imported glTF/FBX source materials stay on their AssetServer-owned path and do not enter the project-material resolver. `Ctrl+S` saves the last edited context. `Ctrl+Shift+S` and **File > Save All** save every dirty scene, authored asset document, and project setting. Source publication remains guarded and atomic. Registry-backed documents use a clean registry baseline plus per-document overlays so saving one setting cannot publish another unsaved setting. Successful source publication advances the clean value, then classifies its `DerivedProcessingImpact`. Scalar, color, emissive, shader-value, label, and render-state Material changes queue no derived work. ARM/ORM texture or channel changes queue material packing; Texture settings, model settings, and project defaults queue only their exact dependency closure. Packing signatures exclude scalar multipliers and are checked before image decoding so an existing content-addressed artifact can be reused. The previous valid runtime artifact remains authoritative until replacement publication succeeds; a processing failure is reported separately and does not make saved source dirty again. Stale job completions are ignored. Dirty asset documents receive editor-local recovery snapshots after two seconds of inactivity, with five generations retained outside `assets/`. Startup restoration never overwrites source: a changed source fingerprint restores the document as an external conflict. Guarded shutdown and project switching count scenes, assets, and project settings in the same Save All / Discard / Cancel decision. Returning a document exactly to its clean value retires any older recovery generation on the next editor tick. Startup also discards a recovery envelope whose value already matches authoritative source, covering a crash between the clean edit and that cleanup tick. ## Consequences - Parameter editing and pointer release stay frame-local and responsive. - Material and direct-base Instance users share one stable live handle authority instead of competing editor and renderer caches. - Saving source and generating derived artifacts are observable, independent phases. - The project remains plain, reviewable RON plus source assets; no asset binary database is added. - Unsaved editor state survives selection changes and can be recovered after a crash without affecting Git until the user saves. - Packaging and read-only processing validation must reject required pending or failed derived work rather than silently packaging stale content. - Import, extract, create, rename, move, and delete remain explicit immediate transactions because they create or remove project identity.