BS-JD-219 - Editor asset dirty state and explicit save transactions #67

Closed
opened 2026-07-14 22:58:41 -04:00 by Rbanh · 1 comment
Owner

Goal

Introduce editor-owned dirty state for authored asset documents so interactive editing is immediate and filesystem publication happens only through an explicit Save/Save All transaction.

P0 reproduction

Editing a Material parameter updates the viewport in real time, but releasing the slider currently publishes the Material file. That wakes guarded file/collaboration/content processing and stalls the editor for roughly one minute or longer. Pointer release must remain an interactive operation and must not perform source-file publication or project-wide processing.

Product contract

  • Material, Material Instance, Texture import settings, model import settings, and future editable asset documents use one editor-owned document-state service.
  • Interactive controls mutate the in-memory document and live runtime preview only, then mark the document dirty.
  • Pointer release never writes authored files, refreshes Git/provider state, rescans content, repacks textures, rebuilds manifests, or invalidates unrelated thumbnails.
  • Explicit Save, Save All, project switch, and guarded shutdown own publication.
  • Saving validates the last loaded disk fingerprint, publishes all selected dirty documents transactionally, suppresses matching watcher events before writes, refreshes only affected runtime/catalog consumers, and establishes a clean checkpoint.
  • External changes keep the in-memory document dirty and present Reload / Save As / Cancel recovery; no silent overwrite.
  • Failed saves leave dirty state and live previews intact.
  • Content Browser cards/details, Material Library, and material-slot editors show the same compact dirty indicator.
  • Undoing to a saved document checkpoint clears dirty; editing away from it restores dirty where document history exists.
  • Ordinary loading remains read-only. Dirty state is editor session state, not a second asset format or a Git staging operation.

Implementation direction

  • Add a reusable authored-asset document store keyed by stable asset identity and document kind, holding loaded fingerprint, in-memory document, clean snapshot/checkpoint, dirty revision, diagnostics, and save status.
  • Keep format-specific serialization and post-save refresh hooks typed; do not introduce an opaque binary asset database.
  • Reuse the existing guarded atomic-write and collaboration conflict workflow at explicit save time.
  • Route the unified Material UI through this store and remove release-time material/instance draft save calls.
  • Integrate dirty assets into Save All, native close, project switch, and session recovery policy.
  • Record the architecture in a new ADR and update ADR 0037/Material and Content Workspace guidance where they link to this contract.

Acceptance criteria

  • Dragging and releasing Material/Instance parameters remains responsive and performs zero authored-file writes until explicit save.
  • The viewport and every shared user update during the interaction without material-handle growth.
  • Dirty badges are consistent in Content Browser, Material Library, and material-slot editors.
  • Explicit Save of one document and Save All publish guarded files transactionally and clear only successful dirty documents.
  • External edit, read-only, provider lock, partial serialization failure, cancel, and retry paths preserve correct dirty/live state.
  • Watcher instrumentation proves an edit/release produces no processing pass and a save suppresses only its authored events.
  • Close/project-switch Save All / Discard / Cancel includes dirty asset documents as well as scenes.
  • Restart/recovery behavior is explicit and tested; no silent loss or automatic source mutation.
  • Focused tests cover dirty/clean checkpoint transitions, save batching/rollback, conflict handling, and material live-handle reuse.
  • Native QA times continuous slider editing, release, explicit save, conflict recovery, and restart persistence with no editor stall.

Non-goals

This does not add a proprietary binary asset database, auto-stage Git files, auto-commit, or replace source RON/image/model files. Background texture/model processing remains separate and may run after explicit save when the saved document actually changes processing inputs.

Child of #59 and required by #65 before M2 closure.

Selected asynchronous processing semantics

  • Explicit Save publishes authoritative source first and clears source dirtiness only for successful documents.
  • Saved scalar/color/emissive/shader-value/label/render-state Material changes publish source without derived work. ARM/ORM texture or channel changes enqueue one coalesced packing job; Texture settings, model settings, and project defaults enqueue only their exact dependency closure.
  • The previous valid runtime artifact stays active until replacement publication succeeds; processing failure is reported separately and does not make saved source dirty again.
  • Stale worker results are ignored when a newer authored revision exists.
  • External watcher/startup refresh uses a coalescing worker queue. Matching authored-save events are suppressed by exact path while unrelated external events remain eligible for a later refresh.
  • Packaging is blocked while authored assets are dirty or required derived work is queued, processing, or failed; headless process-assets --check remains the read-only source/derived consistency gate.

Engineering implementation remains local and uncommitted. Native/visual acceptance is user-owned; keep this issue open until that acceptance and explicit publication approval.

Corrective implementation boundary

Live overlay/runtime resolver and conditional processing remain in #67. Modular Inspector/Content Browser composition and the permanent architecture-debt ratchet are tracked by #68.

## Goal Introduce editor-owned dirty state for authored asset documents so interactive editing is immediate and filesystem publication happens only through an explicit Save/Save All transaction. ## P0 reproduction Editing a Material parameter updates the viewport in real time, but releasing the slider currently publishes the Material file. That wakes guarded file/collaboration/content processing and stalls the editor for roughly one minute or longer. Pointer release must remain an interactive operation and must not perform source-file publication or project-wide processing. ## Product contract - Material, Material Instance, Texture import settings, model import settings, and future editable asset documents use one editor-owned document-state service. - Interactive controls mutate the in-memory document and live runtime preview only, then mark the document dirty. - Pointer release never writes authored files, refreshes Git/provider state, rescans content, repacks textures, rebuilds manifests, or invalidates unrelated thumbnails. - Explicit **Save**, **Save All**, project switch, and guarded shutdown own publication. - Saving validates the last loaded disk fingerprint, publishes all selected dirty documents transactionally, suppresses matching watcher events before writes, refreshes only affected runtime/catalog consumers, and establishes a clean checkpoint. - External changes keep the in-memory document dirty and present Reload / Save As / Cancel recovery; no silent overwrite. - Failed saves leave dirty state and live previews intact. - Content Browser cards/details, Material Library, and material-slot editors show the same compact dirty indicator. - Undoing to a saved document checkpoint clears dirty; editing away from it restores dirty where document history exists. - Ordinary loading remains read-only. Dirty state is editor session state, not a second asset format or a Git staging operation. ## Implementation direction - Add a reusable authored-asset document store keyed by stable asset identity and document kind, holding loaded fingerprint, in-memory document, clean snapshot/checkpoint, dirty revision, diagnostics, and save status. - Keep format-specific serialization and post-save refresh hooks typed; do not introduce an opaque binary asset database. - Reuse the existing guarded atomic-write and collaboration conflict workflow at explicit save time. - Route the unified Material UI through this store and remove release-time material/instance draft save calls. - Integrate dirty assets into Save All, native close, project switch, and session recovery policy. - Record the architecture in a new ADR and update ADR 0037/Material and Content Workspace guidance where they link to this contract. ## Acceptance criteria - [ ] Dragging and releasing Material/Instance parameters remains responsive and performs zero authored-file writes until explicit save. - [ ] The viewport and every shared user update during the interaction without material-handle growth. - [ ] Dirty badges are consistent in Content Browser, Material Library, and material-slot editors. - [ ] Explicit Save of one document and Save All publish guarded files transactionally and clear only successful dirty documents. - [ ] External edit, read-only, provider lock, partial serialization failure, cancel, and retry paths preserve correct dirty/live state. - [ ] Watcher instrumentation proves an edit/release produces no processing pass and a save suppresses only its authored events. - [ ] Close/project-switch Save All / Discard / Cancel includes dirty asset documents as well as scenes. - [ ] Restart/recovery behavior is explicit and tested; no silent loss or automatic source mutation. - [ ] Focused tests cover dirty/clean checkpoint transitions, save batching/rollback, conflict handling, and material live-handle reuse. - [ ] Native QA times continuous slider editing, release, explicit save, conflict recovery, and restart persistence with no editor stall. ## Non-goals This does not add a proprietary binary asset database, auto-stage Git files, auto-commit, or replace source RON/image/model files. Background texture/model processing remains separate and may run after explicit save when the saved document actually changes processing inputs. Child of #59 and required by #65 before M2 closure. ## Selected asynchronous processing semantics - Explicit Save publishes authoritative source first and clears source dirtiness only for successful documents. - Saved scalar/color/emissive/shader-value/label/render-state Material changes publish source without derived work. ARM/ORM texture or channel changes enqueue one coalesced packing job; Texture settings, model settings, and project defaults enqueue only their exact dependency closure. - The previous valid runtime artifact stays active until replacement publication succeeds; processing failure is reported separately and does not make saved source dirty again. - Stale worker results are ignored when a newer authored revision exists. - External watcher/startup refresh uses a coalescing worker queue. Matching authored-save events are suppressed by exact path while unrelated external events remain eligible for a later refresh. - Packaging is blocked while authored assets are dirty or required derived work is queued, processing, or failed; headless `process-assets --check` remains the read-only source/derived consistency gate. Engineering implementation remains local and uncommitted. Native/visual acceptance is user-owned; keep this issue open until that acceptance and explicit publication approval. ## Corrective implementation boundary Live overlay/runtime resolver and conditional processing remain in #67. Modular Inspector/Content Browser composition and the permanent architecture-debt ratchet are tracked by #68.
Rbanh added this to the M2 - Content workspace and asset pipeline milestone 2026-07-14 22:58:41 -04:00
Author
Owner

Candidate-ready — commit cf6eaba

The authored-document/save contract is implemented and verified. The matching UI states are pinned in the Material state catalog and adjusted color overlay.

  • Scalar, color, channel, and UV interaction updates the live overlay and stable cached GPU handle without source writes, processing jobs, Git refreshes, or release-time stalls.
  • Unsaved documents survive selection changes and remain distinct from Git and derived-processing state.
  • Contextual Save and Save All publish authoritative source transactionally; affected-only processing runs asynchronously and preserves the previous valid artifact.
  • Conflicts, recovery, shutdown, coalescing, stale completion, and processing failure paths have focused coverage.
  • Native interaction confirmed persistent live edits, responsive save behavior, dirty state, restart behavior, and no release-time material flicker.

Candidate gates passed: full workspace tests, strict all-target/all-feature Clippy, deterministic asset check, validators, packaging, documentation audit, and native Inspector/material scenarios.

## Candidate-ready — commit `cf6eaba` The authored-document/save contract is implemented and verified. The matching UI states are pinned in the [Material state catalog](https://git.spacetrainclubhouse.com/Falling-Metal-Interactive/Blacksite/src/commit/cf6eaba53473d2825d0109f5a18f44794af5bd48/docs/editor/evaluations/content-workspace-m2/penpot/material-components-states.svg) and [adjusted color overlay](https://git.spacetrainclubhouse.com/Falling-Metal-Interactive/Blacksite/src/commit/cf6eaba53473d2825d0109f5a18f44794af5bd48/docs/editor/evaluations/content-workspace-m2/penpot/color-picker-adjusted.svg). - Scalar, color, channel, and UV interaction updates the live overlay and stable cached GPU handle without source writes, processing jobs, Git refreshes, or release-time stalls. - Unsaved documents survive selection changes and remain distinct from Git and derived-processing state. - Contextual Save and Save All publish authoritative source transactionally; affected-only processing runs asynchronously and preserves the previous valid artifact. - Conflicts, recovery, shutdown, coalescing, stale completion, and processing failure paths have focused coverage. - Native interaction confirmed persistent live edits, responsive save behavior, dirty state, restart behavior, and no release-time material flicker. Candidate gates passed: full workspace tests, strict all-target/all-feature Clippy, deterministic asset check, validators, packaging, documentation audit, and native Inspector/material scenarios.
Rbanh closed this issue 2026-07-17 23:47:58 -04:00
Sign in to join this conversation.
No project
No Assignees
1 Participants
Notifications
Due Date
The due date is invalid or out of range. Please use the format 'yyyy-mm-dd'.

No due date set.

Dependencies

No dependencies set.

Reference: Falling-Metal-Interactive/Blacksite#67
No description provided.