Skip to content

test(opencode): add regression test for lost terminal-iteration wakeup - #1

Merged
dreampuf merged 1 commit into
dreampuf:fix/runner-queue-background-notificationfrom
scotttesler:add-terminal-iteration-regression-test
Jul 20, 2026
Merged

test(opencode): add regression test for lost terminal-iteration wakeup#1
dreampuf merged 1 commit into
dreampuf:fix/runner-queue-background-notificationfrom
scotttesler:add-terminal-iteration-regression-test

Conversation

@scotttesler

@scottteslerscotttesler commented Jul 20, 2026

Copy link
Copy Markdown

Your fix in

is the right root-cause repair: adding the RunningThenRun state so ensureRunning queues new work instead of discarding it while the runner is already Running is exactly what stops a background-subagent notification from being lost. This PR adds only one regression test on top of your branch — no production changes.

Your tests already cover a single queued run: queuing behind a running turn, the RunningThenRun transition, and a third caller sharing the pending run. What none of them exercise is a repeated re-queue — a second notification that arrives after the first queued run has already been promoted to Running, forcing the runner to cycle Running → RunningThenRun → Running → RunningThenRun → Running. That's the real-world case of a parent session getting several background-subagent wakeups over its lifetime, so it's worth locking down.

The new test re-queues each run that arrives after the previous queued run is promoted (in packages/opencode/test/effect/runner.test.ts):

  • starts a parent turn and waits for Running;
  • queues notification A while the parent is busy and waits for RunningThenRun;
  • releases the parent and waits for A to be promoted back to Running;
  • queues notification B while A is running and waits for RunningThenRun a second time;
  • releases A, then asserts each caller receives its own result (parent, notify-a, notify-b), the work ran in order, and — via a flag A sets on completion that B reads at its start — that B was promoted only after A completed (serialization, not just start-ordering), ending back at Idle.

It synchronizes only on published state via waitForState, with no fixed sleeps, per the package's test-synchronization guidance.

The test fails on the pre-fix runner and passes with your fix. With the fix present:

$ bun test test/effect/runner.test.ts -t "re-queues each run that arrives after the previous queued run is promoted"
1 pass
0 fail
5 expect() calls

The full runner.test.ts file is 29 pass, 0 fail, and tsgo --noEmit, prettier --check, and oxlint are clean.

With only packages/opencode/src/effect/runner.ts reverted to its pre-fix parent (the test left unchanged):

(fail) Runner > re-queues each run that arrives after the previous queued run is promoted [1006ms]
TimeoutError: TimeoutError
0 pass
1 fail

Pre-fix the runner never reaches RunningThenRun because the queued work is dropped, so waitForState(runner, "RunningThenRun") times out — confirming the test guards the behavior your fix restores rather than passing vacuously.

Cover the queued-work path repaired in anomalyco#36375 (refs anomalyco#35066). When a
background subagent notifies the parent by calling ensureRunning while the
parent turn is still running, the runner must queue that work and cycle
Running -> RunningThenRun -> Running for every arrival instead of dropping
it. Exercise two back-to-back notifications so the runner re-enters
RunningThenRun a second time after the first queued run is promoted.
Without the fix the runner never enters RunningThenRun, so the queued
wakeup is lost: the test fails (waitForState times out) on the pre-fix
runner.ts and passes with the fix in place.
@dreampuf
dreampuf merged commit 85a2eed into dreampuf:fix/runner-queue-background-notificationJul 20, 2026
Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants

@scotttesler@dreampuf