feat(tui): route employee feedback follow-ups to internal link (#10198)

## Problem
OpenAI employees were sent to the public GitHub issue flow after
`/feedback`, which is the wrong follow-up path internally.

## Mental model
After feedback upload completes, we render a follow-up link/message.
That link should be audience-aware but must not change the upload
pipeline itself.

## Non-goals
- Changing how feedback is captured or uploaded
- Changing external user behavior

## Tradeoffs
We detect employees via the authenticated account email suffix
(`@openai.com`). If the email is unavailable (e.g., API key auth), we
default to the external behavior.

## Architecture
- Introduce `FeedbackAudience` and thread it from `App` -> `ChatWidget`
-> `FeedbackNoteView`
- Gate internal messaging/links on `FeedbackAudience::OpenAiEmployee`
- Internal follow-up link is now `http://go/codex-feedback-internal`
- External GitHub URL remains byte-for-byte identical

## Observability
No new telemetry; this only changes rendered follow-up instructions.

## Tests
- `just fmt`
- `cargo test -p codex-tui --lib`
This commit is contained in:
Josh McKinney
2026-01-29 18:12:46 -08:00
committed by GitHub
parent a9cf449a80
commit 36f2fe8af9
5 changed files with 154 additions and 33 deletions

View File

@@ -8,6 +8,7 @@ use super::*;
use crate::app_event::AppEvent;
use crate::app_event::ExitMode;
use crate::app_event_sender::AppEventSender;
use crate::bottom_pane::FeedbackAudience;
use crate::bottom_pane::LocalImageAttachment;
use crate::history_cell::UserHistoryCell;
use crate::test_backend::VT100Backend;
@@ -716,6 +717,7 @@ async fn helpers_are_available_and_do_not_panic() {
models_manager: thread_manager.get_models_manager(),
feedback: codex_feedback::CodexFeedback::new(),
is_first_run: true,
feedback_audience: FeedbackAudience::External,
model: Some(resolved_model),
otel_manager,
};
@@ -837,6 +839,7 @@ async fn make_chatwidget_manual(
last_separator_elapsed_secs: None,
last_rendered_width: std::cell::Cell::new(None),
feedback: codex_feedback::CodexFeedback::new(),
feedback_audience: FeedbackAudience::External,
current_rollout_path: None,
external_editor_state: ExternalEditorState::Closed,
};
@@ -2309,6 +2312,7 @@ async fn collaboration_modes_defaults_to_code_on_startup() {
models_manager: thread_manager.get_models_manager(),
feedback: codex_feedback::CodexFeedback::new(),
is_first_run: true,
feedback_audience: FeedbackAudience::External,
model: Some(resolved_model.clone()),
otel_manager,
};
@@ -2353,6 +2357,7 @@ async fn experimental_mode_plan_applies_on_startup() {
models_manager: thread_manager.get_models_manager(),
feedback: codex_feedback::CodexFeedback::new(),
is_first_run: true,
feedback_audience: FeedbackAudience::External,
model: Some(resolved_model.clone()),
otel_manager,
};