diff --git a/crates/op-orchestrator/src/validation.rs b/crates/op-orchestrator/src/validation.rs index 775eb14f3..b94e23da1 100644 --- a/crates/op-orchestrator/src/validation.rs +++ b/crates/op-orchestrator/src/validation.rs @@ -416,7 +416,8 @@ pub struct ValidationSummary { /// 6. Emit `ValidationDone`. Return `Ok(ValidationSummary)`. /// /// Returns `Err(OrchestratorError::Aborted)` when the abort flag is set before -/// any vision round starts. +/// a vision round starts. Once `ValidationStarted` has been emitted, every +/// return path also emits terminal `ValidationDone`. /// /// `reference_screenshot` is currently always `None` from within this function; /// D1's host wiring will thread host-side reference images through. @@ -472,6 +473,7 @@ pub fn run_post_generation_validation( for round in 1..=MAX_VALIDATION_ROUNDS { // 5a: abort check — if set before this round starts, return early. if abort.is_set() { + on_progress(Progress::ValidationDone { total_applied }); return Err(OrchestratorError::Aborted); } diff --git a/crates/op-orchestrator/src/validation_tests_c2.rs b/crates/op-orchestrator/src/validation_tests_c2.rs index b021ce1f2..e4502972c 100644 --- a/crates/op-orchestrator/src/validation_tests_c2.rs +++ b/crates/op-orchestrator/src/validation_tests_c2.rs @@ -413,7 +413,7 @@ fn tc6_fix_history_dedup_second_occurrence_dropped() { ); } -/// TC-7: abort fires before the loop → Err(Aborted), no rounds. +/// TC-7: abort before the loop → Err(Aborted), no rounds, terminal done event. #[test] fn tc7_abort_stops_loop() { let mut sink = sink_with_n_nodes(40); @@ -442,6 +442,17 @@ fn tc7_abort_stops_loop() { .any(|p| matches!(p, Progress::ValidationRoundStarted { .. })), "no round should start after abort" ); + assert!( + matches!( + events.as_slice(), + [ + Progress::ValidationStarted, + Progress::ValidationPreCheckDone { .. }, + Progress::ValidationDone { total_applied: 0 } + ] + ), + "an aborted validation phase must still terminate: {events:?}" + ); } /// TC-8: all stub providers with node-count >= 30 → ValidationDone, 0 rounds, 0 applied.