Bound Git root discovery for metadata enrichment (#42132)

## Why

Git root discovery is optional metadata work, but filesystem probes can block. They should not exhaust Tokio's blocking pool, delay runtime shutdown, or prevent later turns from observing repository changes.

## What changed

- Add a shared `GitRootDiscovery` service that coalesces concurrent lookups for the same working directory and limits probes across directories.
- Run probes on detached threads, retain in-flight work across caller cancellation, and discard completed results instead of caching them.
- Use the service for turn and memory metadata enrichment, abort unused turn enrichment when its state is dropped, and limit memory metadata waits to one second.

## Testing

Add coverage for probe sharing, capacity limits, cancellation, fresh discovery, runtime shutdown, memory timeouts, and repositories restored after startup prewarming.

GitOrigin-RevId: bca46fc263e7a12a2f69146d8a0b3e7c7e0846cb
This commit is contained in:
Charlie Marsh authored and copyberry committed 2026-09-01 20:41:32 +00:00
1 parent bd89ce67cc
commit 8436b749a4
21 files changed
+562 -55

No files matched your search

+4
View File
@@ -169,6 +169,7 @@ use codex_thread_store::ResumeThreadParams;
use codex_thread_store::ThreadPersistenceMetadata;
use codex_thread_store::ThreadStore;
use codex_utils_audio::prepare_response_items as prepare_audio_response_items;
use codex_utils_git_discovery::GitRootDiscovery;
use codex_utils_path_uri::PathUri;
use futures::future::BoxFuture;
use futures::future::Shared;
@@ -418,6 +419,7 @@ pub(crate) struct SessionSpawnArgs {
pub(crate) installation_id: String,
pub(crate) auth_manager: Arc<AuthManager>,
pub(crate) models_manager: SharedModelsManager,
pub(crate) git_root_discovery: Arc<GitRootDiscovery>,
pub(crate) environment_manager: Arc<EnvironmentManager>,
pub(crate) skills_service: Arc<HostSkillsService>,
pub(crate) plugins_manager: Arc<PluginsManager>,
@@ -521,6 +523,7 @@ impl Session {
installation_id,
auth_manager,
models_manager,
git_root_discovery,
environment_manager,
skills_service,
plugins_manager,
@@ -775,6 +778,7 @@ impl Session {
installation_id,
auth_manager.clone(),
models_manager.clone(),
git_root_discovery,
model_info,
exec_policy,
tx_event.clone(),
+2 -1
View File
@@ -191,7 +191,8 @@ pub(super) async fn spawn_review_thread(
}];
let tc = Arc::new(review_turn_context);
if tc.environments.single_local_environment_cwd().is_some() {
tc.turn_metadata_state.spawn_git_enrichment_task();
tc.turn_metadata_state
.spawn_git_enrichment_task(Arc::clone(&sess.services.git_root_discovery));
}
// TODO(ccunningham): Review turns currently rely on `spawn_task` for TurnComplete but do not
// emit a parent TurnStarted. Consider giving review a full parent turn lifecycle
+3
View File
@@ -32,6 +32,7 @@ use codex_protocol::protocol::ThreadHistoryMode;
use codex_protocol::protocol::ThreadSource;
use codex_protocol::protocol::TurnEnvironmentSelections;
use codex_skills::SkillError;
use codex_utils_git_discovery::GitRootDiscovery;
use std::sync::OnceLock;
use tokio::sync::Semaphore;
@@ -636,6 +637,7 @@ impl Session {
installation_id: String,
auth_manager: Arc<AuthManager>,
models_manager: SharedModelsManager,
git_root_discovery: Arc<GitRootDiscovery>,
model_info: ModelInfo,
exec_policy: Arc<ExecPolicyManager>,
tx_event: Sender<Event>,
@@ -1411,6 +1413,7 @@ impl Session {
.with_legacy_custom_ca_fallback(),
session_telemetry,
models_manager: Arc::clone(&models_manager),
git_root_discovery,
tool_approvals: Mutex::new(ApprovalStore::default()),
guardian_rejection_circuit_breaker: Mutex::new(Default::default()),
runtime_handle: tokio::runtime::Handle::current(),
+5
View File
@@ -6327,6 +6327,7 @@ async fn session_new_fails_when_zsh_fork_enabled_without_packaged_zsh() {
"11111111-1111-4111-8111-111111111111".to_string(),
auth_manager,
models_manager,
Arc::default(),
model_info,
Arc::new(ExecPolicyManager::default()),
tx_event,
@@ -6539,6 +6540,7 @@ pub(crate) async fn make_session_and_context() -> (Session, TurnContext) {
.with_legacy_custom_ca_fallback(),
session_telemetry: session_telemetry.clone(),
models_manager: Arc::clone(&models_manager),
git_root_discovery: Arc::default(),
tool_approvals: Mutex::new(ApprovalStore::default()),
guardian_rejection_circuit_breaker: Mutex::new(Default::default()),
runtime_handle: tokio::runtime::Handle::current(),
@@ -6782,6 +6784,7 @@ async fn make_session_with_config_and_rx(
"11111111-1111-4111-8111-111111111111".to_string(),
auth_manager,
models_manager,
Arc::default(),
model_info,
Arc::new(ExecPolicyManager::default()),
tx_event,
@@ -6908,6 +6911,7 @@ async fn make_session_with_history_source_and_agent_control_and_rx(
"11111111-1111-4111-8111-111111111111".to_string(),
auth_manager,
models_manager,
Arc::default(),
model_info,
Arc::new(ExecPolicyManager::default()),
tx_event,
@@ -8820,6 +8824,7 @@ where
.with_legacy_custom_ca_fallback(),
session_telemetry: session_telemetry.clone(),
models_manager: Arc::clone(&models_manager),
git_root_discovery: Arc::default(),
tool_approvals: Mutex::new(ApprovalStore::default()),
guardian_rejection_circuit_breaker: Mutex::new(Default::default()),
runtime_handle: tokio::runtime::Handle::current(),
@@ -1287,6 +1287,7 @@ async fn guardian_subagent_does_not_inherit_parent_exec_policy_rules() {
installation_id: "11111111-1111-4111-8111-111111111111".to_string(),
auth_manager,
models_manager,
git_root_discovery: Arc::default(),
environment_manager: Arc::new(EnvironmentManager::default_for_tests()),
skills_service,
plugins_manager,
+3 -1
View File
@@ -1035,7 +1035,9 @@ impl Session {
.single_local_environment_cwd()
.is_some()
{
turn_context.turn_metadata_state.spawn_git_enrichment_task();
turn_context
.turn_metadata_state
.spawn_git_enrichment_task(Arc::clone(&self.services.git_root_discovery));
}
turn_context
}