From 8e079cccf645bd281aeded5b7245b37a8fc6ce7c Mon Sep 17 00:00:00 2001 From: Yvette Carlisle Date: Mon, 15 Jun 2026 02:15:54 +0800 Subject: [PATCH] {"schema":"decodex/commit/1","summary":"Persist upstream Radar review artifacts","authority":"manual"} --- .../github/bundles/openai-codex-pr-26662.json | 304 ++++++++++++++++++ .../github/bundles/openai-codex-pr-28122.json | 296 +++++++++++++++++ .../github/impact/openai-codex-pr-26662.json | 47 +++ .../github/impact/openai-codex-pr-28122.json | 47 +++ .../review-queue/openai-codex-latest.json | 199 +++++++----- .../reviews/openai-codex-pr-26662.review.json | 86 +++++ .../reviews/openai-codex-pr-28122.review.json | 88 +++++ .../openai-codex-pr-26662.json | 53 +++ .../openai-codex-pr-28122.json | 53 +++ 9 files changed, 1087 insertions(+), 86 deletions(-) create mode 100644 artifacts/github/bundles/openai-codex-pr-26662.json create mode 100644 artifacts/github/bundles/openai-codex-pr-28122.json create mode 100644 artifacts/github/impact/openai-codex-pr-26662.json create mode 100644 artifacts/github/impact/openai-codex-pr-28122.json create mode 100644 artifacts/github/reviews/openai-codex-pr-26662.review.json create mode 100644 artifacts/github/reviews/openai-codex-pr-28122.review.json create mode 100644 artifacts/github/social-candidates/openai-codex-pr-26662.json create mode 100644 artifacts/github/social-candidates/openai-codex-pr-28122.json diff --git a/artifacts/github/bundles/openai-codex-pr-26662.json b/artifacts/github/bundles/openai-codex-pr-26662.json new file mode 100644 index 000000000..95cd7833f --- /dev/null +++ b/artifacts/github/bundles/openai-codex-pr-26662.json @@ -0,0 +1,304 @@ +{ + "analysis_mode": "pr_first", + "commits": [ + { + "author": "btraut-openai", + "committed_at": "2026-06-07T21:43:30Z", + "message": "feat(app-server): filter threads by parent", + "sha": "68567deb6f6e9227662c9558d37ff3e280a2b377", + "url": "https://github.com/openai/codex/commit/68567deb6f6e9227662c9558d37ff3e280a2b377" + }, + { + "author": "btraut-openai", + "committed_at": "2026-06-07T21:43:37Z", + "message": "refactor(app-server): source parent filter from spawn edges", + "sha": "724cd58bf6ed04ffaf8ab8520c951a5518f3161a", + "url": "https://github.com/openai/codex/commit/724cd58bf6ed04ffaf8ab8520c951a5518f3161a" + }, + { + "author": "btraut-openai", + "committed_at": "2026-06-07T22:49:09Z", + "message": "codex: fix CI failure on PR #26662", + "sha": "c2f877a1d0c5dbab82f5d7fcb4c591b90e9541f8", + "url": "https://github.com/openai/codex/commit/c2f877a1d0c5dbab82f5d7fcb4c591b90e9541f8" + }, + { + "author": "btraut-openai", + "committed_at": "2026-06-07T22:28:34Z", + "message": "docs(app-server): clarify parent thread listing", + "sha": "e06ed34720737e1657c74fdc466972c5fdda5ac4", + "url": "https://github.com/openai/codex/commit/e06ed34720737e1657c74fdc466972c5fdda5ac4" + }, + { + "author": "btraut-openai", + "committed_at": "2026-06-08T01:24:47Z", + "message": "fix(app-server): preserve explicit thread list filters", + "sha": "eaeb92854e2d6da708558a8f0b81ff7cacdfd569", + "url": "https://github.com/openai/codex/commit/eaeb92854e2d6da708558a8f0b81ff7cacdfd569" + }, + { + "author": "btraut-openai", + "committed_at": "2026-06-10T06:42:04Z", + "message": "fix(app-server): address parent thread listing feedback", + "sha": "4c1fbf28545273cd4ba9402a4065171b646824f9", + "url": "https://github.com/openai/codex/commit/4c1fbf28545273cd4ba9402a4065171b646824f9" + }, + { + "author": "btraut-openai", + "committed_at": "2026-06-11T16:47:37Z", + "message": "fix(state): preserve indexed thread pagination", + "sha": "28d35a99eff66cf06742933e4a45fde47fb927d5", + "url": "https://github.com/openai/codex/commit/28d35a99eff66cf06742933e4a45fde47fb927d5" + }, + { + "author": "btraut-openai", + "committed_at": "2026-06-12T16:02:02Z", + "message": "Address thread list review feedback", + "sha": "ba23593c751b155e4a86d2e6c24125a4b177a8c6", + "url": "https://github.com/openai/codex/commit/ba23593c751b155e4a86d2e6c24125a4b177a8c6" + }, + { + "author": "btraut-openai", + "committed_at": "2026-06-12T19:49:25Z", + "message": "Revert thread list tuple pagination", + "sha": "95d0018d71d9b15ccac883561abd1d408cf0f875", + "url": "https://github.com/openai/codex/commit/95d0018d71d9b15ccac883561abd1d408cf0f875" + }, + { + "author": "btraut-openai", + "committed_at": "2026-06-14T06:47:26Z", + "message": "docs(app-server): clarify parent thread filter scope", + "sha": "688537c78d85337d3bc70e80a7e74fcfe11da6ce", + "url": "https://github.com/openai/codex/commit/688537c78d85337d3bc70e80a7e74fcfe11da6ce" + } + ], + "default_branch": "main", + "docs_refs": [ + "codex-rs/app-server/README.md" + ], + "examples_refs": [], + "extracted_flags": [ + "SQL", + "JSONL", + "JSONRPCR", + "DEFAULT_READ_TIMEOUT", + "JSONRPCE", + "CONFLICT", + "NOTHING", + "FROM", + "AND", + "SELECT", + "WHERE" + ], + "files": [ + { + "additions": 11, + "deletions": 21, + "patch_excerpt": "@@ -5,50 +5,40 @@ import type { SortDirection } from \"./SortDirection\";\n import type { ThreadSortKey } from \"./ThreadSortKey\";\n import type { ThreadSourceKind } from \"./ThreadSourceKind\";\n \n-export type ThreadListParams = {\n-/**\n+export type ThreadListParams = {/**\n * Opaque pagination cursor returned by a previous call.\n */\n-cursor?: string | null,\n-/**\n+cursor?: string | null, /**\n * Optional page size; defaults to a reasonable server-side value.\n */\n-limit?: number | null,\n-/**\n+limit?: number | null, /**\n * Optional sort key; defaults to created_at.\n */\n-sortKey?: ThreadSortKey | null,\n-/**\n+sortKey?: ThreadSortKey | null, /**\n * Optional sort direction; defaults to descending (newest first).\n */\n-sortDirection?: SortDirection | null,\n-/**\n+sortDirection?: SortDirection | null, /**\n * Optional provider filter; when set, only sessions recorded under these\n * providers are re...", + "path": "codex-rs/app-server-protocol/schema/typescript/v2/ThreadListParams.ts", + "status": "modified" + }, + { + "additions": 1, + "deletions": 0, + "patch_excerpt": "@@ -603,6 +603,7 @@ client_request_definitions! {\n },\n ThreadList => \"thread/list\" {\n params: v2::ThreadListParams,\n+ inspect_params: true,\n serialization: None,\n response: v2::ThreadListResponse,\n },", + "path": "codex-rs/app-server-protocol/src/protocol/common.rs", + "status": "modified" + }, + { + "additions": 5, + "deletions": 1, + "patch_excerpt": "@@ -1022,7 +1022,7 @@ pub struct ThreadRollbackResponse {\n pub thread: Thread,\n }\n \n-#[derive(Serialize, Deserialize, Debug, Clone, PartialEq, JsonSchema, TS)]\n+#[derive(Serialize, Deserialize, Debug, Clone, PartialEq, JsonSchema, TS, ExperimentalApi)]\n #[serde(rename_all = \"camelCase\")]\n #[ts(export_to = \"v2/\")]\n pub struct ThreadListParams {\n@@ -1062,6 +1062,10 @@ pub struct ThreadListParams {\n /// Optional substring filter for the extracted thread title.\n #[ts(optional = nullable)]\n pub search_term: Option,\n+ /// Optional direct parent thread filter.\n+ #[experimental(\"thread/list.parentThreadId\")]\n+ #[ts(optional = nullable)]\n+ pub parent_thread_id: Option,\n }\n \n #[derive(Serialize, Deserialize, Debug, Clone, PartialEq, JsonSchema, TS)]", + "path": "codex-rs/app-server-protocol/src/protocol/v2/thread.rs", + "status": "modified" + }, + { + "additions": 1, + "deletions": 0, + "patch_excerpt": "@@ -1129,6 +1129,7 @@ async fn thread_list(endpoint: &Endpoint, config_overrides: &[String], limit: u3\n model_providers: None,\n source_kinds: None,\n archived: None,\n+ parent_thread_id: None,\n cwd: None,\n use_state_db_only: false,\n search_term: None,", + "path": "codex-rs/app-server-test-client/src/lib.rs", + "status": "modified" + }, + { + "additions": 19, + "deletions": 1, + "patch_excerpt": "@@ -134,7 +134,7 @@ Example with notification opt-out:\n - `thread/resume` — reopen an existing thread by id so subsequent `turn/start` calls append to it. Accepts the same permission override rules as `thread/start`.\n - `thread/fork` — fork an existing thread into a new thread id by copying the stored history; if the source thread is currently mid-turn, the fork records the same interruption marker as `turn/interrupt` instead of inheriting an unmarked partial turn suffix. The returned `thread.forkedFromId` points at the source thread when known. Accepts `ephemeral: true` for an in-memory temporary fork, emits `thread/started` (including the current `thread.status`), and auto-subscribes you to turn/item events for the new thread. Experimental clients can pass `excludeTurns: true` when they plan to page fork history via `thread/turns/list` instead of receiving the full turn array immediate...", + "path": "codex-rs/app-server/README.md", + "status": "modified" + }, + { + "additions": 17, + "deletions": 1, + "patch_excerpt": "@@ -15,6 +15,7 @@ struct ThreadListFilters {\n cwd_filters: Option>,\n search_term: Option,\n use_state_db_only: bool,\n+ parent_thread_id: Option,\n }\n \n fn collect_resume_override_mismatches(\n@@ -1874,8 +1875,14 @@ impl ThreadRequestProcessor {\n cwd,\n use_state_db_only,\n search_term,\n+ parent_thread_id,\n } = params;\n let cwd_filters = normalize_thread_list_cwd_filters(cwd)?;\n+ let parent_thread_id = parent_thread_id\n+ .as_deref()\n+ .map(ThreadId::from_string)\n+ .transpose()\n+ .map_err(|err| invalid_request(format!(\"invalid parent thread id: {err}\")))?;\n \n let requested_page_size = limit\n .map(|value| value as usize)\n@@ -1899,6 +1906,7 @@ impl ThreadRequestProcessor {\n cwd_filters,\n ...", + "path": "codex-rs/app-server/src/request_processors/thread_processor.rs", + "status": "modified" + }, + { + "additions": 7, + "deletions": 0, + "patch_excerpt": "@@ -338,6 +338,7 @@ async fn external_agent_config_import_creates_session_rollouts() -> Result<()> {\n cwd: None,\n use_state_db_only: false,\n search_term: None,\n+ parent_thread_id: None,\n })\n .await?;\n let response: JSONRPCResponse = timeout(\n@@ -514,6 +515,7 @@ required = true\n cwd: None,\n use_state_db_only: false,\n search_term: None,\n+ parent_thread_id: None,\n })\n .await?;\n let response: JSONRPCResponse = timeout(\n@@ -601,6 +603,7 @@ async fn external_agent_config_import_accepts_detected_session_payload_after_res\n cwd: None,\n use_state_db_only: false,\n search_term: None,\n+ parent_thread_id: None,\n })\n .await?;\n let response: JSONRPCResponse = timeout(\n@@ -688,6 +691,7 @@ async fn external_...", + "path": "codex-rs/app-server/tests/suite/v2/external_agent_config.rs", + "status": "modified" + }, + { + "additions": 1, + "deletions": 0, + "patch_excerpt": "@@ -132,6 +132,7 @@ async fn thread_delete_with_non_local_thread_store_does_not_create_local_persist\n cwd: None,\n use_state_db_only: false,\n search_term: None,\n+ parent_thread_id: None,\n },\n })\n .await?", + "path": "codex-rs/app-server/tests/suite/v2/remote_thread_store.rs", + "status": "modified" + }, + { + "additions": 1, + "deletions": 0, + "patch_excerpt": "@@ -71,6 +71,7 @@ async fn list_threads(mcp: &mut TestAppServer) -> Result {\n cwd: None,\n use_state_db_only: false,\n search_term: None,\n+ parent_thread_id: None,\n })\n .await?;\n let list_resp: JSONRPCResponse = timeout(", + "path": "codex-rs/app-server/tests/suite/v2/thread_fork.rs", + "status": "modified" + }, + { + "additions": 197, + "deletions": 0, + "patch_excerpt": "@@ -35,6 +35,7 @@ use codex_protocol::protocol::RolloutItem;\n use codex_protocol::protocol::RolloutLine;\n use codex_protocol::protocol::SessionSource as CoreSessionSource;\n use codex_protocol::protocol::SubAgentSource;\n+use codex_state::DirectionalThreadSpawnEdgeStatus;\n use core_test_support::responses;\n use pretty_assertions::assert_eq;\n use std::cmp::Reverse;\n@@ -95,6 +96,7 @@ async fn list_threads_with_sort(\n cwd: None,\n use_state_db_only: false,\n search_term: None,\n+ parent_thread_id: None,\n })\n .await?;\n let resp: JSONRPCResponse = timeout(\n@@ -105,6 +107,37 @@ async fn list_threads_with_sort(\n to_response::(resp)\n }\n \n+async fn list_threads_for_parent(\n+ mcp: &mut TestAppServer,\n+ parent_thread_id: ThreadId,\n+ cursor: Option,\n+ limit: u32,\n+ model_providers: Option Result<()>\n cwd: None,\n use_state_db_only: false,\n search_term: None,\n+ parent_thread_id: None,\n },\n })\n .await?\n@@ -960,6 +961,7 @@ async fn thread_name_set_is_reflected_in_read_list_and_resume() -> Result<()> {\n cwd: None,\n use_state_db_only: false,\n search_term: None,\n+ parent_thread_id: None,\n })\n .await?;\n let list_resp: JSONRPCResponse = timeout(", + "path": "codex-rs/app-server/tests/suite/v2/thread_read.rs", + "status": "modified" + }, + { + "additions": 1, + "deletions": 0, + "patch_excerpt": "@@ -88,6 +88,7 @@ async fn has_threads(store: &LocalThreadStore, archived: bool) -> io::Result Vec {\n allowed_sources: Vec::new(),\n model_providers: None,\n cwd_filters: None,\n+ parent_thread_id: None,\n archived: false,\n search_term: None,\n use_state_db_only: false,", + "path": "codex-rs/core/src/realtime_context.rs", + "status": "modified" + }, + { + "additions": 2, + "deletions": 0, + "patch_excerpt": "@@ -1444,6 +1444,7 @@ async fn resolve_resume_thread_id(\n model_providers: model_providers.clone(),\n source_kinds: Some(all_thread_source_kinds()),\n archived: Some(false),\n+ parent_thread_id: None,\n cwd: None,\n use_state_db_only: false,\n search_term: None,\n@@ -1509,6 +1510,7 @@ async fn resolve_resume_thread_id(\n model_providers: model_providers.clone(),\n source_kinds: Some(all_thread_source_kinds()),\n archived: Some(false),\n+ parent_thread_id: None,\n cwd: None,\n use_state_db_only: false,\n search_term: Some(session_id.to_string()),", + "path": "codex-rs/exec/src/lib.rs", + "status": "modified" + }, + { + "additions": 4, + "deletions": 0, + "patch_excerpt": "@@ -376,6 +376,7 @@ impl RolloutRecorder {\n allowed_sources,\n model_providers,\n cwd_filters,\n+ /*parent_thread_id*/ None,\n archived,\n search_term,\n )\n@@ -484,6 +485,7 @@ impl RolloutRecorder {\n allowed_sources,\n model_providers,\n cwd_filters,\n+ /*parent_thread_id*/ None,\n archived,\n search_term,\n )\n@@ -512,6 +514,7 @@ impl RolloutRecorder {\n allowed_sources,\n model_providers,\n cwd_filters,\n+ /*parent_thread_id*/ None,\n archived,\n search_term,\n )\n@@ -608,6 +611,7 @@ impl RolloutRecorder {\n allowed_sources,\n model_providers,\n ...", + "path": "codex-rs/rollout/src/recorder.rs", + "status": "modified" + }, + { + "additions": 29, + "deletions": 22, + "patch_excerpt": "@@ -363,6 +363,7 @@ pub async fn list_threads_db(\n allowed_sources: &[SessionSource],\n model_providers: Option<&[String]>,\n cwd_filters: Option<&[PathBuf]>,\n+ parent_thread_id: Option,\n archived: bool,\n search_term: Option<&str>,\n ) -> Option {\n@@ -391,29 +392,35 @@ pub async fn list_threads_db(\n .map(|cwd| normalize_cwd_for_state_db(cwd))\n .collect::>()\n });\n- match ctx\n- .list_threads(\n- page_size,\n- codex_state::ThreadFilterOptions {\n- archived_only: archived,\n- allowed_sources: allowed_sources.as_slice(),\n- model_providers: model_providers.as_deref(),\n- cwd_filters: normalized_cwd_filters.as_deref(),\n- anchor: anchor.as_ref(),\n- sort_key: match sort_key {\n- ...", + "path": "codex-rs/rollout/src/state_db.rs", + "status": "modified" + }, + { + "additions": 123, + "deletions": 1, + "patch_excerpt": "@@ -398,11 +398,32 @@ ON CONFLICT(child_thread_id) DO NOTHING\n &self,\n page_size: usize,\n filters: ThreadFilterOptions<'_>,\n+ ) -> anyhow::Result {\n+ self.list_threads_matching(page_size, filters, /*parent_thread_id*/ None)\n+ .await\n+ }\n+\n+ /// List direct children of `parent_thread_id` using persisted spawn edges.\n+ pub async fn list_threads_by_parent(\n+ &self,\n+ page_size: usize,\n+ parent_thread_id: ThreadId,\n+ filters: ThreadFilterOptions<'_>,\n+ ) -> anyhow::Result {\n+ self.list_threads_matching(page_size, filters, Some(parent_thread_id))\n+ .await\n+ }\n+\n+ async fn list_threads_matching(\n+ &self,\n+ page_size: usize,\n+ filters: ThreadFilterOptions<'_>,\n+ parent_thread_id: Option,\n ) -> anyhow::Resul...", + "path": "codex-rs/state/src/runtime/threads.rs", + "status": "modified" + }, + { + "additions": 75, + "deletions": 2, + "patch_excerpt": "@@ -48,6 +48,10 @@ mod tests {\n use crate::ListTurnsParams;\n use crate::SortDirection;\n use crate::StoredTurnItemsView;\n+ use crate::ThreadPersistenceMetadata;\n+ use crate::ThreadSortKey;\n+ use codex_protocol::models::BaseInstructions;\n+ use codex_protocol::protocol::SessionSource;\n \n #[tokio::test]\n async fn default_turn_pagination_methods_return_unsupported() {\n@@ -90,6 +94,68 @@ mod tests {\n }\n ));\n }\n+\n+ #[tokio::test]\n+ async fn list_threads_filters_by_parent_thread_id() {\n+ let store = InMemoryThreadStore::default();\n+ let parent_thread_id = ThreadId::default();\n+ let child_thread_id =\n+ ThreadId::from_string(\"00000000-0000-0000-0000-000000000001\").expect(\"valid thread id\");\n+ let unrelated_thread_id =\n+ ThreadId::from_string(\"00000000-0000-0000-0000-000000000002\").expect...", + "path": "codex-rs/thread-store/src/in_memory.rs", + "status": "modified" + }, + { + "additions": 1, + "deletions": 0, + "patch_excerpt": "@@ -110,6 +110,7 @@ mod tests {\n cwd_filters: None,\n archived: true,\n search_term: None,\n+ parent_thread_id: None,\n use_state_db_only: false,\n })\n .await", + "path": "codex-rs/thread-store/src/local/archive_thread.rs", + "status": "modified" + }, + { + "additions": 2, + "deletions": 4, + "patch_excerpt": "@@ -25,7 +25,7 @@ pub(super) async fn create_thread(\n model_provider_id: params.metadata.model_provider.clone(),\n generate_memories: matches!(params.metadata.memory_mode, ThreadMemoryMode::Enabled),\n };\n- let recorder = RolloutRecorder::new(\n+ RolloutRecorder::new(\n &config,\n RolloutRecorderParams::new(\n params.thread_id,\n@@ -41,7 +41,5 @@ pub(super) async fn create_thread(\n .await\n .map_err(|err| ThreadStoreError::Internal {\n message: format!(\"failed to initialize local thread recorder: {err}\"),\n- })?;\n-\n- Ok(recorder)\n+ })\n }", + "path": "codex-rs/thread-store/src/local/create_thread.rs", + "status": "modified" + }, + { + "additions": 32, + "deletions": 0, + "patch_excerpt": "@@ -116,6 +116,32 @@ pub(super) async fn list_rollout_threads(\n sort_key: codex_rollout::ThreadSortKey,\n sort_direction: codex_rollout::SortDirection,\n ) -> ThreadStoreResult {\n+ if let Some(parent_thread_id) = params.parent_thread_id {\n+ let page = codex_rollout::state_db::list_threads_db(\n+ state_db.as_deref(),\n+ config.codex_home.as_path(),\n+ params.page_size,\n+ cursor,\n+ sort_key,\n+ sort_direction,\n+ params.allowed_sources.as_slice(),\n+ params.model_providers.as_deref(),\n+ params.cwd_filters.as_deref(),\n+ Some(parent_thread_id),\n+ params.archived,\n+ params.search_term.as_deref(),\n+ )\n+ .await\n+ .ok_or_else(|| ThreadStoreError::Internal {\n+ message: \"state DB unavailable for par...", + "path": "codex-rs/thread-store/src/local/list_threads.rs", + "status": "modified" + }, + { + "additions": 1, + "deletions": 0, + "patch_excerpt": "@@ -93,6 +93,7 @@ pub(super) async fn search_threads(\n cwd_filters: None,\n archived: params.archived,\n search_term: None,\n+ parent_thread_id: None,\n use_state_db_only: state_db.is_some(),\n };\n let mut remaining_rollouts = matching_rollouts;", + "path": "codex-rs/thread-store/src/local/search_threads.rs", + "status": "modified" + }, + { + "additions": 1, + "deletions": 0, + "patch_excerpt": "@@ -1476,6 +1476,7 @@ mod tests {\n cwd_filters: Some(vec![workspace]),\n archived: false,\n search_term: None,\n+ parent_thread_id: None,\n use_state_db_only: true,\n })\n .await", + "path": "codex-rs/thread-store/src/local/update_thread_metadata.rs", + "status": "modified" + }, + { + "additions": 2, + "deletions": 0, + "patch_excerpt": "@@ -195,6 +195,8 @@ pub struct ListThreadsParams {\n pub archived: bool,\n /// Optional substring/full-text search term for thread title/preview.\n pub search_term: Option,\n+ /// Optional direct parent thread filter.\n+ pub parent_thread_id: Option,\n /// Return directly from the state DB without scanning JSONL rollouts to repair metadata.\n pub use_state_db_only: bool,\n }", + "path": "codex-rs/thread-store/src/types.rs", + "status": "modified" + }, + { + "additions": 2, + "deletions": 0, + "patch_excerpt": "@@ -696,6 +696,7 @@ async fn lookup_session_target_by_name_with_app_server(\n model_providers: None,\n source_kinds: Some(vec![ThreadSourceKind::Cli, ThreadSourceKind::VsCode]),\n archived: Some(false),\n+ parent_thread_id: None,\n cwd: None,\n use_state_db_only: false,\n search_term: Some(name.to_string()),\n@@ -808,6 +809,7 @@ fn latest_session_lookup_params(\n },\n source_kinds: Some(resume_source_kinds(include_non_interactive)),\n archived: Some(false),\n+ parent_thread_id: None,\n cwd: cwd_filter.map(|cwd| ThreadListCwdFilter::One(cwd.to_string_lossy().to_string())),\n use_state_db_only: match lookup_mode {\n LatestSessionLookupMode::StateDbOnly => true,", + "path": "codex-rs/tui/src/lib.rs", + "status": "modified" + }, + { + "additions": 1, + "deletions": 0, + "patch_excerpt": "@@ -1821,6 +1821,7 @@ fn thread_list_params(\n },\n source_kinds: Some(crate::resume_source_kinds(include_non_interactive)),\n archived: Some(false),\n+ parent_thread_id: None,\n cwd: cwd_filter.map(|cwd| ThreadListCwdFilter::One(cwd.to_string_lossy().into_owned())),\n use_state_db_only: false,\n search_term: None,", + "path": "codex-rs/tui/src/resume_picker.rs", + "status": "modified" + }, + { + "additions": 1, + "deletions": 0, + "patch_excerpt": "@@ -177,6 +177,7 @@ async fn lookup_session_by_exact_name(\n /*include_non_interactive*/ false,\n )),\n archived: Some(archived),\n+ parent_thread_id: None,\n cwd: None,\n use_state_db_only: false,\n search_term: search_term.map(str::to_string),", + "path": "codex-rs/tui/src/session_archive_commands.rs", + "status": "modified" + } + ], + "linked_issues": [ + "#25112", + "#26662" + ], + "notes": [ + "Built from GitHub pull-request, commits, files, and repo endpoints." + ], + "primary_pr": { + "body": "## Why\n\nClients that display or coordinate spawned subagents need an authoritative snapshot of a thread's immediate spawned children when they connect to app-server or recover after missing live events. `thread/list` cannot query by parent, so clients must otherwise scan unrelated threads or reconstruct relationships from rollout history and transient events.\n\nThe direct spawn relationship already exists in persisted `thread_spawn_edges` state. Review and Guardian threads do not participate in that lifecycle and are intentionally outside this filter's scope.\n\n## What changed\n\nThis adds an experimental `parentThreadId` filter to `thread/list`. Parent-filtered requests return direct spawned children from persisted state while preserving the existing response shape, explicit filters, sorting, and timestamp-only cursor behavior. The lookup does not read rollout transcripts or recursively return descendants.\n\nSupersedes #25112 with the narrower `thread/list` filter approach.\n\n## How it works\n\n1. An experimental client passes a valid thread ID as `parentThreadId`.\n2. App-server routes the list through the existing thread-store and state-database boundaries.\n3. SQLite selects threads whose IDs have a direct persisted spawn edge from that parent.\n4. Omitted provider and source filters include all values; explicit filters keep ordinary `thread/list` semantics.\n5. Grandchildren, Review threads, and Guardian threads are excluded.\n\n## Verification\n\nState (144 tests), rollout (69 tests), and focused app-server thread-list (31 tests) suites passed. Scoped Clippy checks and repository formatting also passed. Coverage includes direct spawned children, omitted grandchildren, pagination, malformed IDs, mixed source kinds, explicit filters, and operation without rollout files.", + "labels": [ + "code-reviewed" + ], + "merged_at": "2026-06-14T07:14:27Z", + "number": 26662, + "state": "merged", + "title": "feat(app-server): filter threads by parent", + "url": "https://github.com/openai/codex/pull/26662" + }, + "repo": "openai/codex", + "schema": "github_change_bundle/v1" +} diff --git a/artifacts/github/bundles/openai-codex-pr-28122.json b/artifacts/github/bundles/openai-codex-pr-28122.json new file mode 100644 index 000000000..c29bc53c4 --- /dev/null +++ b/artifacts/github/bundles/openai-codex-pr-28122.json @@ -0,0 +1,296 @@ +{ + "analysis_mode": "pr_first", + "commits": [ + { + "author": "anp-oai", + "committed_at": "2026-06-13T21:50:40Z", + "message": "core: carry turn environment cwd as PathUri", + "sha": "a2a917b071ce164777333349163005720c8c5e7f", + "url": "https://github.com/openai/codex/commit/a2a917b071ce164777333349163005720c8c5e7f" + }, + { + "author": "anp-oai", + "committed_at": "2026-06-13T22:22:06Z", + "message": "core: honor remote environment cwd and shell", + "sha": "019ff65142c38263fd685f9692670aeeb560c5c6", + "url": "https://github.com/openai/codex/commit/019ff65142c38263fd685f9692670aeeb560c5c6" + }, + { + "author": "anp-oai", + "committed_at": "2026-06-13T22:43:11Z", + "message": "protocol: clarify remote cwd preservation", + "sha": "5bada3f2a4f18a252cd65d89f461d3ff3c9f4b1f", + "url": "https://github.com/openai/codex/commit/5bada3f2a4f18a252cd65d89f461d3ff3c9f4b1f" + }, + { + "author": "anp-oai", + "committed_at": "2026-06-13T23:10:56Z", + "message": "app-server: record foreign environment cwd rejection", + "sha": "2a8b87ed44215e4bf0bcce6b778038874c720b51", + "url": "https://github.com/openai/codex/commit/2a8b87ed44215e4bf0bcce6b778038874c720b51" + }, + { + "author": "anp-oai", + "committed_at": "2026-06-13T23:21:08Z", + "message": "tests: cover app-server remote Windows cwd", + "sha": "310ccf29f684a7a19ae65ea790bd465cfe74cb2a", + "url": "https://github.com/openai/codex/commit/310ccf29f684a7a19ae65ea790bd465cfe74cb2a" + }, + { + "author": "anp-oai", + "committed_at": "2026-06-14T01:26:27Z", + "message": "tests: send native Windows cwd through app server", + "sha": "763357aaa79a5fb13f84a5013deb2ff284a67bd4", + "url": "https://github.com/openai/codex/commit/763357aaa79a5fb13f84a5013deb2ff284a67bd4" + }, + { + "author": "anp-oai", + "committed_at": "2026-06-14T01:36:48Z", + "message": "tests: extract Wine exec-server fixture", + "sha": "ce4102787545b9131e32619e43ed89dc0ad13f12", + "url": "https://github.com/openai/codex/commit/ce4102787545b9131e32619e43ed89dc0ad13f12" + }, + { + "author": "anp-oai", + "committed_at": "2026-06-14T05:08:18Z", + "message": "codex: address PR review feedback (#28122)", + "sha": "4f6dd50b0eb01f3548c7b1403017e74c8697ef51", + "url": "https://github.com/openai/codex/commit/4f6dd50b0eb01f3548c7b1403017e74c8697ef51" + }, + { + "author": "anp-oai", + "committed_at": "2026-06-14T05:31:28Z", + "message": "codex: fix CI failure on PR #28122", + "sha": "f4db0780fc9ef2063e29847f851759c5bd97dbe1", + "url": "https://github.com/openai/codex/commit/f4db0780fc9ef2063e29847f851759c5bd97dbe1" + }, + { + "author": "anp-oai", + "committed_at": "2026-06-14T05:41:42Z", + "message": "codex: fix CI failure on PR #28122", + "sha": "25644e0ec49ebf371ab45c8ae73b3cb8fd78607e", + "url": "https://github.com/openai/codex/commit/25644e0ec49ebf371ab45c8ae73b3cb8fd78607e" + }, + { + "author": "anp-oai", + "committed_at": "2026-06-14T05:49:31Z", + "message": "codex: fix CI failure on PR #28122", + "sha": "18004b9322a89dd9efc40aea3f88643cdfc55eed", + "url": "https://github.com/openai/codex/commit/18004b9322a89dd9efc40aea3f88643cdfc55eed" + }, + { + "author": "anp-oai", + "committed_at": "2026-06-14T05:56:50Z", + "message": "tests: follow runfiles symlinks in Wine runtime", + "sha": "716e9e32e934a3f7b868a1bc7a327524594dc81e", + "url": "https://github.com/openai/codex/commit/716e9e32e934a3f7b868a1bc7a327524594dc81e" + }, + { + "author": "anp-oai", + "committed_at": "2026-06-14T05:59:36Z", + "message": "codex: fix CI failure on PR #28122", + "sha": "1a7dbd5b4ff43cdf230f8b7062e6c1618ed458dc", + "url": "https://github.com/openai/codex/commit/1a7dbd5b4ff43cdf230f8b7062e6c1618ed458dc" + } + ], + "default_branch": "main", + "docs_refs": [], + "examples_refs": [], + "extracted_flags": [ + "URI", + "TODO", + "BUILT_IN_PERMISSION_PROFILE_DANGER_FULL_ACCESS", + "BUILT_IN_PERMISSION_PROFILE_WORKSPACE", + "THREAD_LIST_DEFAULT_LIMIT", + "THREAD_LIST_MAX_LIMIT", + "DIRECT_INPUT_TO_MULTI_AGENT_V2_SUBAGENT_ERROR", + "LOCAL_ENVIRONMENT_ID", + "REMOTE_ENVIRONMENT_ID", + "JSONRPCE", + "CODEX_EXEC_SERVER_URL_ENV_VAR", + "APP_SERVER_READ_TIMEOUT", + "CALL_ID", + "COMMAND", + "WINE_BAZEL_OK", + "INVALID_REQUEST_ERROR_CODE", + "CODEX_HOME", + "URL", + "COLLABORATION_MODE_CLOSE_TAG", + "REALTIME_CONVERSATION_OPEN_TAG", + "REALTIME_CONVERSATION_CLOSE_TAG", + "USER_MESSAGE_BEGIN" + ], + "files": [ + { + "additions": 24, + "deletions": 12, + "patch_excerpt": "@@ -328,11 +328,12 @@ fn install_powershell_runtime(prefix: &Path, runtime: &Path) -> Result<()> {\n \n /// Recursively reproduces a runfiles directory in a writable Wine prefix.\n ///\n-/// Bazel runfiles may be immutable and may contain the PowerShell distribution\n-/// on a different filesystem from the temporary prefix. Hard links avoid\n-/// repeatedly copying the roughly hundred-megabyte runtime when both locations\n-/// share a filesystem; the copy fallback preserves correctness for sandbox or\n-/// remote-execution layouts where cross-device hard links are unavailable.\n+/// Bazel runfiles may be immutable, represented by a symlink forest, and may\n+/// contain the PowerShell distribution on a different filesystem from the\n+/// temporary prefix. Hard links avoid repeatedly copying the roughly\n+/// hundred-megabyte runtime when both locations share a filesystem; the copy\n+/// fallback prese...", + "path": "bazel/rules/testing/wine/src/lib.rs", + "status": "modified" + }, + { + "additions": 22, + "deletions": 0, + "patch_excerpt": "@@ -264,6 +264,28 @@ fn powershell_runtime_is_materialized_at_the_windows_fallback_path() -> Result<(\n Ok(())\n }\n \n+#[test]\n+fn powershell_runtime_follows_runfiles_symlinks() -> Result<()> {\n+ let prefix = TempDir::new()?;\n+ let runtime = TempDir::new()?;\n+ let backing = TempDir::new()?;\n+ let backing_file = backing.path().join(\"pwsh.exe\");\n+ fs::write(&backing_file, b\"pwsh\")?;\n+ std::os::unix::fs::symlink(&backing_file, runtime.path().join(\"pwsh.exe\"))?;\n+\n+ install_powershell_runtime(prefix.path(), runtime.path())?;\n+\n+ let installed = prefix\n+ .path()\n+ .join(\"drive_c\")\n+ .join(\"Program Files\")\n+ .join(\"PowerShell\")\n+ .join(\"7\")\n+ .join(\"pwsh.exe\");\n+ assert_eq!(fs::read(installed)?, b\"pwsh\");\n+ Ok(())\n+}\n+\n #[tokio::test]\n async fn pinned_powershell_runs_under_wine_with_a_pty() -> Result<()> {\n // Keep th...", + "path": "bazel/rules/testing/wine/src/lib_tests.rs", + "status": "modified" + }, + { + "additions": 1, + "deletions": 0, + "patch_excerpt": "@@ -3583,6 +3583,7 @@ dependencies = [\n \"codex-network-proxy\",\n \"codex-utils-absolute-path\",\n \"codex-utils-image\",\n+ \"codex-utils-path-uri\",\n \"codex-utils-string\",\n \"encoding_rs\",\n \"globset\",", + "path": "codex-rs/Cargo.lock", + "status": "modified" + }, + { + "additions": 2, + "deletions": 1, + "patch_excerpt": "@@ -4,6 +4,7 @@ use codex_app_server_protocol::SelectedCapabilityRoot;\n use codex_extension_api::ExtensionDataInit;\n use codex_protocol::models::BUILT_IN_PERMISSION_PROFILE_DANGER_FULL_ACCESS;\n use codex_protocol::models::BUILT_IN_PERMISSION_PROFILE_WORKSPACE;\n+use codex_utils_path_uri::PathUri;\n \n const THREAD_LIST_DEFAULT_LIMIT: usize = 25;\n const THREAD_LIST_MAX_LIMIT: usize = 100;\n@@ -1292,7 +1293,7 @@ impl ThreadRequestProcessor {\n .into_iter()\n .map(|environment| TurnEnvironmentSelection {\n environment_id: environment.environment_id,\n- cwd: environment.cwd,\n+ cwd: PathUri::from_abs_path(&environment.cwd),\n })\n .collect::>()\n });", + "path": "codex-rs/app-server/src/request_processors/thread_processor.rs", + "status": "modified" + }, + { + "additions": 3, + "deletions": 2, + "patch_excerpt": "@@ -4,6 +4,7 @@ use codex_protocol::protocol::AdditionalContextKind as CoreAdditionalContextKind\n use codex_protocol::protocol::MultiAgentVersion;\n use codex_protocol::protocol::SessionSource;\n use codex_protocol::protocol::SubAgentSource;\n+use codex_utils_path_uri::PathUri;\n \n const DIRECT_INPUT_TO_MULTI_AGENT_V2_SUBAGENT_ERROR: &str =\n \"direct app-server input is not allowed for multi-agent v2 sub-agents\";\n@@ -339,7 +340,7 @@ impl TurnRequestProcessor {\n .into_iter()\n .map(|environment| TurnEnvironmentSelection {\n environment_id: environment.environment_id,\n- cwd: environment.cwd,\n+ cwd: PathUri::from_abs_path(&environment.cwd),\n })\n .collect::>()\n });\n@@ -523,7 +524,7 @@ impl TurnRequestProcessor {\n environment_selections\n ...", + "path": "codex-rs/app-server/src/request_processors/turn_processor.rs", + "status": "modified" + }, + { + "additions": 21, + "deletions": 9, + "patch_excerpt": "@@ -7,6 +7,7 @@ use codex_protocol::error::CodexErr;\n use codex_protocol::error::Result as CodexResult;\n use codex_protocol::protocol::TurnEnvironmentSelection;\n use codex_utils_absolute_path::AbsolutePathBuf;\n+use codex_utils_path_uri::PathUri;\n \n use crate::session::turn_context::TurnEnvironment;\n use crate::shell::Shell;\n@@ -20,7 +21,7 @@ pub(crate) fn default_thread_environment_selections(\n .into_iter()\n .map(|environment_id| TurnEnvironmentSelection {\n environment_id,\n- cwd: cwd.clone(),\n+ cwd: PathUri::from_abs_path(cwd),\n })\n .collect()\n }\n@@ -99,7 +100,12 @@ pub(crate) async fn resolve_environment_selections(\n turn_environments.push(TurnEnvironment::new(\n environment_id,\n environment,\n- selected_environment.cwd.clone(),\n+ selected_environment.cwd.to_abs_path().m...", + "path": "codex-rs/core/src/environment_selection.rs", + "status": "modified" + }, + { + "additions": 36, + "deletions": 8, + "patch_excerpt": "@@ -149,6 +149,7 @@ use codex_thread_store::ResumeThreadParams;\n use codex_thread_store::ThreadPersistenceMetadata;\n use codex_thread_store::ThreadStore;\n use codex_utils_output_truncation::TruncationPolicy;\n+use codex_utils_path_uri::PathUri;\n use futures::future::BoxFuture;\n use futures::future::Shared;\n use futures::prelude::*;\n@@ -2206,6 +2207,18 @@ impl Session {\n }\n \n let requested_permissions = args.permissions;\n+ // TODO(anp): Migrate request_permissions to support paths from foreign environments.\n+ let Ok(native_environment_cwd) = environment.cwd.to_abs_path() else {\n+ warn!(\n+ cwd = %environment.cwd,\n+ \"request_permissions requires a cwd native to the Codex host\"\n+ );\n+ return Some(RequestPermissionsResponse {\n+ permissions: RequestPermissionProfile::default(),\n+ ...", + "path": "codex-rs/core/src/session/mod.rs", + "status": "modified" + }, + { + "additions": 2, + "deletions": 1, + "patch_excerpt": "@@ -58,6 +58,7 @@ use codex_protocol::protocol::SandboxPolicy;\n use codex_protocol::protocol::TurnEnvironmentSelections;\n use codex_protocol::request_permissions::PermissionGrantScope;\n use codex_protocol::request_permissions::RequestPermissionProfile;\n+use codex_utils_path_uri::PathUri;\n use tracing::Span;\n \n use crate::rollout::recorder::RolloutRecorder;\n@@ -4705,7 +4706,7 @@ async fn cwd_update_rewrites_sticky_environment_cwd() {\n assert_eq!(state.session_configuration.cwd(), &updated_cwd);\n assert_eq!(\n state.session_configuration.environment_selections()[0].cwd,\n- updated_cwd\n+ PathUri::from_abs_path(&updated_cwd)\n );\n assert_ne!(environment_cwd, updated_cwd);\n }", + "path": "codex-rs/core/src/session/tests.rs", + "status": "modified" + }, + { + "additions": 1, + "deletions": 1, + "patch_excerpt": "@@ -79,7 +79,7 @@ impl TurnEnvironment {\n pub(crate) fn selection(&self) -> TurnEnvironmentSelection {\n TurnEnvironmentSelection {\n environment_id: self.environment_id.clone(),\n- cwd: self.cwd.clone(),\n+ cwd: self.cwd_uri.clone(),\n }\n }\n }", + "path": "codex-rs/core/src/session/turn_context.rs", + "status": "modified" + }, + { + "additions": 3, + "deletions": 2, + "patch_excerpt": "@@ -23,6 +23,7 @@ use codex_protocol::protocol::SessionSource;\n use codex_protocol::protocol::ThreadSource;\n use codex_protocol::protocol::TurnStartedEvent;\n use codex_protocol::protocol::UserMessageEvent;\n+use codex_utils_path_uri::PathUri;\n use core_test_support::PathBufExt;\n use core_test_support::PathExt;\n use core_test_support::responses::mount_models_once;\n@@ -331,7 +332,7 @@ async fn start_thread_rejects_explicit_local_environment_when_default_provider_i\n parent_trace: None,\n environments: vec![TurnEnvironmentSelection {\n environment_id: \"local\".to_string(),\n- cwd: config.cwd.clone(),\n+ cwd: PathUri::from_abs_path(&config.cwd),\n }],\n thread_extension_init: Default::default(),\n })\n@@ -594,7 +595,7 @@ async fn resume_and_fork_do_not_restore_thread_environments_from_rollout() {\n ...", + "path": "codex-rs/core/src/thread_manager_tests.rs", + "status": "modified" + }, + { + "additions": 8, + "deletions": 1, + "patch_excerpt": "@@ -151,9 +151,16 @@ impl ExecCommandHandler {\n let process_id = manager.allocate_process_id().await;\n let shell_mode =\n shell_mode_for_environment(&turn.unified_exec_shell_mode, environment.as_ref());\n+ // Remote environments may use a different OS and must build commands with their native\n+ // shell; fall back to the session shell when the environment did not report one.\n+ let shell = turn_environment\n+ .shell\n+ .clone()\n+ .map(Arc::new)\n+ .unwrap_or_else(|| session.user_shell());\n let resolved_command = get_command(\n &args,\n- session.user_shell(),\n+ shell,\n &shell_mode,\n turn.config.permissions.allow_login_shell,\n )", + "path": "codex-rs/core/src/tools/handlers/unified_exec/exec_command.rs", + "status": "modified" + }, + { + "additions": 1, + "deletions": 1, + "patch_excerpt": "@@ -104,7 +104,7 @@ impl UserInstructionsProvider for RecordingUserInstructionsProvider {\n pub fn local(cwd: AbsolutePathBuf) -> TurnEnvironmentSelection {\n TurnEnvironmentSelection {\n environment_id: codex_exec_server::LOCAL_ENVIRONMENT_ID.to_string(),\n- cwd,\n+ cwd: PathUri::from_abs_path(&cwd),\n }\n }", + "path": "codex-rs/core/tests/common/test_codex.rs", + "status": "modified" + }, + { + "additions": 8, + "deletions": 2, + "patch_excerpt": "@@ -6,19 +6,25 @@ wine_rust_test(\n srcs = [\"remote_env_windows_test.rs\"],\n crate_name = \"remote_env_windows_test\",\n crate_root = \"remote_env_windows_test.rs\",\n+ host_binaries = {\n+ \"codex-app-server\": \"//codex-rs/app-server:codex-app-server\",\n+ },\n windows_binaries = {\n \"wine-windows-exec-server\": \"//codex-rs/exec-server/testing:windows-exec-server\",\n },\n deps = [\n- \"//bazel/rules/testing/wine:wine_test_support\",\n+ \"//codex-rs/app-server-protocol\",\n+ \"//codex-rs/app-server/tests/common\",\n \"//codex-rs/core/tests/common\",\n \"//codex-rs/exec-server\",\n+ \"//codex-rs/exec-server/testing:wine-exec-server-test-support\",\n \"//codex-rs/features\",\n \"//codex-rs/protocol\",\n- \"//codex-rs/utils/cargo-bin\",\n+ \"//codex-rs/utils/path-uri\",\n \"@crates//:anyhow\",\n \"@crates//:pr...", + "path": "codex-rs/core/tests/remote_env_windows/BUILD.bazel", + "status": "modified" + }, + { + "additions": 87, + "deletions": 42, + "patch_excerpt": "@@ -2,11 +2,16 @@\n \n use anyhow::Context;\n use anyhow::Result;\n+use app_test_support::TestAppServer;\n+use codex_app_server_protocol::JSONRPCError;\n+use codex_app_server_protocol::RequestId;\n use codex_exec_server::REMOTE_ENVIRONMENT_ID;\n+use codex_exec_server::CODEX_EXEC_SERVER_URL_ENV_VAR;\n use codex_features::Feature;\n use codex_protocol::models::PermissionProfile;\n use codex_protocol::protocol::AskForApproval;\n use codex_protocol::protocol::EventMsg;\n+use codex_protocol::protocol::ExecCommandStatus;\n use codex_protocol::protocol::Op;\n use codex_protocol::protocol::TurnEnvironmentSelection;\n use codex_protocol::protocol::TurnEnvironmentSelections;\n@@ -21,40 +26,27 @@ use core_test_support::responses::start_mock_server;\n use core_test_support::test_codex::test_codex;\n use core_test_support::test_codex::turn_permission_fields;\n use core_test_support::wait_for_event;\n+use codex_utils_path...", + "path": "codex-rs/core/tests/remote_env_windows/remote_env_windows_test.rs", + "status": "modified" + }, + { + "additions": 2, + "deletions": 2, + "patch_excerpt": "@@ -646,11 +646,11 @@ async fn multi_environment_thread_loads_every_project_and_keeps_creation_snapsho\n environments: vec![\n TurnEnvironmentSelection {\n environment_id: REMOTE_ENVIRONMENT_ID.to_string(),\n- cwd: test.config.cwd.clone(),\n+ cwd: PathUri::from_abs_path(&test.config.cwd),\n },\n TurnEnvironmentSelection {\n environment_id: LOCAL_ENVIRONMENT_ID.to_string(),\n- cwd: local_root.path().to_path_buf().try_into()?,\n+ cwd: PathUri::from_path(local_root.path())?,\n },\n ],\n thread_extension_init: Default::default(),", + "path": "codex-rs/core/tests/suite/agents_md.rs", + "status": "modified" + }, + { + "additions": 1, + "deletions": 1, + "patch_excerpt": "@@ -1635,7 +1635,7 @@ async fn apply_patch_turn_diff_tracks_local_and_remote_environment_paths() -> Re\n local(shared_cwd.clone()),\n TurnEnvironmentSelection {\n environment_id: REMOTE_ENVIRONMENT_ID.to_string(),\n- cwd: shared_cwd.clone(),\n+ cwd: PathUri::from_abs_path(&shared_cwd),\n },\n ];\n test.codex", + "path": "codex-rs/core/tests/suite/apply_patch_cli.rs", + "status": "modified" + }, + { + "additions": 5, + "deletions": 5, + "patch_excerpt": "@@ -352,7 +352,7 @@ async fn exec_command_routes_to_selected_remote_environment() -> Result<()> {\n .await?;\n let remote_selection = TurnEnvironmentSelection {\n environment_id: REMOTE_ENVIRONMENT_ID.to_string(),\n- cwd: remote_cwd.clone(),\n+ cwd: PathUri::from_abs_path(&remote_cwd),\n };\n let multi_env_output = exec_command_routing_output(\n &test,\n@@ -508,7 +508,7 @@ async fn remote_request_permissions_grant_unblocks_later_remote_exec() -> Result\n local(local_cwd.path().abs()),\n TurnEnvironmentSelection {\n environment_id: REMOTE_ENVIRONMENT_ID.to_string(),\n- cwd: remote_cwd.clone(),\n+ cwd: PathUri::from_abs_path(&remote_cwd),\n },\n ],\n )\n@@ -648,7 +648,7 @@ async fn apply_patch_freeform_routes_to_selected_remote_environment() -> Result<\n ...", + "path": "codex-rs/core/tests/suite/remote_env.rs", + "status": "modified" + }, + { + "additions": 1, + "deletions": 1, + "patch_excerpt": "@@ -624,7 +624,7 @@ async fn view_image_routes_to_selected_remote_environment() -> anyhow::Result<()\n .await?;\n let remote_selection = TurnEnvironmentSelection {\n environment_id: REMOTE_ENVIRONMENT_ID.to_string(),\n- cwd: remote_cwd.clone(),\n+ cwd: PathUri::from_abs_path(&remote_cwd),\n };\n let call_id = \"call-view-image-multi-env\";\n let response_mock = mount_sse_sequence(", + "path": "codex-rs/core/tests/suite/view_image.rs", + "status": "modified" + }, + { + "additions": 17, + "deletions": 1, + "patch_excerpt": "@@ -1,4 +1,20 @@\n-load(\"@rules_rust//rust:defs.bzl\", \"rust_binary\")\n+load(\"@rules_rust//rust:defs.bzl\", \"rust_binary\", \"rust_library\")\n+\n+rust_library(\n+ name = \"wine-exec-server-test-support\",\n+ testonly = True,\n+ srcs = [\"wine_exec_server.rs\"],\n+ crate_name = \"wine_exec_server_test_support\",\n+ crate_root = \"wine_exec_server.rs\",\n+ target_compatible_with = [\"@platforms//os:linux\"],\n+ visibility = [\"//codex-rs/core/tests/remote_env_windows:__pkg__\"],\n+ deps = [\n+ \"//bazel/rules/testing/wine:wine_test_support\",\n+ \"//codex-rs/utils/cargo-bin\",\n+ \"@crates//:anyhow\",\n+ \"@crates//:tokio\",\n+ ],\n+)\n \n rust_binary(\n name = \"windows-exec-server\",", + "path": "codex-rs/exec-server/testing/BUILD.bazel", + "status": "modified" + }, + { + "additions": 43, + "deletions": 0, + "patch_excerpt": "@@ -0,0 +1,43 @@\n+//! Test support for running the Windows exec-server under Wine.\n+\n+use std::future::Future;\n+\n+use anyhow::Context;\n+use anyhow::Result;\n+use tokio::io::AsyncBufReadExt;\n+use tokio::io::BufReader;\n+use wine_test_support::WineTestCommand;\n+\n+/// Runs the Windows exec-server under Wine for the duration of a scoped operation.\n+pub struct WineExecServer;\n+\n+impl WineExecServer {\n+ /// Starts the server, passes its WebSocket URL to `operation`, and tears it down afterward.\n+ pub async fn scope(self, operation: F) -> Result\n+ where\n+ F: FnOnce(String) -> Fut,\n+ Fut: Future>,\n+ {\n+ let executable = codex_utils_cargo_bin::cargo_bin(\"wine-windows-exec-server\")?;\n+ let mut exec_server = WineTestCommand::new(executable)\n+ .env(\"CODEX_HOME\", r\"C:\\codex-home\")\n+ .spawn()?;\n+ let st...", + "path": "codex-rs/exec-server/testing/wine_exec_server.rs", + "status": "added" + }, + { + "additions": 1, + "deletions": 0, + "patch_excerpt": "@@ -20,6 +20,7 @@ codex-execpolicy = { workspace = true }\n codex-network-proxy = { workspace = true }\n codex-utils-absolute-path = { workspace = true }\n codex-utils-image = { workspace = true }\n+codex-utils-path-uri = { workspace = true }\n codex-utils-string = { workspace = true }\n encoding_rs = { workspace = true }\n globset = { workspace = true }", + "path": "codex-rs/protocol/Cargo.toml", + "status": "modified" + }, + { + "additions": 10, + "deletions": 3, + "patch_excerpt": "@@ -52,6 +52,7 @@ use crate::request_permissions::RequestPermissionsResponse;\n use crate::request_user_input::RequestUserInputResponse;\n use crate::user_input::UserInput;\n use codex_utils_absolute_path::AbsolutePathBuf;\n+use codex_utils_path_uri::PathUri;\n use schemars::JsonSchema;\n use serde::Deserialize;\n use serde::Serialize;\n@@ -105,11 +106,14 @@ pub const COLLABORATION_MODE_CLOSE_TAG: &str = \"\";\n pub const REALTIME_CONVERSATION_OPEN_TAG: &str = \"\";\n pub const REALTIME_CONVERSATION_CLOSE_TAG: &str = \"\";\n pub const USER_MESSAGE_BEGIN: &str = \"## My request for Codex:\";\n+const LOCAL_ENVIRONMENT_ID: &str = \"local\";\n \n+// TODO(anp): Replace `TurnEnvironmentSelection` with `PathUri` once path URIs carry environment\n+// identifiers.\n #[derive(Debug, Clone, PartialEq)]\n pub struct TurnEnvironmentSelection {\n pub environ...", + "path": "codex-rs/protocol/src/protocol.rs", + "status": "modified" + } + ], + "linked_issues": [ + "#28122" + ], + "notes": [ + "Built from GitHub pull-request, commits, files, and repo endpoints." + ], + "primary_pr": { + "body": "## Why\n\nNext slice needed to make progress on the `remote_env_windows` test is to support passing a Windows cwd for the remote environment and using that environment's native shell. This lets the test run a real Windows process instead of only recording an early path or shell mismatch.\n\n## What\n\n- change `TurnEnvironmentSelection.cwd` from `AbsolutePathBuf` to `PathUri`\n- convert local cwd values to URIs when constructing selections\n- preserve a remote primary cwd instead of replacing it with the local legacy fallback\n- prefer the selected environment's discovered shell for unified exec, falling back to the session shell when unavailable\n- convert back to a host-native absolute path at current native-only consumer boundaries\n- reject or deny unsupported foreign cwd values at the existing request-permissions boundary, with TODOs for its future migration\n- extend the hermetic Wine test to execute Windows PowerShell in `C:\\windows` and verify successful process completion\n- record the current app-server rejection against the same Wine-backed remote Windows fixture when its cwd is supplied as a native Windows path\n", + "labels": [], + "merged_at": "2026-06-14T06:07:47Z", + "number": 28122, + "state": "merged", + "title": "[codex] exec-server honors remote environment cwd and shell", + "url": "https://github.com/openai/codex/pull/28122" + }, + "repo": "openai/codex", + "schema": "github_change_bundle/v1" +} diff --git a/artifacts/github/impact/openai-codex-pr-26662.json b/artifacts/github/impact/openai-codex-pr-26662.json new file mode 100644 index 000000000..7ccd601df --- /dev/null +++ b/artifacts/github/impact/openai-codex-pr-26662.json @@ -0,0 +1,47 @@ +{ + "candidate_followups": [ + "Evaluate using `thread/list.parentThreadId` in Decodex operator UI and recovery paths that need direct child-thread visibility.", + "Preserve existing thread-list filters and cursor behavior when adding parent-filtered child-thread queries.", + "Treat unavailable state DB for parent-filtered listing as a capability/readiness state rather than silently falling back to rollout scans." + ], + "caveats": [ + "`parentThreadId` is explicitly experimental.", + "The filter returns direct spawned children only; it does not recursively return descendants.", + "Review and Guardian threads are intentionally outside this spawned-child lifecycle." + ], + "confidence": "confirmed", + "control_plane_impact": "candidate", + "evidence": [ + "App-server `ThreadListParams` adds experimental optional `parentThreadId`.", + "The thread processor parses `parentThreadId` into the existing thread-list filter path.", + "Local thread-store routing uses the state DB for parent-filtered listing.", + "State runtime adds `list_threads_by_parent` against persisted spawn edges.", + "The source-backed review is recorded at `artifacts/github/reviews/openai-codex-pr-26662.review.json`." + ], + "observed_change": "Codex adds an experimental `thread/list.parentThreadId` filter that returns direct spawned child threads from persisted spawn-edge state while preserving the existing list response shape and filters.", + "public_signal_decision": "publish", + "publisher_angle": "operator_impact", + "repo": "openai/codex", + "schema": "upstream_impact/v1", + "slug": "openai-codex-pr-26662", + "social_notes": [ + "Frame this as an app-server recovery and subagent-visibility improvement.", + "Do not imply recursive thread-tree listing or stable API status; the field is experimental and direct-child only." + ], + "source_refs": { + "items": [ + { + "kind": "pull_request", + "meta": "Merged 2026-06-14T07:14:27Z", + "title": "feat(app-server): filter threads by parent", + "url": "https://github.com/openai/codex/pull/26662" + }, + { + "kind": "pull_request", + "meta": "artifacts/github/reviews/openai-codex-pr-26662.review.json", + "title": "Source-backed Decodex upstream review", + "url": "https://github.com/openai/codex/pull/26662" + } + ] + } +} diff --git a/artifacts/github/impact/openai-codex-pr-28122.json b/artifacts/github/impact/openai-codex-pr-28122.json new file mode 100644 index 000000000..90129d246 --- /dev/null +++ b/artifacts/github/impact/openai-codex-pr-28122.json @@ -0,0 +1,47 @@ +{ + "candidate_followups": [ + "Audit Decodex Control Plane paths that construct or consume `TurnEnvironmentSelection` and preserve `PathUri` instead of normalizing everything to local absolute paths.", + "Use selected remote-environment shell information when bridging unified exec into remote executor sessions.", + "Expose unsupported foreign cwd request-permissions responses as cross-host path compatibility states instead of retrying them as transient process failures." + ], + "caveats": [ + "The PR does not make every request-permissions path foreign-host aware; native-only boundaries remain explicit.", + "Unified exec falls back to the session shell when the selected environment does not report a shell.", + "Decodex implementation work still needs a separate issue if local Control Plane code assumes selected environment cwd is always host-native." + ], + "confidence": "confirmed", + "control_plane_impact": "compat_risk", + "evidence": [ + "`TurnEnvironmentSelection.cwd` changed from `AbsolutePathBuf` to `PathUri`.", + "App-server thread and turn processors convert local cwd values into `PathUri` selections.", + "Core environment selection converts cwd URI values back to absolute paths only at native-only consumer boundaries.", + "Unified exec now prefers the selected environment shell and falls back to the session shell when absent.", + "The source-backed review is recorded at `artifacts/github/reviews/openai-codex-pr-28122.review.json`." + ], + "observed_change": "Codex changes turn environment cwd handling to preserve `PathUri` values and makes unified exec prefer the selected remote environment's native shell.", + "public_signal_decision": "publish", + "publisher_angle": "operator_impact", + "repo": "openai/codex", + "schema": "upstream_impact/v1", + "slug": "openai-codex-pr-28122", + "social_notes": [ + "Frame this as remote-exec cwd and native-shell compatibility for Control Plane integrations.", + "Do not imply all foreign cwd request-permissions paths are fully supported; the PR records current native-only rejection." + ], + "source_refs": { + "items": [ + { + "kind": "pull_request", + "meta": "Merged 2026-06-14T06:07:47Z", + "title": "[codex] exec-server honors remote environment cwd and shell", + "url": "https://github.com/openai/codex/pull/28122" + }, + { + "kind": "pull_request", + "meta": "artifacts/github/reviews/openai-codex-pr-28122.review.json", + "title": "Source-backed Decodex upstream review", + "url": "https://github.com/openai/codex/pull/28122" + } + ] + } +} diff --git a/artifacts/github/review-queue/openai-codex-latest.json b/artifacts/github/review-queue/openai-codex-latest.json index 46d3f3715..6edcf9b32 100644 --- a/artifacts/github/review-queue/openai-codex-latest.json +++ b/artifacts/github/review-queue/openai-codex-latest.json @@ -8,7 +8,7 @@ "recent_commits_scanned": 40, "subjects_queued": 40 }, - "generated_at": "2026-06-14T06:06:44.836542Z", + "generated_at": "2026-06-14T18:06:03.813491Z", "repo": "openai/codex", "schema": "upstream_review_queue/v1", "source": { @@ -17,91 +17,6 @@ "signals_dir": "site/src/content/signals" }, "subjects": [ - { - "attention_flags": [ - "auth_account", - "breaking_change", - "deprecated_removed", - "new_feature", - "protocol_change", - "security_policy" - ], - "changed_file_count": 8, - "commit_shas": [ - "07d66eccd904cd15cd754c43d3f74a72d63a1980", - "3e3379b56006b9e877f5db4ba65009b4ad41c49c" - ], - "committed_at": "2026-06-12T19:15:21Z", - "next_step": "ai_review_required", - "pr_number": 27504, - "pr_url": "https://github.com/openai/codex/pull/27504", - "review_priority": "critical", - "review_reason": "Needs AI review for auth_account, breaking_change, deprecated_removed, new_feature, protocol_change, security_policy.", - "sample_paths": [ - "codex-rs/config/src/types.rs", - "codex-rs/core/config.schema.json", - "codex-rs/core/src/config/auth_keyring.rs", - "codex-rs/core/src/config/auth_keyring_tests.rs", - "codex-rs/core/src/config/config_tests.rs", - "codex-rs/core/src/config/mod.rs", - "codex-rs/features/src/lib.rs", - "codex-rs/features/src/tests.rs" - ], - "source_state": "merged", - "subject_id": "27504", - "subject_kind": "pr", - "surface_hints": [ - "auth_accounts", - "config_hooks", - "tests_ci" - ], - "title": "feat: add secret auth storage configuration", - "url": "https://github.com/openai/codex/pull/27504" - }, - { - "attention_flags": [ - "auth_account", - "deprecated_removed", - "new_feature", - "protocol_change", - "security_policy" - ], - "changed_file_count": 9, - "commit_shas": [ - "bfd992f6dbf9acffcbdafbcee3c092d729725759", - "94185dff59cd43d21450db876ab4b595383ae959", - "f45d36dc66dfe7eba7478c6921a69ced53a92c07", - "21c45654a19f658a83b37ada768ab8e109f06955" - ], - "committed_at": "2026-06-12T19:38:30Z", - "next_step": "ai_review_required", - "pr_number": 27674, - "pr_url": "https://github.com/openai/codex/pull/27674", - "review_priority": "critical", - "review_reason": "Needs AI review for auth_account, deprecated_removed, new_feature, protocol_change, security_policy.", - "sample_paths": [ - "codex-rs/Cargo.lock", - "codex-rs/cli/Cargo.toml", - "codex-rs/cli/src/login.rs", - "codex-rs/cli/tests/login.rs", - "codex-rs/login/src/auth/manager.rs", - "codex-rs/login/src/auth/mod.rs", - "codex-rs/login/src/auth/revoke.rs", - "codex-rs/login/src/server.rs", - "codex-rs/login/tests/suite/logout.rs" - ], - "source_state": "merged", - "subject_id": "27674", - "subject_kind": "pr", - "surface_hints": [ - "auth_accounts", - "cli_tui", - "config_hooks", - "tests_ci" - ], - "title": "[login] revoke existing auth before starting login", - "url": "https://github.com/openai/codex/pull/27674" - }, { "attention_flags": [ "auth_account", @@ -861,6 +776,118 @@ "title": "build: run buildifier from just fmt", "url": "https://github.com/openai/codex/pull/28125" }, + { + "attention_flags": [ + "auth_account", + "breaking_change", + "new_feature", + "protocol_change", + "release_packaging", + "security_policy" + ], + "changed_file_count": 22, + "commit_shas": [ + "a2a917b071ce164777333349163005720c8c5e7f", + "019ff65142c38263fd685f9692670aeeb560c5c6", + "5bada3f2a4f18a252cd65d89f461d3ff3c9f4b1f", + "2a8b87ed44215e4bf0bcce6b778038874c720b51", + "310ccf29f684a7a19ae65ea790bd465cfe74cb2a", + "763357aaa79a5fb13f84a5013deb2ff284a67bd4", + "ce4102787545b9131e32619e43ed89dc0ad13f12", + "4f6dd50b0eb01f3548c7b1403017e74c8697ef51", + "f4db0780fc9ef2063e29847f851759c5bd97dbe1", + "25644e0ec49ebf371ab45c8ae73b3cb8fd78607e", + "18004b9322a89dd9efc40aea3f88643cdfc55eed", + "716e9e32e934a3f7b868a1bc7a327524594dc81e", + "1a7dbd5b4ff43cdf230f8b7062e6c1618ed458dc" + ], + "committed_at": "2026-06-14T06:07:46Z", + "next_step": "ai_review_required", + "pr_number": 28122, + "pr_url": "https://github.com/openai/codex/pull/28122", + "review_priority": "critical", + "review_reason": "Needs AI review for auth_account, breaking_change, new_feature, protocol_change, release_packaging, security_policy.", + "sample_paths": [ + "bazel/rules/testing/wine/src/lib.rs", + "bazel/rules/testing/wine/src/lib_tests.rs", + "codex-rs/Cargo.lock", + "codex-rs/app-server/src/request_processors/thread_processor.rs", + "codex-rs/app-server/src/request_processors/turn_processor.rs", + "codex-rs/core/src/environment_selection.rs", + "codex-rs/core/src/session/mod.rs", + "codex-rs/core/src/session/tests.rs", + "codex-rs/core/src/session/turn_context.rs", + "codex-rs/core/src/thread_manager_tests.rs", + "codex-rs/core/src/tools/handlers/unified_exec/exec_command.rs", + "codex-rs/core/tests/common/test_codex.rs" + ], + "source_state": "merged", + "subject_id": "28122", + "subject_kind": "pr", + "surface_hints": [ + "app_server_protocol", + "cli_tui", + "config_hooks", + "tests_ci" + ], + "title": "[codex] exec-server honors remote environment cwd and shell", + "url": "https://github.com/openai/codex/pull/28122" + }, + { + "attention_flags": [ + "auth_account", + "breaking_change", + "deprecated_removed", + "new_feature", + "protocol_change", + "security_policy" + ], + "changed_file_count": 27, + "commit_shas": [ + "68567deb6f6e9227662c9558d37ff3e280a2b377", + "724cd58bf6ed04ffaf8ab8520c951a5518f3161a", + "c2f877a1d0c5dbab82f5d7fcb4c591b90e9541f8", + "e06ed34720737e1657c74fdc466972c5fdda5ac4", + "eaeb92854e2d6da708558a8f0b81ff7cacdfd569", + "4c1fbf28545273cd4ba9402a4065171b646824f9", + "28d35a99eff66cf06742933e4a45fde47fb927d5", + "ba23593c751b155e4a86d2e6c24125a4b177a8c6", + "95d0018d71d9b15ccac883561abd1d408cf0f875", + "688537c78d85337d3bc70e80a7e74fcfe11da6ce" + ], + "committed_at": "2026-06-14T07:14:26Z", + "next_step": "ai_review_required", + "pr_number": 26662, + "pr_url": "https://github.com/openai/codex/pull/26662", + "review_priority": "critical", + "review_reason": "Needs AI review for auth_account, breaking_change, deprecated_removed, new_feature, protocol_change, security_policy.", + "sample_paths": [ + "codex-rs/app-server-protocol/schema/typescript/v2/ThreadListParams.ts", + "codex-rs/app-server-protocol/src/protocol/common.rs", + "codex-rs/app-server-protocol/src/protocol/v2/thread.rs", + "codex-rs/app-server-test-client/src/lib.rs", + "codex-rs/app-server/README.md", + "codex-rs/app-server/src/request_processors/thread_processor.rs", + "codex-rs/app-server/tests/suite/v2/external_agent_config.rs", + "codex-rs/app-server/tests/suite/v2/remote_thread_store.rs", + "codex-rs/app-server/tests/suite/v2/thread_fork.rs", + "codex-rs/app-server/tests/suite/v2/thread_list.rs", + "codex-rs/app-server/tests/suite/v2/thread_read.rs", + "codex-rs/core/src/personality_migration.rs" + ], + "source_state": "merged", + "subject_id": "26662", + "subject_kind": "pr", + "surface_hints": [ + "app_server_protocol", + "cli_tui", + "config_hooks", + "docs_examples", + "tests_ci" + ], + "title": "feat(app-server): filter threads by parent", + "url": "https://github.com/openai/codex/pull/26662" + }, { "attention_flags": [ "auth_account", diff --git a/artifacts/github/reviews/openai-codex-pr-26662.review.json b/artifacts/github/reviews/openai-codex-pr-26662.review.json new file mode 100644 index 000000000..b1eba9c85 --- /dev/null +++ b/artifacts/github/reviews/openai-codex-pr-26662.review.json @@ -0,0 +1,86 @@ +{ + "adoption_opportunity": "Use app-server `thread/list.parentThreadId` in Decodex Control Plane and operator UIs to recover direct spawned child threads from persisted spawn edges instead of scanning unrelated threads or reconstructing relationships from rollout history.", + "caveats": "The filter is marked experimental, returns only direct spawned children, depends on persisted spawn-edge state, and intentionally excludes grandchildren, Review threads, and Guardian threads.", + "changed_surfaces": [ + "app-server v2 `thread/list` params", + "app-server protocol TypeScript schema", + "thread-list request parameter inspection", + "thread request processor filter normalization", + "local thread-store parent-filter routing", + "state database thread listing by spawn edge", + "app-server README documentation", + "thread-list and thread-store tests" + ], + "community_value": "High for clients that coordinate spawned subagents because the PR gives them an authoritative app-server query for direct children after reconnects or missed live events.", + "compatibility_risk": "Low. The change adds an experimental optional `parentThreadId` filter while preserving the existing `thread/list` response shape, explicit filters, sorting, and cursor behavior.", + "confidence": "confirmed", + "control_plane_relevance": "High. Decodex Control Plane needs reliable parent-child thread visibility for subagent coordination, recovery, and operator display.", + "deprecated_or_breaking_notes": "No removal was observed. The new field is additive and experimental; callers that do not pass `parentThreadId` keep ordinary `thread/list` behavior.", + "evidence": [ + "PR #26662 says it adds an experimental `parentThreadId` filter to `thread/list` so clients can query direct spawned children from persisted state without scanning unrelated threads or rollout history.", + "`codex-rs/app-server-protocol/src/protocol/v2/thread.rs` adds optional `parent_thread_id` to `ThreadListParams` and marks it with `#[experimental(\"thread/list.parentThreadId\")]`.", + "`codex-rs/app-server-protocol/src/protocol/common.rs` enables request-parameter inspection for `thread/list`.", + "`codex-rs/app-server/src/request_processors/thread_processor.rs` parses the optional parent thread id and stores it in thread-list filters.", + "`codex-rs/thread-store/src/local/list_threads.rs` routes parent-filtered list requests through the state DB and errors when the state DB is unavailable for parent-filtered listing.", + "`codex-rs/state/src/runtime/threads.rs` adds `list_threads_by_parent` backed by persisted spawn-edge matching.", + "`codex-rs/app-server/tests/suite/v2/thread_list.rs` adds coverage for direct children, omitted grandchildren, pagination, malformed IDs, mixed source kinds, explicit filters, and missing rollout files.", + "The normalized bundle `artifacts/github/bundles/openai-codex-pr-26662.json` records 27 changed files for the merged PR." + ], + "next_actions": [ + { + "reason": "The new parent-filtered thread listing can improve Decodex Control Plane subagent visibility and recovery flows.", + "type": "upstream_impact" + }, + { + "reason": "The change has a clear operator-facing public angle around subagent/thread-tree recovery through app-server.", + "type": "social_candidate" + } + ], + "observed_change": "Codex adds an experimental `thread/list.parentThreadId` filter that returns direct spawned child threads from persisted spawn-edge state while preserving the existing list response shape and filters.", + "repo": "openai/codex", + "reviewed_at": "2026-06-14T18:08:07Z", + "schema": "upstream_review/v1", + "slug": "openai-codex-pr-26662", + "source_refs": { + "items": [ + { + "kind": "pull_request", + "meta": "Merged 2026-06-14T07:14:27Z", + "title": "feat(app-server): filter threads by parent", + "url": "https://github.com/openai/codex/pull/26662" + }, + { + "kind": "commit", + "title": "feat(app-server): filter threads by parent", + "url": "https://github.com/openai/codex/commit/68567deb6f6e9227662c9558d37ff3e280a2b377" + }, + { + "kind": "commit", + "title": "refactor(app-server): source parent filter from spawn edges", + "url": "https://github.com/openai/codex/commit/724cd58bf6ed04ffaf8ab8520c951a5518f3161a" + }, + { + "kind": "commit", + "title": "docs(app-server): clarify parent thread filter scope", + "url": "https://github.com/openai/codex/commit/688537c78d85337d3bc70e80a7e74fcfe11da6ce" + } + ] + }, + "subject": { + "commit_shas": [ + "68567deb6f6e9227662c9558d37ff3e280a2b377", + "724cd58bf6ed04ffaf8ab8520c951a5518f3161a", + "c2f877a1d0c5dbab82f5d7fcb4c591b90e9541f8", + "e06ed34720737e1657c74fdc466972c5fdda5ac4", + "eaeb92854e2d6da708558a8f0b81ff7cacdfd569", + "4c1fbf28545273cd4ba9402a4065171b646824f9", + "28d35a99eff66cf06742933e4a45fde47fb927d5", + "ba23593c751b155e4a86d2e6c24125a4b177a8c6", + "95d0018d71d9b15ccac883561abd1d408cf0f875", + "688537c78d85337d3bc70e80a7e74fcfe11da6ce" + ], + "subject_id": "26662", + "subject_kind": "pr" + }, + "user_visible_path": "App-server clients can call `thread/list` with experimental `parentThreadId` to list direct spawned child threads for a parent thread after reconnects or missed events, without scanning unrelated sessions or rollout transcripts." +} diff --git a/artifacts/github/reviews/openai-codex-pr-28122.review.json b/artifacts/github/reviews/openai-codex-pr-28122.review.json new file mode 100644 index 000000000..c6159d2aa --- /dev/null +++ b/artifacts/github/reviews/openai-codex-pr-28122.review.json @@ -0,0 +1,88 @@ +{ + "adoption_opportunity": "Update Decodex Control Plane remote-exec and multi-environment handling to preserve selected environment cwd as a `PathUri`, use the selected environment's discovered native shell when present, and classify unsupported foreign cwd permission requests as a cross-host path boundary instead of a transient exec failure.", + "caveats": "This PR improves remote-environment cwd and shell selection, but it still leaves some native-only request-permissions boundaries in place and falls back to the session shell when the remote environment has not reported a shell.", + "changed_surfaces": [ + "core `TurnEnvironmentSelection.cwd` representation", + "app-server thread and turn request processors", + "core environment-selection resolution", + "session request-permissions cwd handling", + "unified exec command shell selection", + "remote Windows exec-server Wine test fixture", + "core protocol and remote-environment tests" + ], + "community_value": "High for remote executor and multi-environment users because the change moves Codex closer to target-native cwd and shell handling instead of forcing local-host assumptions onto remote environments.", + "compatibility_risk": "High. Integrations that construct `TurnEnvironmentSelection` or reason about remote-environment cwd as a host-local absolute path must now preserve `PathUri` values and handle explicit native-only rejection at permission boundaries.", + "confidence": "confirmed", + "control_plane_relevance": "High. Decodex Control Plane remote execution depends on selecting the right environment cwd and shell, especially when the executor host differs from the operator host.", + "deprecated_or_breaking_notes": "`TurnEnvironmentSelection.cwd` changes from `AbsolutePathBuf` to `PathUri`; app-server request processors convert local cwd values with `PathUri::from_abs_path`, and core converts back to native absolute paths only at native-only consumer boundaries.", + "evidence": [ + "PR #28122 says Codex changes `TurnEnvironmentSelection.cwd` from `AbsolutePathBuf` to `PathUri`, preserves remote primary cwd, prefers the selected environment's discovered shell, and rejects unsupported foreign cwd values at request-permissions boundaries.", + "`codex-rs/protocol/src/protocol.rs` changes the turn environment selection cwd field to `PathUri` and adds local-environment conversion logic.", + "`codex-rs/app-server/src/request_processors/thread_processor.rs` and `turn_processor.rs` convert app-server local environment cwd values with `PathUri::from_abs_path` before creating `TurnEnvironmentSelection` values.", + "`codex-rs/core/src/environment_selection.rs` resolves selected cwd values through `to_abs_path()` only where the current consumer still requires a native host path.", + "`codex-rs/core/src/tools/handlers/unified_exec/exec_command.rs` now chooses the turn environment shell when available and falls back to the session shell otherwise.", + "`codex-rs/core/src/session/mod.rs` returns a default permission response and warning when request permissions receive a cwd URI that is not native to the Codex host.", + "`codex-rs/core/tests/remote_env_windows/remote_env_windows_test.rs` extends the Wine-backed remote Windows fixture to run PowerShell in `C:\\windows` and records app-server rejection for native Windows cwd at current boundaries.", + "The normalized bundle `artifacts/github/bundles/openai-codex-pr-28122.json` records 22 changed files for the merged PR." + ], + "next_actions": [ + { + "reason": "Remote-environment cwd and shell semantics directly affect Decodex app-server and Control Plane compatibility.", + "type": "upstream_impact" + }, + { + "reason": "The change has a clear operator-facing public angle around cross-OS remote execution and native shell/cwd handling.", + "type": "social_candidate" + } + ], + "observed_change": "Codex changes turn environment cwd handling to preserve `PathUri` values and makes unified exec prefer the selected remote environment's native shell.", + "repo": "openai/codex", + "reviewed_at": "2026-06-14T18:08:07Z", + "schema": "upstream_review/v1", + "slug": "openai-codex-pr-28122", + "source_refs": { + "items": [ + { + "kind": "pull_request", + "meta": "Merged 2026-06-14T06:07:47Z", + "title": "[codex] exec-server honors remote environment cwd and shell", + "url": "https://github.com/openai/codex/pull/28122" + }, + { + "kind": "commit", + "title": "core: carry turn environment cwd as PathUri", + "url": "https://github.com/openai/codex/commit/a2a917b071ce164777333349163005720c8c5e7f" + }, + { + "kind": "commit", + "title": "core: honor remote environment cwd and shell", + "url": "https://github.com/openai/codex/commit/019ff65142c38263fd685f9692670aeeb560c5c6" + }, + { + "kind": "commit", + "title": "tests: send native Windows cwd through app server", + "url": "https://github.com/openai/codex/commit/763357aaa79a5fb13f84a5013deb2ff284a67bd4" + } + ] + }, + "subject": { + "commit_shas": [ + "a2a917b071ce164777333349163005720c8c5e7f", + "019ff65142c38263fd685f9692670aeeb560c5c6", + "5bada3f2a4f18a252cd65d89f461d3ff3c9f4b1f", + "2a8b87ed44215e4bf0bcce6b778038874c720b51", + "310ccf29f684a7a19ae65ea790bd465cfe74cb2a", + "763357aaa79a5fb13f84a5013deb2ff284a67bd4", + "ce4102787545b9131e32619e43ed89dc0ad13f12", + "4f6dd50b0eb01f3548c7b1403017e74c8697ef51", + "f4db0780fc9ef2063e29847f851759c5bd97dbe1", + "25644e0ec49ebf371ab45c8ae73b3cb8fd78607e", + "18004b9322a89dd9efc40aea3f88643cdfc55eed", + "716e9e32e934a3f7b868a1bc7a327524594dc81e", + "1a7dbd5b4ff43cdf230f8b7062e6c1618ed458dc" + ], + "subject_id": "28122", + "subject_kind": "pr" + }, + "user_visible_path": "Remote-environment unified exec can use the selected environment's cwd URI and native shell; app-server and Control Plane clients must preserve cwd URI shape and handle current native-only permission-boundary rejection for unsupported foreign cwd values." +} diff --git a/artifacts/github/social-candidates/openai-codex-pr-26662.json b/artifacts/github/social-candidates/openai-codex-pr-26662.json new file mode 100644 index 000000000..0ab69c363 --- /dev/null +++ b/artifacts/github/social-candidates/openai-codex-pr-26662.json @@ -0,0 +1,53 @@ +{ + "audience": "Control Plane operators and app-server client builders", + "candidate_text": [ + "Codex app-server adds experimental `thread/list.parentThreadId`: clients can list direct spawned child threads from persisted spawn edges without scanning rollout history. Useful for subagent UIs and recovery flows. PR: https://github.com/openai/codex/pull/26662" + ], + "caveats": [ + "Do not imply recursive thread-tree listing.", + "Keep the claim scoped to experimental direct spawned-child listing from persisted state." + ], + "channel": "x", + "claims": [ + { + "confidence": "confirmed", + "evidence": "artifacts/github/reviews/openai-codex-pr-26662.review.json", + "text": "Codex app-server adds an experimental parentThreadId filter to thread/list." + }, + { + "confidence": "confirmed", + "evidence": "artifacts/github/impact/openai-codex-pr-26662.json", + "text": "Parent-filtered thread listing is a Decodex Control Plane adoption opportunity." + } + ], + "decision": { + "idempotency_key": "x:decodexspace:openai-codex-pr-26662:operator_impact", + "reason": "The change has a concrete subagent recovery and operator-UI angle with direct source links.", + "worthiness": "publish" + }, + "evidence_notes": [ + "ThreadListParams adds experimental parentThreadId.", + "Parent-filtered listing uses persisted spawn edges.", + "Tests cover direct children, omitted grandchildren, filters, pagination, and malformed IDs." + ], + "mode": "operator_impact", + "next_steps": [ + "Let Publisher automation decide whether to reserve or publish this candidate." + ], + "priority": "high", + "repo": "openai/codex", + "schema": "social_candidate/v1", + "slug": "openai-codex-pr-26662", + "source_refs": { + "upstream_impacts": [ + "artifacts/github/impact/openai-codex-pr-26662.json" + ], + "upstream_reviews": [ + "artifacts/github/reviews/openai-codex-pr-26662.review.json" + ], + "urls": [ + "https://github.com/openai/codex/pull/26662" + ] + }, + "target_account": "decodexspace" +} diff --git a/artifacts/github/social-candidates/openai-codex-pr-28122.json b/artifacts/github/social-candidates/openai-codex-pr-28122.json new file mode 100644 index 000000000..76bb914ab --- /dev/null +++ b/artifacts/github/social-candidates/openai-codex-pr-28122.json @@ -0,0 +1,53 @@ +{ + "audience": "Control Plane operators and remote exec-server integrators", + "candidate_text": [ + "Codex remote exec now preserves environment cwd as `PathUri` and uses the selected environment's native shell for unified exec. Integrations need cross-OS cwd handling. PR: https://github.com/openai/codex/pull/28122" + ], + "caveats": [ + "Do not imply all foreign cwd request-permissions paths are fully supported.", + "Keep the claim scoped to turn environment cwd, selected shell handling, and unified exec." + ], + "channel": "x", + "claims": [ + { + "confidence": "confirmed", + "evidence": "artifacts/github/reviews/openai-codex-pr-28122.review.json", + "text": "Codex preserves selected turn environment cwd values as PathUri." + }, + { + "confidence": "confirmed", + "evidence": "artifacts/github/impact/openai-codex-pr-28122.json", + "text": "Remote-environment cwd and native-shell handling is a Control Plane compatibility risk." + } + ], + "decision": { + "idempotency_key": "x:decodexspace:openai-codex-pr-28122:operator_impact", + "reason": "The change has a concrete remote-exec compatibility angle with direct source links.", + "worthiness": "publish" + }, + "evidence_notes": [ + "TurnEnvironmentSelection.cwd changed to PathUri.", + "Unified exec now prefers the selected environment shell.", + "Current native-only permission boundaries reject unsupported foreign cwd values." + ], + "mode": "operator_impact", + "next_steps": [ + "Let Publisher automation decide whether to reserve or publish this candidate." + ], + "priority": "high", + "repo": "openai/codex", + "schema": "social_candidate/v1", + "slug": "openai-codex-pr-28122", + "source_refs": { + "upstream_impacts": [ + "artifacts/github/impact/openai-codex-pr-28122.json" + ], + "upstream_reviews": [ + "artifacts/github/reviews/openai-codex-pr-28122.review.json" + ], + "urls": [ + "https://github.com/openai/codex/pull/28122" + ] + }, + "target_account": "decodexspace" +}