Skip to content

Blocking-fresh aft_inspect holds the project execution lane; unrelated agents' mutations queue 25-60s behind it #242

Description

@iceteaSA

Blocking-fresh aft_inspect holds a project's execution lane for the full duration of its scan. On a shared root with parallel agents, every unrelated mutation queues behind it. Observed on v0.51.2 with three concurrent implementer sessions on one project.

This is not the v0.51.1 wedge — the deadlines work, nothing hangs forever. It's the cost of the design surfacing under concurrency.

Evidence

Log timestamps are completion times, so a queued call and the inspect that blocked it are logged at the same instant. That pairing is the signature:

T20:02:36  inspect      exec=64.3s              [oa-path-alias-impl]
T20:02:36  apply_patch  queue=24.7s  exec=0.0s  [oa-ws-no-replay-impl]   <- released when inspect ended

T20:04:41  inspect      exec=63.1s              [oa-path-alias-impl]
T20:04:41  safety       queue=53.8s  exec=0.0s  [oa-ws-no-replay-impl]

T20:06:14  inspect      exec=63.0s              [oa-path-alias-impl]
T20:06:14  apply_patch  queue=59.5s  exec=0.0s  [oa-ws-no-replay-impl]

Three inspects, three blocked calls from a different session on the same root, each released exactly when the inspect completed.

The same apply_patch when no inspect is running:

T20:01:23  apply_patch  queue=0.0s  exec=0.2s
T20:03:08  apply_patch  queue=0.0s  exec=0.1s
T20:03:13  apply_patch  queue=0.0s  exec=0.1s
T20:06:33  apply_patch  queue=0.0s  exec=0.1s

0.1–0.2s normally, 25–60s behind an inspect. The lane is healthy except during inspect.

Aggregate over an 8-minute window, 9 sessions:

inspect      n=3   total=190.4s   exec=190.4s   queue=0.0s
apply_patch  n=10  total= 85.3s   exec=  1.0s   queue=84.2s
safety       n=1   total= 53.8s   exec=  0.0s   queue=53.8s

apply_patch spent 84 of its 85 seconds waiting.

Why it's worse than the numbers suggest

BLOCKING_TIER2_PHASE_TIMEOUT is 120s (commands/inspect.rs:24), per phase. The 63s scans above are well inside the bound — a legitimately slow root can hold the lane substantially longer, and the bound is what keeps it finite rather than what keeps it short.

The blast radius is also wider than the caller: the blocked calls came from sessions that never invoked inspect. One agent's diagnostic call stalls every other agent on that root.

Parallel implementer subagents on one repo is the workload where this concentrates, and it's exactly the workload the tool encourages — each agent independently running aft_inspect to check its own edits.

What I'm not claiming

Not a regression against v0.51.1: the deadlines hold and calls terminate. Not a report that inspect is too slow in itself — 63s for a full-root verified-fresh scan may be the honest cost. The issue is specifically that the cost is paid by unrelated concurrent callers on a shared lane, silently, as queue time they cannot see or attribute.

Fix directions

  1. Don't hold the mutating lane across the LSP/Tier-2 wait. The v0.51.1 fix for the wedge made the wait terminate; the same shape as LspManager mutex is held across the post-edit diagnostics wait (up to 10s), serializing every other LSP operation #216's parked-waiter would let it wait off-lane. Probably the real fix.
  2. Coalesce concurrent inspects on one root — three full scans in four minutes from the same session is redundant work regardless of lane behaviour; the later two could join the first's result.
  3. Surface the blocking occupant in the queued call's response so an agent stuck for 60s can see it's waiting on someone else's inspect rather than assuming the daemon is broken. Cheapest of the three and useful even if 1 lands.

Environment

v0.51.2 (aa027c6f, one commit above 1d2da675, the extra commit is an unrelated tool), Linux, subc daemon transport, 9 concurrent sessions across ~6 roots.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions