# Operator Regression Testing Blacksite editor operators and modal tools must preserve the authored scene across preview, commit, cancellation, validation failure, and undo/redo. Tests share `operators::test_harness::OperatorInvariantHarness` so a new tool proves the same contract instead of inventing local assertions. ## Required invariants Every production operator test must cover the paths it exposes: | Path | Required proof | |------|----------------| | Commit | Expected authored projection, exact undo-group delta, dirty state, stable operator ID, committed phase | | Zero-history commit | Authored projection and prior dirty state remain unchanged | | Cancel or commit failure | Exact authored projection restored, no new history, prior dirty state, stable operator ID, terminal canceled/blocked phase | | Blocked start | Commit closure never runs; authored state, history, and dirty state are unchanged | | Preview failure | Cancel finalizer runs, authored state is restored, and helpers are removed | | Preview helpers | No helper component remains after commit or cancel | | Undoable commit | `assert_undo_redo_round_trip` restores both initial and committed semantic projections | | Continuous edit | The entire interaction creates one history command, not one per frame or target | The harness intentionally fails with the invariant name in the assertion message. Tests may add domain assertions, but should not replace these shared lifecycle checks. ## Adding a tool test 1. Build a minimal `World` with `ActiveOperator`, `EditorHistory`, and `SceneIo`. Add tool-specific selection/resources and `SelectedEntity` when history helpers update selection. 2. Capture `OperatorInvariantHarness` immediately before starting the operation. 3. Run the real dispatch path or production finalizer used by the input system. Do not duplicate its state transition in the test. 4. Call `assert_committed`, `assert_canceled`, or `assert_blocked` with the expected authored and undo deltas, then `assert_status` with the stable operator ID and terminal phase. 5. For helpers, call `assert_no_helpers::`. For undoable work, project the meaningful state through `assert_undo_redo_round_trip`; use `assert_projection_unchanged` for no-op paths. Do not satisfy a lifecycle test by constructing an `EditorCommand` and checking only its label. The test must mutate a world and prove restoration. ## Current coverage | Workflow | Coverage | |----------|----------| | Generic `EditorOperator` | Commit cleanup, preview/commit failure rollback, blocked no-op, terminal ID/phase | | Palette and registered commands | Typed immediate commit versus modal preview ownership; failed CSG start terminates | | Selection and scene commands | Atomic Group Selection across repeated undo/redo; grouped Reset Lighting and Project Sun history | | Asset workflows | Asset/sub-asset placement; material/texture group assignment; audio/animation assignment and incompatible targets | | Viewport material drop | Exact renderer slot/primitive/brush-face preview, cancel, commit, cleanup, undo, and redo | | Draw Brush and CSG | Modal cancel; decomposed commit; CSG validation/read-only block, cancel, grouped commit, and deleted-brush restoration | | Brush clip and element gizmo | Production finalizers, geometry round trip, Escape rollback, and helper cleanup | | Terrain sculpt and paint | Multi-dab grouped commit, no-op release, commit failure rollback, cancel, clean-view interruption, and resource cleanup | | Physics placement | Prerequisite block, no-op commit, exact cancel, real settle commit, multi-selection grouping, helper cleanup, undo, and redo | | Transform gizmo finalization | Actual tracker finalizer, continuous multi-target grouping, no-op release, and missing-primary survivor rollback | The shared harness covers formal operators and multi-frame modal paths. Atomic inspector and history mutations that do not own `ActiveOperator` use focused typed history tests with equivalent semantic projection and undo/redo assertions.