Skip to content

Session-bound worktree freshness/ingress can stall basic MCP tools; warm single-file mutations trigger full-root reconciliation #390

Description

@baron

Title

Session-bound worktree freshness/ingress can stall basic MCP tools; warm single-file mutations trigger full-root reconciliation

Proposed labels

bug, area:mcp, area:worktrees

Body

Summary

Session-bound worktree roots appear to have a shared freshness / publisher-ingress failure layer that can affect multiple MCP surfaces at once. This is adjacent to, but distinct from, the narrower work already split across:

This follow-up is for the lower-level worktree freshness / ingress / reconciliation path. The observed symptoms are:

  1. basic tools can time out or hang before doing their actual work because they wait on workspace freshness / ingress;
  2. successful single-file mutations in a warm session-bound worktree can still take ~8-12s while read/search/tree are subsecond;
  3. the current diagnostics do not clearly identify which root/barrier is stuck or why a full-root reconcile was required.

Duplicate / related issue check

Related but not duplicates:

This issue assumes #382/#387 and #383/#388 remain their own tracks. Acceptance criteria here should not absorb those PRs if their exact implementation changes.

Environment / evidence note

Evidence comes from local RepoPrompt CE worktree-bug investigations on July 6, 2026. Code paths were checked against the current worktree-bug branches and main-line source around 8cf39f70. Timings below are coarse local observations, not formal benchmark artifacts.

Observed behavior

A live session-bound worktree investigation saw basic read/search/tree become fast after reopening the workspace, but mutation tools remained much slower:

get_file_tree: ~0.18s
file_search: ~0.18s
read_file: ~0.27s
file_actions create: ~12.1s
apply_edits one-line replacement: ~8.4s
read_file after edit: ~0.13s
file_actions delete: ~8.5s

Separate evidence from the same worktree-bug investigation showed file_search failing before search began with a typed freshness result:

Status: Workspace freshness timed out
Code: workspace_freshness_timeout
Retryable: yes

That indicates the search did not actually run. It timed out at the shared workspace freshness barrier.

Code paths implicated

Confirmed from code review:

  • StoreBackedWorkspaceSearch gates file_search on awaitAppliedIngress(...) and races that wait against MCPTimeoutPolicy.workspaceFreshnessWaitTimeout (currently 30s), returning typed workspace_freshness_timeout before search begins.
  • WorkspaceReadableFileService uses the same awaitAppliedIngressForExplicitRequest(...) family for explicit read-file requests.
  • MCPApplyEditsToolProvider waits on explicit-request freshness before validation and after writes.
  • file_actions waits before mutation and again after mutation / selection updates.
  • tree, selection, prompt/context, and code-structure paths also touch the same awaitAppliedIngress* family.
  • WorkspaceFileContextStore.awaitAppliedIngress(...) captures watcher watermark plus accepted publisher sequence, then waits for publisher ingress, watcher flush, and downstream publication application.
  • WorkspaceFileSystemIngressCoordinator can pause drain during handoff; waiters only release when application advances and wakes them.

The important asymmetry: file_search already has an explicit timeout race and typed retryable error. Other basic tools appear to await the underlying freshness family without equivalent typed, root-scoped freshness failures, so they can hang until request cancellation or burn a generic server deadline.

Current hypotheses

These are plausible, not yet proven:

Hard freshness stall

A session-bound worktree root may leave publisher ingress with an accepted publication that never reaches applied state, or with drain paused during handoff, or with a drain handler stuck before finishApplying. Any tool waiting on freshness for that root can then block behind the same barrier.

Potential diagnostic states to capture:

  • accepted service publication sequence > applied service publication sequence;
  • watcher watermark target not flushed/applied;
  • pending queue not draining;
  • applyingCount > 0 without progress;
  • paused handoff state not resumed;
  • waiters accumulating on the root.

Finite mutation latency

The 8-12s successful mutation timings look separate from a hard stall. The leading hypothesis is unnecessary synchronous full-root reconciliation after a self-authored single-file mutation:

self-authored mutation
→ seeded/worktree authority invalidated by the mutation itself
→ post-mutation freshness wait blocks
→ authority snapshot/fence recapture
→ reconcilePublishedSeededAuthority
→ reconcileEntireTreeForAuthorityChange
→ full-root crawl before tool reply is released

If the watcher and self-authored mutation publication path are healthy, ordinary one-file mutations should reconcile incrementally using known touched path(s), operation type, publication token/sequence, and root/worktree projection. Full-root reconcile should be exceptional repair, not the normal hot path for a single-file edit/create/delete.

Expected behavior

  • Basic tools in a session-bound worktree should not hang indefinitely behind workspace freshness / ingress.
  • If freshness cannot be reached, tools should return typed, retryable, root-scoped errors naming the blocking layer.
  • A warm one-file mutation in a watched session-bound worktree should not synchronously trigger full-root reconciliation on the tool response path.
  • Codemap/code-structure readiness should not block basic read/search/edit/file-action tools.
  • Diagnostics should make it clear which root and which barrier is blocking progress.

Acceptance criteria

Phase 1: bounded typed freshness behavior

Phase 1: root-level diagnostics

  • Freshness timeout/unavailable responses include a bounded diagnostic snapshot for the affected root(s), redacted as needed, including:
    • root kind / session-worktree marker;
    • accepted vs applied service publication sequence and gap;
    • watcher watermark target vs applied/flushed watermark;
    • pending queue count;
    • applying count;
    • paused-handoff state;
    • waiter count;
    • oldest outstanding publication age;
    • whether codemap work is pending separately.

Phase 1: handoff / ingress progress

  • Session-bound worktree handoff cannot leave publisher ingress paused or with unapplied accepted publications indefinitely.
  • If handoff fails, paused subscriptions are resumed or force-terminalized, waiters are released, and later tools receive a typed retryable freshness/worktree-readiness error instead of hanging.
  • A hung drain handler or stuck applyingCount has a recovery / diagnostic path.

Phase 2: mutation latency / incremental reconcile

This phase may become a follow-up PR if diagnostics show it should be split from the hard freshness-stall work.

  • Warm one-file apply_edits in a watched session-bound worktree does not trigger reconcileEntireTreeForAuthorityChange on the synchronous tool-response path.
  • Warm one-file file_actions create/delete/move in a watched session-bound worktree does not trigger synchronous full-root reconcile on the tool-response path.
  • Full-root reconcile is reserved for explicit repair/recovery cases such as initial root load, watcher overflow/dropped events, root replacement/authority corruption, or explicit rescan.
  • If a full-root reconcile is required, it is diagnostic-tagged with the reason and does not block unrelated basic tools without a typed bounded freshness result.
  • Suggested warm-path budget for simple one-file mutation in a session-bound worktree: p50 <= 1s, p95 <= 2.5s, with instrumentation showing where time is spent.

Verification: codemap independence

  • Confirm, and enforce with regression coverage, that stale or slow codemap/code-structure generation does not block read_file, file_search, apply_edits, file_actions, or file tree for basic filesystem operations.
  • get_code_structure may report codemap readiness/staleness for its own output, but codemap freshness is not a global blocker for unrelated tools.

Suggested instrumentation

Add bounded DEBUG diagnostics / perf stages around:

  • pre-mutation freshness wait;
  • host write / actual file operation;
  • post-mutation awaitAppliedIngressForExplicitRequest;
  • publisher ingress accepted/applied sequence changes;
  • watcher watermark flush/apply;
  • requirePublishedSeededAuthorityFresh / authority fence recapture;
  • reconcilePublishedSeededAuthority;
  • reconcileEntireTreeForAuthorityChange count and duration;
  • post-mutation catalog / selection / token-accounting phases.

Non-goals for this issue

Notes for implementation planning

This issue likely spans:

  • Sources/RepoPrompt/Infrastructure/WorkspaceContext
  • Sources/RepoPrompt/Infrastructure/MCP
  • affected Agent Mode callers only where they wait on or report freshness/readiness

The first useful implementation step may be diagnostic-only: measure whether the 8-12s mutation path is dominated by post-mutation freshness, authority recapture, full-root reconcile, catalog refresh, or selection/token-accounting.

Metadata

Metadata

Assignees

No one assigned

    Labels

    area:mcpMCP server, clients, and connection visibilityarea:worktreesGit worktree behavior and interfacebugSomething isn't working

    Type

    No type

    Fields

    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions