mirror of
https://github.com/openai/codex.git
synced 2026-06-01 19:02:59 +00:00
Include auto-review rollout in feedback uploads (#20064)
## Summary - include the live auto-review trunk rollout when `/feedback` uploads logs - upload that attachment as `auto-review-rollout-<parent-thread-id>.jsonl` so it is distinguishable from the parent rollout - show the same auto-review attachment name in the TUI consent popup ## Scope - this only covers the live cached auto-review trunk for the current parent thread - it does not add durable historical parent->auto-review lookup - it does not add persisted rollout support for ephemeral parallel review forks ## UI <img width="599" height="185" alt="Screenshot 2026-04-28 at 1 17 18 PM" src="https://github.com/user-attachments/assets/6a0e79c2-5d21-4702-8a89-f765778bc9e9" /> ## Validation - `cargo test -p codex-core cached_guardian_subagent_exposes_its_rollout_path` - `cargo test -p codex-feedback` - `cargo test -p codex-app-server` - `cargo test -p codex-tui feedback_upload_consent_popup_snapshot` - `cargo test -p codex-tui feedback_good_result_consent_popup_includes_connectivity_diagnostics_filename` ## Known unrelated local failures - `cargo test -p codex-core` currently fails in the pre-existing proxy env snapshot test `tools::runtimes::tests::maybe_wrap_shell_lc_with_snapshot_keeps_user_proxy_env_when_proxy_inactive` - `cargo test -p codex-tui` currently hits pre-existing `status::*` snapshot drift unrelated to this change ## Follow-Up - persist parallel auto-review fork sessions so /feedback can include their rollout history too - attach each persisted fork as its own clearly named file, for example auto-review-rollout-<parent-thread-id>-fork <n>.jsonl, instead of merging multiple Guardian sessions into one attachment - keep the same live-session-only scope initially; durable historical parent -> auto-review lookup can remain a separate decision if we later need feedback from resumed sessions
This commit is contained in:
@@ -338,12 +338,18 @@ pub struct FeedbackSnapshot {
|
||||
pub thread_id: String,
|
||||
}
|
||||
|
||||
pub struct FeedbackAttachmentPath {
|
||||
pub path: PathBuf,
|
||||
/// Optional filename to use for the uploaded attachment instead of `path`'s basename.
|
||||
pub attachment_filename_override: Option<String>,
|
||||
}
|
||||
|
||||
pub struct FeedbackUploadOptions<'a> {
|
||||
pub classification: &'a str,
|
||||
pub reason: Option<&'a str>,
|
||||
pub tags: Option<&'a BTreeMap<String, String>>,
|
||||
pub include_logs: bool,
|
||||
pub extra_attachment_paths: &'a [PathBuf],
|
||||
pub extra_attachment_paths: &'a [FeedbackAttachmentPath],
|
||||
pub session_source: Option<SessionSource>,
|
||||
pub logs_override: Option<Vec<u8>>,
|
||||
}
|
||||
@@ -501,7 +507,7 @@ impl FeedbackSnapshot {
|
||||
fn feedback_attachments(
|
||||
&self,
|
||||
include_logs: bool,
|
||||
extra_attachment_paths: &[PathBuf],
|
||||
extra_attachment_paths: &[FeedbackAttachmentPath],
|
||||
logs_override: Option<Vec<u8>>,
|
||||
) -> Vec<sentry::protocol::Attachment> {
|
||||
use sentry::protocol::Attachment;
|
||||
@@ -526,22 +532,28 @@ impl FeedbackSnapshot {
|
||||
});
|
||||
}
|
||||
|
||||
for path in extra_attachment_paths {
|
||||
let data = match fs::read(path) {
|
||||
for attachment_path in extra_attachment_paths {
|
||||
let data = match fs::read(&attachment_path.path) {
|
||||
Ok(data) => data,
|
||||
Err(err) => {
|
||||
tracing::warn!(
|
||||
path = %path.display(),
|
||||
path = %attachment_path.path.display(),
|
||||
error = %err,
|
||||
"failed to read log attachment; skipping"
|
||||
);
|
||||
continue;
|
||||
}
|
||||
};
|
||||
let filename = path
|
||||
.file_name()
|
||||
.map(|s| s.to_string_lossy().to_string())
|
||||
.unwrap_or_else(|| "extra-log.log".to_string());
|
||||
let filename = attachment_path
|
||||
.attachment_filename_override
|
||||
.clone()
|
||||
.unwrap_or_else(|| {
|
||||
attachment_path
|
||||
.path
|
||||
.file_name()
|
||||
.map(|s| s.to_string_lossy().to_string())
|
||||
.unwrap_or_else(|| "extra-log.log".to_string())
|
||||
});
|
||||
attachments.push(Attachment {
|
||||
buffer: data,
|
||||
filename,
|
||||
@@ -676,6 +688,10 @@ mod tests {
|
||||
fn feedback_attachments_gate_connectivity_diagnostics() {
|
||||
let extra_filename = format!("codex-feedback-extra-{}.jsonl", ThreadId::new());
|
||||
let extra_path = std::env::temp_dir().join(&extra_filename);
|
||||
let extra_attachment_path = FeedbackAttachmentPath {
|
||||
path: extra_path.clone(),
|
||||
attachment_filename_override: None,
|
||||
};
|
||||
fs::write(&extra_path, "rollout").expect("extra attachment should be written");
|
||||
|
||||
let snapshot_with_diagnostics = CodexFeedback::new()
|
||||
@@ -688,7 +704,7 @@ mod tests {
|
||||
|
||||
let attachments_with_diagnostics = snapshot_with_diagnostics.feedback_attachments(
|
||||
/*include_logs*/ true,
|
||||
std::slice::from_ref(&extra_path),
|
||||
std::slice::from_ref(&extra_attachment_path),
|
||||
Some(vec![1]),
|
||||
);
|
||||
|
||||
@@ -715,6 +731,7 @@ mod tests {
|
||||
);
|
||||
let attachments_without_diagnostics = CodexFeedback::new()
|
||||
.snapshot(/*session_id*/ None)
|
||||
.with_feedback_diagnostics(FeedbackDiagnostics::default())
|
||||
.feedback_attachments(/*include_logs*/ true, &[], Some(vec![1]));
|
||||
|
||||
assert_eq!(
|
||||
|
||||
Reference in New Issue
Block a user