Preserve Guardian authorization evidence until request budgeting (#44570)

## Why

Transcript limits could shorten user instructions or omit later messages before Guardian evaluated the complete request budget, losing restrictions or prior approvals even when they would fit.

## What changed

- Keep user messages and manual approvals complete and in source order through transcript collection and retention.
- Preserve historical instructions while synchronous review can still compact history. If the final request still cannot fit, discard optional evidence before shortening older historical entries with truncation markers, preserving later restrictions where possible.
- Warn that shortened instructions and approvals are incomplete and that missing evidence does not authorize actions.
- Let asynchronous review defer to synchronous review when complete instructions exceed its budget.

## Testing

Add coverage for complete instruction retention, approval and restriction ordering, marked truncation of oversized Unicode text, compaction before truncation, and asynchronous fallback when instructions do not fit.

GitOrigin-RevId: e6159e876231347986b937ee7e07f944b83bfbe6
This commit is contained in:
felixxia-oai authored and copyberry committed 2026-09-10 16:02:36 +00:00
1 parent 9c4879f3a5
commit 287e4f7dbf
21 files changed
+575 -335

No files matched your search

+14 -3
View File
@@ -321,8 +321,13 @@ pub(crate) async fn run_turn(
return Ok(None);
}
if crate::guardian::is_basic_session_source(&turn_context.session_source)
&& let Err(error) =
crate::guardian::finalize_guardian_input(&sess, &first_step_context, &mut input).await
&& let Err(error) = crate::guardian::finalize_guardian_input(
&sess,
&first_step_context,
&mut input,
codex_guardian_context::HistoryTruncation::Preserve,
)
.await
{
// Token-budget compaction resets history, which can discard the evidence
// referenced by a pending delta review. Leave budget failures unreusable.
@@ -349,7 +354,13 @@ pub(crate) async fn run_turn(
world_state = sess
.record_context_updates_and_set_reference_context_item(first_step_context.as_ref())
.await?;
crate::guardian::finalize_guardian_input(&sess, &first_step_context, &mut input).await?;
crate::guardian::finalize_guardian_input(
&sess,
&first_step_context,
&mut input,
codex_guardian_context::HistoryTruncation::Allow,
)
.await?;
}
let mut can_drain_pending_input = input.is_empty();
if run_hooks_and_record_inputs(