orchestrator-wake: failed admissions can strand recovery retries
Summary
Two failed-admission paths can leave the orchestrator-wake scheduler with pending work but no further retry. Both behaviors reproduce in source-level probes of the published 2.2.20 and 2.2.21 bundles.
This is a scheduler test with a mocked SDK, not an end-to-end host reproduction or a claim that normal child completion is broken.
Environment
- OpenCode: 2.0.3 on Linux x86_64; host V2 children-driven wake mode informed the test setup.
- OMO: installed 2.2.20 and the published npm 2.2.21 package, downloaded only to a sandbox; package integrity and bundle hashes verified.
- Test runner: Node.js 22.22.3,
node:vm, fake clock, in-memory session SDK. - Actual shipped scheduler/helper source is extracted unchanged. The mocked
promptAsyncrejects before admission; no session is actually woken.
Reproduction
A. SDK rejections consume the no-progress budget
- Create an enabled children-mode scheduler with an eligible idle orchestrator and a recent active child. Keep the child fingerprint unchanged.
- Make
promptAsyncreject its first two calls. - Emit the idle event and advance the fake clock through both evaluations.
- Emit another idle event.
Observed: attempts advance 1 → 2, unchangedWakeCount advances 1 → 2, and stopped becomes true. No timer or third attempt is scheduled, despite neither wake being admitted. commitWakeReservation increments the budget before the SDK call.
B. Stopped-job recovery loses its retry context
- With no active child, call
triggerStoppedJobRecoveryfor an idle parent with current recovery details. - Reject the first
promptAsynccall, then allow future calls to succeed. - Advance the timer scheduled after the rejection.
Observed: the timer invokes ordinary evaluation without the recovery flag. It concludes no-work, leaving one attempted send and zero timers. Recovery details remain present: a later externally supplied idle event causes a second send containing those details.
Expected Behavior
Rejected admission should not be counted as an admitted wake that made no progress. Pending stopped-job recovery should retain a bounded retry path after transient admission failure, without requiring another external event.
Actual Behavior
Retries stop in both scenarios above. Positive controls send a wake for an active child, and busy/input-wait guards still suppress inappropriate wakes.
Additional Context
The same corrected probe exercises both versions; 16 checks pass per version, meaning the observations and controls are reproduced, not that the bugs are fixed. Version 2.2.21's scheduler differs from 2.2.20, so its tests were rerun rather than inferred from the older bundle.
This report is limited to failed-admission retry behavior. It is not a regression claim about #1137, and does not propose treating every idle session or historical terminal child as unfinished work.
The probe assumes eligible sessions and current recovery facts; it does not exercise 2.2.21's real selection resolver, coordinator, SDK, or their event side effects. These are source-level bug candidates, not a claim of demonstrated production incidence for either retry path.
Source: alvinunreal/oh-my-opencode-slim