Fix stale abort result contaminating replacement turns after interrupt

When interrupting a Claude agent mid-tool-call and sending a replacement
message, the SDK's abort error result was being attributed to the new
foreground turn, causing [System Error] banners and displaced replies.

Root cause: pendingInterruptAbort was cleared by visible activity from
the new turn before the stale result arrived (timing race), and the
stale result then poisoned the replacement turn.

Fix:
- Suppress stale non-success results at the top of routeSdkMessageFromPump
  before any turn attribution, using both flag-based (pendingInterruptAbort)
  and content-based (isAbortError) detection
- Stop clearing pendingInterruptAbort on visible activity — only consume
  it when a result message arrives
- Prevent idle flash during replacement by checking pendingReplacement
  in agent-manager turn_completed/turn_canceled handlers
- Fix vitest env loading to use import.meta.url instead of process.cwd()
- Load .env.test eagerly in agent-configs.ts for collection-time availability

Includes regression tests covering the exact f160a2a3 daemon log ordering.
This commit is contained in:
Mohamed Boudra
2026-03-25 20:12:18 +07:00
parent 36327cad00
commit 08f25f065a
7 changed files with 388 additions and 34 deletions
@@ -1,9 +1,11 @@
import path from "node:path";
import { fileURLToPath } from "node:url";
import dotenv from "dotenv";
// Load package-local .env.test first for integration/E2E credentials, then repo-root .env fallback.
dotenv.config({ path: path.resolve(process.cwd(), ".env.test"), override: true });
dotenv.config({ path: path.resolve(process.cwd(), "../.env") });
const serverRoot = path.resolve(path.dirname(fileURLToPath(import.meta.url)), "../..");
dotenv.config({ path: path.resolve(serverRoot, ".env.test"), override: true });
dotenv.config({ path: path.resolve(serverRoot, "../.env") });
process.env.GIT_TERMINAL_PROMPT = "0";
process.env.GIT_SSH_COMMAND = "ssh -oBatchMode=yes";