Recover missing Guardian root instructions in acceptance order (#43472)

## Why

Incomplete retained checkpoints can omit root user instructions that still survive in live history. Queued input can also reach model history after a later-accepted answer, so recording order cannot reliably order grants and restrictions for subagent authorization reviews.

## What changed

- Reconcile retained evidence with surviving local user messages using source identity and persisted acceptance order, including answers present only in the checkpoint.
- Preserve checkpoint gaps and mark evidence incomplete when recovered instructions lack an order or conflict with an existing order.
- Restore the input-order counter from surviving local metadata so new instructions sort after recovered evidence, even without a retained checkpoint.

## Testing

Add unit coverage for source matching, acceptance ordering, persistent gaps, conflicting orders, and counter restoration. Extend subagent authorization tests to cover checkpoint resume, queued approvals, missing sources, and a subsequent revocation.

GitOrigin-RevId: 8bfbfd2c797d725796187e5cecf7f3f11a5f3380
This commit is contained in:
felixxia-oai authored and copyberry committed 2026-09-07 13:40:29 +00:00
1 parent db0568dbbb
commit aa12ab45df
12 files changed
+582 -31

No files matched your search

@@ -21,7 +21,7 @@ const MAX_INSTRUCTION_TOKENS: usize = 900;
fn render_retained_instructions(context: &RetainedContext) -> Vec<String> {
let mut complete = context.user_messages_complete();
let mut fragments = Vec::new();
for (order, entry) in context.ordered_entries().enumerate() {
for (order, (_, entry)) in context.ordered_entries().enumerate() {
let RetainedContextEntry::UserMessage(message) = entry else {
continue;
};
@@ -20,7 +20,7 @@ pub struct RenderedVerifiedAnswers {
pub fn render_verified_answers(context: &RetainedContext) -> RenderedVerifiedAnswers {
let mut complete = context.verified_answers_complete();
let mut fragments = Vec::new();
for (order, entry) in context.ordered_entries().enumerate() {
for (order, (_, entry)) in context.ordered_entries().enumerate() {
let RetainedContextEntry::VerifiedAnswer(answer) = entry else {
continue;
};