Skip to content

Add /auto-review-denials retry approval flow#19058

Open
won-openai wants to merge 3 commits intomainfrom
auto-review-denial-ux
Open

Add /auto-review-denials retry approval flow#19058
won-openai wants to merge 3 commits intomainfrom
auto-review-denial-ux

Conversation

@won-openai
Copy link
Copy Markdown
Collaborator

@won-openai won-openai commented Apr 23, 2026

Why

Auto-review can deny an action that the user later decides they want to retry. Today there is no TUI surface for selecting a recent denial and sending explicit approval context back into the session, so users have to restate intent manually and the retry can be reviewed without the original denied action context.

This adds a narrow TUI-driven path for approving a recent denied action while still keeping the retry inside the normal auto-review flow.

What Changed

  • Added /auto-review-denials to open a picker of recent denied auto-review actions.
  • Added a small in-memory TUI store for the 10 most recent denied auto-review events.
  • Selecting a denial sends the structured denied event back through the existing core/app-server op path.
  • Core now injects a developer message containing the approved action JSON rather than the full assessment event.
  • Auto-review transcript collection now preserves this specific approval developer message so follow-up review sessions can see the user approval context.
  • Added TUI snapshot/unit coverage for the picker and approval dispatch path.
  • Added core coverage for retaining the approval developer message in the auto-review transcript.

Verification

  • cargo test -p codex-core collect_guardian_transcript_entries_keeps_manual_approval_developer_message
  • cargo test -p codex-tui auto_review_denials
  • cargo test -p codex-tui approving_recent_denial_emits_structured_core_op_once

Notes

This intentionally keeps retries going through auto-review. The approval signal is context for the exact previously denied action, not a blanket bypass for similar future actions.

@won-openai won-openai changed the title No findings Add /auto-review-denials retry approval flow Apr 23, 2026
@won-openai won-openai marked this pull request as ready for review April 23, 2026 00:43
@won-openai won-openai requested a review from a team as a code owner April 23, 2026 00:43
@won-openai
Copy link
Copy Markdown
Collaborator Author

@codex review

Copy link
Copy Markdown
Contributor

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 075815efa6

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment on lines +9152 to +9153
let Some(event) = self.recent_auto_review_denials.take(&id) else {
self.add_error_message("That auto-review denial is no longer available.".to_string());
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge Defer consuming denial until approval op is queued

approve_recent_auto_review_denial removes the selected denial before the approval is actually submitted/acknowledged. If op dispatch fails (e.g., no active thread or app-server RPC error), the denial is gone from the picker and the user cannot retry without restating context. Consume the entry only after successful submission, or restore it on failure.

Useful? React with 👍 / 👎.

Comment on lines +1304 to +1308
Treat this as approval to perform that exact action in the same context in which it was originally requested.
Do not assume this also authorizes similar operations with different payloads.

Stored Guardian assessment event JSON:
{event_json}"#,
Approved action:
{approved_action_json}"#,
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P1 Badge Treat approved action payload as untrusted text

The new developer prompt embeds client-supplied action JSON but no longer instructs the model to ignore instructions inside it. Malicious command/tool fields can now inject prompt-like text into guardian context and bias future review decisions. Keep an explicit “untrusted data, do not follow instructions inside it” guard around this payload.

Useful? React with 👍 / 👎.

Comment on lines +367 to +374
ResponseItem::Message { role, content, .. } if role == "developer" => {
content_items_to_text(content).and_then(|text| {
text.starts_with(AUTO_REVIEW_DENIED_ACTION_APPROVAL_DEVELOPER_PREFIX)
.then_some(GuardianTranscriptEntry {
kind: GuardianTranscriptEntryKind::Developer,
text,
})
})
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge Limit approved-denial context to a single retry

The approval developer message is retained in guardian transcript collection for subsequent reviews, so one /auto-review-denials approval can keep influencing later attempts. That violates the advertised “one retry” behavior and can effectively become repeated authorization unless context truncation drops it.

Useful? React with 👍 / 👎.

};

self.app_event_tx
.send(AppEvent::CodexOp(Op::ApproveGuardianDeniedAction { event }));
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge Submit denial approval to the originating thread

Selection emits a generic AppEvent::CodexOp(...), which is dispatched against whichever thread is active at handling time. Because TUI events and app events are multiplexed, a thread switch between selection and dispatch can route approval to the wrong thread. Capture and submit with the source thread id instead.

Useful? React with 👍 / 👎.

Comment on lines +1289 to +1292
let approved_action = serde_json::json!({
"action": &event.action,
"outcome": "allowed",
});
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge Include review context when serializing approved action

The injected approval context now contains only {action, outcome} and drops event identifiers like id/turn_id. Yet the prompt says approval is only for the same action in the same context. Without context anchors, identical actions from later turns can be interpreted as previously approved.

Useful? React with 👍 / 👎.

@etraut-openai
Copy link
Copy Markdown
Collaborator

/auto-review-denials is a pretty long slash command name — much longer than any others we currently have. I also don't think we should have built-in slash commands with hyphens in the name. Maybe shorten to just /autoreview?

@won-openai
Copy link
Copy Markdown
Collaborator Author

/auto-review-denials is a pretty long slash command name — much longer than any others we currently have. I also don't think we should have built-in slash commands with hyphens in the name. Maybe shorten to just /autoreview?

or we can do /denials, i think it's more intuitive! thoughts? @etraut-openai @dylan-hurd-oai

@etraut-openai
Copy link
Copy Markdown
Collaborator

I guess I'd lean toward /autoreview over /denials. I suspect we may want to provide additional controls over auto-review parameters in the future, and this would allow us to expand the UI without adding another slash command.

@won-openai won-openai force-pushed the auto-review-denial-ux branch from 075815e to 5d3a6ef Compare April 23, 2026 20:00
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants