anomalyco / anomalyco/opencode
Goal-mode round driver re-claims blindly after errors/cancel; quit leaves orphan rounds
@neriousy is already working on this.
Since Sep 9, 2026.
- Dominant language
- TypeScript
- Stars
- 209k
- Forks
- 27.5k
- PR merge metrics
- PR metrics pending
Description
Description
The goal-mode round driver (SessionPrompt.loop) re-claims unconditionally on every normal ensureRunning return, but that return is normal for three different outcomes: the single-flight Runner converts user cancel into its registered onInterrupt value for joiners (so the loop's onInterrupt(pauseOnCancel) never fires), and the processor converts provider failures into error-bearing "stop" results. Net: deterministic provider errors hot-retry burning the round budget, the stop button does not stop the loop, and quit/crash between admit-and-run leaves orphan synthetic goal_round messages with rounds spent.
Reproduction
- Run a goal-mode session against a stubbed HTTP 400 provider error (or press stop / quit mid-round)
- Observe: the loop re-runs the round instead of pausing (errors), cancel does not pause, quit leaves trailing unexecuted synthetic
goal_roundmessages - Expected: cancel pauses at once; dead rounds pause after 3 consecutive (2 when non-retryable); no orphan rounds after quit
Environment
- opencode v1.18.29 source build + a local goal-mode extension (same-session round driver +
/goalcommand, cf. #48240) on Linux. The re-claim mechanics (Runnercancel conversion, error-to-stop conversion) live in upstream session core (packages/opencode/src/session/), so the underlying hazard likely affects any driver built onSessionPrompt.loop.
Suggested fix
A GoalDriver.assessRound classifier per round from the last assistant message (productive / cancelled via MessageAbortedError / dead with APIError.isRetryable); a reconcile() retracting trailing unexecuted synthetic rounds via removeMessage + CAS. Fault-injection regression test included in the local patch; available on request.
Contributor guide
First steps
- Read the whole issue, then the project's contributing guide.
- Comment on the issue to say you are picking it up — it saves two people doing the same work.
- Fork the repository and make your change on a branch.
- Open a pull request that references the issue number.
Assessment
This issue has not been assessed yet.