4.4 KiB
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.