Harden Code Mode tool-call completeness tracking (#44472)

## Why

Reused call IDs, ambiguous exec/wait associations, and missing history can make tool-call completeness claims unreliable. Truncating one cell's recorded calls should also preserve completeness for unrelated cells.

## What changed

- Track observed call and runtime cell IDs with bounded memory, including call IDs from initial history, and withhold completeness when evidence is missing or ambiguous.
- Validate exec/wait input-output associations and keep invalidated completeness from returning on retries. Withhold wait completeness after resume or fork, where runtime cell IDs can be reused.
- Keep truncation markers and omission counts local to each output, clearing completeness across the affected cell while preserving unrelated cells within the metadata budget.
- Refresh recording enablement from runtime configuration without changing execution features, and preserve the live recorder during legacy configuration reloads.

## Testing

Add regression coverage for reused IDs, compaction, resumed waits, mismatched wrappers, runtime recording changes, and metadata budgeting that preserves unrelated complete calls.

GitOrigin-RevId: 0bc85964bee079879620ec0664eea530a13b61fb
This commit is contained in:
ningyi-oai authored and copyberry committed 2026-09-10 08:57:35 +00:00
1 parent b348fc2667
commit 03f014564d
12 files changed
+1792 -658

No files matched your search

+16 -1
View File
@@ -1932,6 +1932,11 @@ impl Session {
}
pub(crate) async fn refresh_runtime_config(&self, next_config: Config) {
self.refresh_runtime_config_inner(next_config, /*refresh_recording*/ true)
.await;
}
async fn refresh_runtime_config_inner(&self, next_config: Config, refresh_recording: bool) {
// Refresh only the user layer from the incoming snapshot. Preserve thread-local
// layers such as request/session overrides that were present when this session
// was created.
@@ -1950,6 +1955,13 @@ impl Session {
config.mcp_servers = next_config.mcp_servers.clone();
config.mcp_optional_startup_grace = next_config.mcp_optional_startup_grace;
config.mcp_oauth_credentials_store_mode = next_config.mcp_oauth_credentials_store_mode;
// Recording can follow rollout changes without changing the session's
// execution features (including Code Mode's dispatch gate).
if refresh_recording {
self.services
.executed_tool_calls
.refresh(&next_config.features);
}
if let Err(err) = config.features.set_enabled(
Feature::Mcp20260728,
next_config.features.enabled(Feature::Mcp20260728),
@@ -2144,7 +2156,10 @@ impl Session {
};
self.services.skills_service.clear_cache();
self.services.plugins_manager.clear_cache();
self.refresh_runtime_config(next_config).await;
// This legacy snapshot still has the original execution features, not
// the host's latest rollout settings. Leave the live recorder alone.
self.refresh_runtime_config_inner(next_config, /*refresh_recording*/ false)
.await;
}
/// Record a terminal CodexErr before the app-server completion notification is reduced.
+4 -1
View File
@@ -1478,7 +1478,10 @@ impl Session {
}).await;
}
let executed_tool_calls = crate::state::ExecutedToolCalls::new(&config.features);
let executed_tool_calls = crate::state::ExecutedToolCalls::new(
&config.features,
&initial_history,
);
let services = SessionServices {
// Start with an empty connection set. The initialized set is
// published after SessionConfigured so MCP events follow it.
+4 -2
View File
@@ -6592,7 +6592,8 @@ pub(crate) async fn make_session_and_context() -> (Session, TurnContext) {
));
let network_approval = Arc::new(NetworkApprovalService::default());
let mcp_runtime = Arc::new(codex_mcp::McpRuntime::empty(config.prefix_mcp_tool_names()));
let executed_tool_calls = crate::state::ExecutedToolCalls::new(&config.features);
let executed_tool_calls =
crate::state::ExecutedToolCalls::new(&config.features, &InitialHistory::Forked(Vec::new()));
let (hooks, async_hook_results) = Hooks::new(
HooksConfig {
legacy_notify_argv: config.notify.clone(),
@@ -8764,7 +8765,8 @@ where
));
let network_approval = Arc::new(NetworkApprovalService::default());
let mcp_runtime = Arc::new(codex_mcp::McpRuntime::empty(config.prefix_mcp_tool_names()));
let executed_tool_calls = crate::state::ExecutedToolCalls::new(&config.features);
let executed_tool_calls =
crate::state::ExecutedToolCalls::new(&config.features, &InitialHistory::Forked(Vec::new()));
let (hooks, async_hook_results) = Hooks::new(
HooksConfig {
legacy_notify_argv: config.notify.clone(),