[codex-analytics] stop sending codex error subreason (#27060)

## Summary
- stop emitting `codex_error_subreason` on `codex_turn_event`
- remove the transient analytics fact plumbing that copied
`CodexErr::InvalidRequest(String)` into the event
- update analytics serialization coverage accordingly

## Why
`codex_error_subreason` is a free-form copy of `InvalidRequest(String)`,
including raw provider 400 bodies in some paths. That makes it unsafe as
an analytics field because it can carry user-derived or sensitive text.

## Validation
- `just fmt`
- `just test -p codex-analytics`
This commit is contained in:
rhan-oai
2026-06-08 14:29:06 -07:00
committed by GitHub
Unverified
parent 123cf62a48
commit ee6c91d5cf
4 changed files with 0 additions and 32 deletions
@@ -3318,7 +3318,6 @@ fn turn_event_serializes_expected_shape() {
status: Some(TurnStatus::Completed),
turn_error: None,
codex_error_kind: None,
codex_error_subreason: None,
codex_error_http_status_code: None,
steer_count: Some(0),
total_tool_call_count: None,
@@ -3391,7 +3390,6 @@ fn turn_event_serializes_expected_shape() {
"status": "completed",
"turn_error": null,
"codex_error_kind": null,
"codex_error_subreason": null,
"codex_error_http_status_code": null,
"steer_count": 0,
"total_tool_call_count": null,
@@ -4098,10 +4096,6 @@ async fn turn_lifecycle_emits_failed_turn_event() {
payload["event_params"]["codex_error_kind"],
json!("invalid_request")
);
assert_eq!(
payload["event_params"]["codex_error_subreason"],
json!("unknown turn environment id `env-2`")
);
assert_eq!(
payload["event_params"]["codex_error_http_status_code"],
json!(null)
-1
View File
@@ -803,7 +803,6 @@ pub(crate) struct CodexTurnEventParams {
pub(crate) status: Option<TurnStatus>,
pub(crate) turn_error: Option<CodexErrorInfo>,
pub(crate) codex_error_kind: Option<CodexErrKind>,
pub(crate) codex_error_subreason: Option<String>,
pub(crate) codex_error_http_status_code: Option<u16>,
pub(crate) steer_count: Option<usize>,
pub(crate) total_tool_call_count: Option<usize>,
-24
View File
@@ -30,9 +30,6 @@ use codex_protocol::request_permissions::RequestPermissionsResponse;
use serde::Serialize;
use std::path::PathBuf;
const INVALID_REQUEST_SUBREASON_MAX_BYTES: usize = 512;
const INVALID_REQUEST_SUBREASON_TRUNCATION_SUFFIX: &str = "...";
#[derive(Clone, Debug, PartialEq, Eq, Serialize)]
pub struct AcceptedLineFingerprint {
pub path_hash: String,
@@ -182,7 +179,6 @@ pub(crate) enum CodexErrKind {
#[derive(Clone)]
pub(crate) struct TurnCodexError {
pub(crate) kind: CodexErrKind,
pub(crate) subreason: Option<String>,
pub(crate) http_status_code: Option<u16>,
}
@@ -190,26 +186,6 @@ impl TurnCodexError {
fn from_codex_err(error: &CodexErr) -> Self {
Self {
kind: error.into(),
subreason: match error {
CodexErr::InvalidRequest(message) => {
// InvalidRequest can contain raw provider response bodies, so bound the
// analytics copy without changing the source CodexErr.
let subreason = if message.len() <= INVALID_REQUEST_SUBREASON_MAX_BYTES {
message.clone()
} else {
let truncated_len = message.floor_char_boundary(
INVALID_REQUEST_SUBREASON_MAX_BYTES
.saturating_sub(INVALID_REQUEST_SUBREASON_TRUNCATION_SUFFIX.len()),
);
format!(
"{}{INVALID_REQUEST_SUBREASON_TRUNCATION_SUFFIX}",
&message[..truncated_len]
)
};
Some(subreason)
}
_ => None,
},
http_status_code: error.http_status_code_value(),
}
}
-1
View File
@@ -2470,7 +2470,6 @@ fn codex_turn_event_params(
status: completed.status,
turn_error: completed.turn_error,
codex_error_kind: codex_error.map(|error| error.kind),
codex_error_subreason: codex_error.and_then(|error| error.subreason.clone()),
codex_error_http_status_code: codex_error.and_then(|error| error.http_status_code),
steer_count: Some(turn_state.steer_count),
total_tool_call_count: Some(turn_state.tool_counts.total),