Skip to content

fix(server): a steered turn start no longer wedges the follow-up queue forever - #15

Merged
leonardoxr merged 1 commit into
main-xavierfrom
fix/follow-up-queue-ghost-turn-start
Aug 19, 2026
Merged

fix(server): a steered turn start no longer wedges the follow-up queue forever#15
leonardoxr merged 1 commit into
main-xavierfrom
fix/follow-up-queue-ghost-turn-start

Conversation

@leonardoxr

Copy link
Copy Markdown
Owner

Problem

A queued follow-up was never sent. From the event log of the thread it happened in:

14:09:35  turn-start-requested   ← a mid-turn send (a steer)
          …no turn.started ever follows, and no session change either
14:11:28  follow-up-queued       "also, queue keybinds are not working…"
14:42:46  session-set ready      ← the gate opens; the queue evaluates… and refuses
14:44:53  follow-up-removed reason=user   ← deleted by hand, then retyped

A provider that steers folds the request into the turn it is already running, so no turn.started is emitted and the session snapshot does not change. The pending turn-start row (turn_id IS NULL, state='pending') is therefore never adopted and never cleared, and FollowUpQueueReactor treats a pending turn start as work in flight. From that moment the thread's queue never dispatches again — for the life of the thread. Not omp-specific: Claude and OpenCode steering leave the same ghost.

Fix

The gate ignores a pending turn start that some turn completed after: that request has already had its answer, and no turn will ever be named for it. A pending start with no turn completed since still holds the queue, so a start that is merely racing adoption is unaffected. The reactor stays read-only — the projection keeps owning its rows.

Verification

  • New test dispatches when a turn completed after the waiting turn startfails on main-xavier, passes here.
  • Companion test holds when the only completed turn predates the waiting turn start pins the race case that the guard exists for.
  • FollowUpQueueReactor + ProjectionPipeline.followUpQueue: 17 tests green. tsgo clean; lint/format clean.

Built with Claude Opus 5 on Oh My Pi.

…e forever

A provider that steers folds a mid-turn send into the turn it is already
running: no turn.started, and no session change, so the pending turn-start row
is never adopted and never cleared. The queue gate treats a pending turn start
as work in flight, so from that moment on the thread's queue never dispatched
again — a follow-up queued at 14:11 was still sitting there when the thread had
been idle for two minutes, and the user deleted it and retyped the message.

The gate now ignores a pending turn start that some turn completed after: that
request already had its answer, and no turn will ever be named for it. A
pending start with no turn completed since still holds the queue, so a start
racing adoption is unaffected.

Built with Claude Opus 5 on Oh My Pi.
@github-actions github-actions Bot added size:S vouch:trusted PR author is trusted by repo permissions or the VOUCHED list. labels Aug 19, 2026
@leonardoxr
leonardoxr merged commit 5b932a3 into main-xavier Aug 19, 2026
5 of 9 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

size:S vouch:trusted PR author is trusted by repo permissions or the VOUCHED list.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant