From 435d1b3f19e20b96dc3a0eb63c73bb7f213d1e27 Mon Sep 17 00:00:00 2001 From: jif Date: Mon, 5 Oct 2026 09:30:39 +0000 Subject: [PATCH] Gate Guardian continuation tests on classifier request capture (#51061) ## Why Snapshot classifier requests can arrive out of order, so continuation tests need to keep the next tool blocked until the current tool's classifier request has been captured and checked. ## What changed Gate every mock Guardian review in high-risk review continuation scenarios. Release each review after checking the corresponding classifier request, preserving the ordering needed by the existing assertions. GitOrigin-RevId: 9e52acd2bb1ce2fb71100fe0e1b92304d29e9634 --- codex-rs/app-server/tests/suite/v2/guardian_v2.rs | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) diff --git a/codex-rs/app-server/tests/suite/v2/guardian_v2.rs b/codex-rs/app-server/tests/suite/v2/guardian_v2.rs index 9902b14ecd..bfd3d8e6ac 100644 --- a/codex-rs/app-server/tests/suite/v2/guardian_v2.rs +++ b/codex-rs/app-server/tests/suite/v2/guardian_v2.rs @@ -183,6 +183,7 @@ struct MockResponsesState { root_thread_id: Mutex>, allow_luna: Notify, allow_guardian_review: Notify, + gate_each_guardian_review: bool, classification_completed: Notify, truncation_recorded: Notify, context_metric_bounds: Mutex>>, @@ -422,7 +423,7 @@ async fn parent_response( .expect("Guardian request lock should not be poisoned") .push(request.clone()); let review_number = state.guardian_reviews.fetch_add(1, Ordering::SeqCst); - if review_number == 0 { + if review_number == 0 || state.gate_each_guardian_review { state.allow_guardian_review.notified().await; } let review_outcome = if state.late_root_restriction && review_number > 0 { @@ -743,6 +744,7 @@ async fn guardian_v2_routes_scoped_tool_approvals( + usize::from(late_root_restriction); let responses_state = Arc::new(MockResponsesState { luna_score, + gate_each_guardian_review: review_continuations && matches!(risk, GuardianRisk::High), invalid_classification: matches!(risk, GuardianRisk::InvalidResponse), fail_after_classification, review_outcome, @@ -1482,6 +1484,11 @@ async fn guardian_v2_routes_scoped_tool_approvals( { wait_for_guardian_reviews(responses_state.as_ref(), expected_guardian_reviews).await?; } + if responses_state.gate_each_guardian_review { + // Snapshot classifiers can arrive out of order. Keep the next tool blocked until + // this tool's classifier request has been captured and checked. + responses_state.allow_guardian_review.notify_one(); + } responses_state.allow_luna.notify_one(); if review_continuations { let third_sample = wait_for_luna_request(responses_state.as_ref(), /*index*/ 2).await?; @@ -1538,6 +1545,9 @@ async fn guardian_v2_routes_scoped_tool_approvals( "snapshot and failed-stream recovery must start with fresh history" ); } + if responses_state.gate_each_guardian_review { + responses_state.allow_guardian_review.notify_one(); + } responses_state.allow_luna.notify_one(); } } else {