[codex-analytics] preserve user thread source for exec threads (#23376)

## Why
- Follows #20949.
- The above moved `thread_source` attribution from the reducer to
explicit caller provided metadata
- The `codex exec` path still omitted this metadata, leaving
exec-created threads without `thread_source`


## What Changed
- Ensures exec threads are marked as user created (`thread_source =
"user"`)
- Preserves thread-source metadata in exec’s startup session event


## Verification
- Updated unit tests to validate exec `thread_source` propagation.
- `cargo +1.93.0 test -p codex-exec --manifest-path codex-rs/Cargo.toml`
- `cargo +1.93.1 build -p codex-cli --manifest-path codex-rs/Cargo.toml`
- Validated locally with a freshly built `codex exec` run:
  - Startup logs showed `thread_source: Some(User)`.
  - Rollout metadata recorded `"thread_source":"user"`.
This commit is contained in:
marksteinbrick-oai
2026-05-18 17:13:49 -07:00
committed by GitHub
parent a66712c95d
commit 5696167fe8
2 changed files with 47 additions and 2 deletions

View File

@@ -458,6 +458,25 @@ async fn thread_start_params_include_review_policy_when_auto_review_is_enabled()
);
}
#[tokio::test]
async fn thread_start_params_include_user_thread_source() {
let codex_home = tempdir().expect("create temp codex home");
let cwd = tempdir().expect("create temp cwd");
let config = ConfigBuilder::default()
.codex_home(codex_home.path().to_path_buf())
.fallback_cwd(Some(cwd.path().to_path_buf()))
.build()
.await
.expect("build config");
let params = thread_start_params_from_config(&config);
assert_eq!(
params.thread_source,
Some(codex_app_server_protocol::ThreadSource::User)
);
}
#[test]
fn active_profile_selection_uses_profile_id_only() {
let selection = permissions_selection_from_active_profile(ActivePermissionProfile::new(
@@ -548,6 +567,27 @@ async fn session_configured_from_thread_response_uses_permission_profile_from_co
);
}
#[tokio::test]
async fn session_configured_from_thread_response_preserves_thread_source() {
let codex_home = tempdir().expect("create temp codex home");
let cwd = tempdir().expect("create temp cwd");
let config = ConfigBuilder::default()
.codex_home(codex_home.path().to_path_buf())
.fallback_cwd(Some(cwd.path().to_path_buf()))
.build()
.await
.expect("build config");
let response = sample_thread_start_response();
let event = session_configured_from_thread_start_response(&response, &config)
.expect("build bootstrap session configured event");
assert_eq!(
event.thread_source,
Some(codex_protocol::protocol::ThreadSource::User)
);
}
fn sample_thread_start_response() -> ThreadStartResponse {
ThreadStartResponse {
thread: codex_app_server_protocol::Thread {
@@ -564,7 +604,7 @@ fn sample_thread_start_response() -> ThreadStartResponse {
cwd: test_path_buf("/tmp").abs(),
cli_version: "0.0.0".to_string(),
source: codex_app_server_protocol::SessionSource::Cli,
thread_source: None,
thread_source: Some(codex_app_server_protocol::ThreadSource::User),
agent_nickname: None,
agent_role: None,
git_info: None,