Improve Guardian report diagnostics (#42033)

## Why

Reports from a large thread tree can exceed the rollout attachment limit, making
the threads involved in a failed Guardian review harder to diagnose.

## What changed

- Prioritize descendants with retained failed reviews when selecting bounded
  report rollouts, while always preserving the reported thread.
- Include each selected thread's available Guardian trunk rollout alongside its
  conversation rollout.
- Add a thread index attachment with selected filenames, bounded omission details,
  retained failure threads, and the process-wide discarded-record count.
- Link failed-review records to their reviewed turn and target item when available.

## Testing

- Cover failed-review prioritization, bounded omission metadata, discarded-record
  accounting, and turn/item linkage in Guardian report records.

GitOrigin-RevId: ae7916c27a3c279e899cd5a6ead8a4b7e0cc26a1
This commit is contained in:
jif authored and copyberry committed 2026-09-01 11:14:20 +00:00
1 parent 8209978616
commit 2e5ee418ad
13 files changed
+293 -66

No files matched your search

+3 -3
View File
@@ -1385,9 +1385,9 @@ async fn guardian_denial_rejects_tool_call_with_rationale(
assert!(guardian_request.body_contains_text(&command));
assert_eq!(guardian_request.body_json()["model"], "gpt-5.6-luna");
let feedback =
codex_feedback::guardian_review_failures_attachment(&[test.session_configured.thread_id])
.expect("failed Guardian review");
let feedback = codex_feedback::guardian_review_failures(&[test.session_configured.thread_id])
.attachment
.expect("failed Guardian review");
let record: serde_json::Value = serde_json::from_slice(&feedback.buffer)?;
assert!(
guardian_request.body_contains_text(record["action"].as_str().expect("reviewed action"))
@@ -327,12 +327,15 @@ async fn guardian_subagent_review_preserves_late_root_user_authorization() -> Re
.thread_manager
.list_agent_subtree_thread_ids(root_thread_id)
.await?;
let feedback = codex_feedback::guardian_review_failures_attachment(&feedback_thread_ids)
.expect("failed worker review");
let failures = codex_feedback::guardian_review_failures(&feedback_thread_ids);
assert_eq!(failures.thread_ids, vec![worker_thread_id]);
let feedback = failures.attachment.expect("failed worker review");
let record: Value = serde_json::from_slice(&feedback.buffer)?;
assert_eq!(
json!({
"reviewed_thread_id": record["reviewed_thread_id"],
"reviewed_turn_id": record["reviewed_turn_id"],
"target_item_id": record["target_item_id"],
"reviewer_thread_id": record["reviewer_thread_id"],
"status": record["status"],
"decision": serde_json::from_str::<Value>(
@@ -341,6 +344,8 @@ async fn guardian_subagent_review_preserves_late_root_user_authorization() -> Re
}),
json!({
"reviewed_thread_id": worker_thread_id,
"reviewed_turn_id": worker_request.body_json()["client_metadata"]["turn_id"],
"target_item_id": WORKER_CALL_ID,
"reviewer_thread_id": guardian_review.single_request().body_json()["client_metadata"]["thread_id"],
"status": "denied",
"decision": {