refactor(agent-loop): state slot invariants directly instead of guarding them

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.
This commit is contained in:
_Kerman
2026-07-26 17:22:50 +08:00
parent 8117f61396
commit 5e8225505c

View File

@@ -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)
}