test(goal-session): pin the unsettled-attempt yield with a real failure path

The drive-pass guard for an unsettled attempt was wrongly annotated
unreachable after admission joined the running interval. It is reachable:
a contained turn-close failure (pre-commit turn/end rejection) reaches
idle with the attempt's turn open and no terminal reason, and the idle
drive pass must yield to that attempt instead of misreading the absent
reason as settled. Replace the ignore with a test driving exactly that
path; the guard's comment now names the real producer.
This commit is contained in:
_Kerman
2026-07-26 19:13:47 +08:00
parent 050090e512
commit 2985bc5267
2 changed files with 28 additions and 4 deletions

View File

@@ -176,10 +176,9 @@ export function apply(ctx: Context): void {
const attempt = state.attempt
if (attempt !== undefined) {
// Prompt admission joined the loop's running interval, so a drive pass
// (which requires idle) can no longer observe an unsettled attempt;
// kept as a backstop against a future trigger inside the interval.
/* v8 ignore next -- unreachable yield, see above */
// Still unsettled: a contained turn-close failure reaches idle with the
// attempt's turn open in the log and no terminal reason recorded, so
// the drive pass must yield rather than misread it as settled.
if (attempt.reason === undefined) return
state.attempt = undefined
const turn = attempt.turn

View File

@@ -712,6 +712,31 @@ describe('same-session goal driving', () => {
expect(test.adapter.requests).toHaveLength(1)
})
it('yields to a round whose turn/end never committed instead of misreading it as settled', async () => {
const test = await harness([textResponse('round ran')])
// A persistent pre-commit turn/end rejection: the loop contains the close
// failure and reaches idle, but the round's attempt holds a turn with no
// terminal reason. The idle drive pass must yield to that unsettled
// attempt rather than classify an absent reason or crash into disarm.
test.ctx.on('internal/dispatch', (_mode, name, args) => {
if (name !== 'session/event') return
const event = args[1] as { type: string }
if (event.type === 'turn/end') throw new Error('turn close permanently rejected')
})
test.ctx.goals.create(test.agent, { objective: 'survive a lost turn end' })
await waitForRequests(test.adapter, 1)
await test.agent.whenIdle()
await new Promise((resolve) => { setImmediate(resolve) })
// One request ran; the unsettled attempt parked the driver without a
// second reservation and without disarming the goal.
expect(test.adapter.requests).toHaveLength(1)
expect(test.ctx.goals.get(test.agent)).toMatchObject({
phase: 'active',
activation: 'armed',
})
})
it('disarms instead of continuing when a plugin reports a post-turn persistence failure', async () => {
const test = await harness([textResponse('round one')])
test.ctx.on('session/event', (session, event) => {