# 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 entity delta, exact undo-group delta, dirty state, committed phase | | Cancel or commit failure | No authored entity delta, no new history, prior dirty state, canceled phase | | Blocked start | Commit closure never runs; authored state, history, and dirty state are unchanged | | Preview helpers | No helper component remains after commit or cancel | | Undoable commit | `assert_undo_redo_round_trip` restores both initial and committed 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 operator entry point or the same production commit/cancel function used by its input system. 4. Call `assert_committed`, `assert_canceled`, or `assert_blocked` with the expected authored and undo deltas. 5. For helpers, call `assert_no_helpers::`. For undoable work, project the meaningful state through `assert_undo_redo_round_trip`. 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, commit failure rollback, blocked no-op | | Asset placement | Commit, dirty state, single undo, authored spawn round trip | | Sub-asset placement | Missing dependency commit failure leaves no side effects | | Texture/material assignment | Multi-actor grouped undo; missing material failure; empty-selection block | | Draw Brush | Full modal-state cancel; decomposed multi-brush grouped commit and round trip | | Brush CSG | Pending-preview cancel; merge commit/deletion grouped round trip | | Brush clip and element gizmo | Clip grouped geometry round trip; Escape rollback and helper cleanup | | Transform gizmo finalization | Multi-target continuous edit grouped into one undo command | Terrain strokes and physics-settle sessions are roadmap tools, not current production operators. Their implementation tickets must add harness fixtures before those tools can pass their own exit gates; Gitea issue BS-JD-502 remains the umbrella until that coverage exists.