From 5e8225505c3bc4f28476f015189c41b1e128907e Mon Sep 17 00:00:00 2001 From: _Kerman Date: Sun, 26 Jul 2026 17:22:50 +0800 Subject: [PATCH] refactor(agent-loop): state slot invariants directly instead of guarding them MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The coverage pass left agent.ts with eight v8 ignore annotations — well above this repo's density elsewhere. Six guarded conditions the surrounding invariants already exclude; expressing the invariant directly deletes the dead arm instead of excusing it: admission/run teardown releases the abort slot unconditionally (no writer can replace the owner mid-flight), the request-failed branch closes its always-open step unconditionally, the recovery finally retires the window it installed, and the driver finally drops its dead last-resort step close (every path already closes the step). kick()'s dequeue states the non-empty-queue invariant as a non-null assertion. The two remaining ignores are the assertNever exhaustiveness guard and the retry()/run() slot-race guard, both repo-wide conventions. --- packages/core/agent-loop/src/agent.ts | 43 +++++++++++---------------- 1 file changed, 17 insertions(+), 26 deletions(-) diff --git a/packages/core/agent-loop/src/agent.ts b/packages/core/agent-loop/src/agent.ts index 50d01024e0..7176fdeb0d 100644 --- a/packages/core/agent-loop/src/agent.ts +++ b/packages/core/agent-loop/src/agent.ts @@ -196,10 +196,10 @@ export class ReactLoopAgent implements Agent { /** Claim and admit the next queued prompt, then start its turn. */ private kick(): void { if (this.abort !== undefined || !this.queued.some(item => item.wakeup)) return - const item = this.queued.shift() - /* v8 ignore next -- unreachable: the some() guard above proves the queue is non-empty */ - if (item === undefined) return - const { message } = item + // The some() guard above proves the queue is non-empty; the non-null + // assertion expresses that invariant. + // eslint-disable-next-line @typescript-eslint/no-non-null-assertion + const { message } = this.queued.shift()! emitAgentEvent(this.loopCtx, this, 'agent/inbox/dequeue', message) const admission = new AbortController() @@ -232,9 +232,8 @@ export class ReactLoopAgent implements Agent { // cancel() aborts but never clears the slot, and kick()/run()/retry() // all refuse to install a new owner while one exists, so the admission - // still owns the slot here. - /* v8 ignore next -- unreachable false arm: no writer replaces the abort owner mid-admission */ - if (this.abort === admission) this.abort = undefined + // still owns the slot here and releasing it unconditionally is exact. + this.abort = undefined if (admitted === undefined) { this.continueOrIdle() return @@ -297,11 +296,8 @@ export class ReactLoopAgent implements Agent { case 'request-failed': { // step() reports request failures only after step/start commits // and before its own step/end, so the step is always open here. - /* v8 ignore next -- unreachable false arm, see above */ - if (this.stepOpen) { - this.stepOpen = false - this.session.append('step/end', { turn, step }) - } + this.stepOpen = false + this.session.append('step/end', { turn, step }) if (agentInterruptReasonOf(signal) === undefined) { const retryWindow = { requested: false } this.retryWindow = retryWindow @@ -319,9 +315,9 @@ export class ReactLoopAgent implements Agent { ) } finally { // Nothing else writes the window while the waterfall runs: - // cancel() only flips `requested` and a second run cannot start. - /* v8 ignore next -- unreachable false arm, see above */ - if (this.retryWindow === retryWindow) this.retryWindow = undefined + // cancel() only flips `requested` and a second run cannot + // start, so unconditional retirement is exact. + this.retryWindow = undefined } retry = recoveryCompleted && agentInterruptReasonOf(signal) === undefined @@ -347,15 +343,10 @@ export class ReactLoopAgent implements Agent { } ({ reason, idle } = this.settle(turn, step, caught, signal)) } finally { + // Every step-close happens before this point on both success and + // failure paths (step(), the request-failed branch, the catch), so the + // finally owes only the turn boundary. try { - // Every step-close before this point clears the flag on both success - // and failure paths (step(), the request-failed branch, the catch), - // so the finally never finds a step still open. - /* v8 ignore next 4 -- unreachable last-resort step close, see above */ - if (this.stepOpen) { - this.stepOpen = false - this.session.append('step/end', { turn, step }) - } if (this.turnOpen) { // Re-entrant turn/end listeners must route new input to a later turn. this.turnOpen = false @@ -368,9 +359,9 @@ export class ReactLoopAgent implements Agent { } this.retryWindow = undefined // cancel() aborts but never clears the slot, and no second run can - // install a controller while this one is still unwinding. - /* v8 ignore next -- unreachable false arm, see above */ - if (this.abort === controller) this.abort = undefined + // install a controller while this one is still unwinding, so the slot + // is still this run's controller here. + this.abort = undefined signal.removeEventListener('abort', cancelRetry) }