mirror of
https://github.com/rowboatlabs/rowboat.git
synced 2026-07-12 21:02:17 +02:00
fix(x): make stopTurn reliable under concurrent advances on one turn
The sessions layer tracked live advances in a map keyed by bare turnId with overwrite-on-set and unconditional delete-on-settle. A turn can legally have several live advances at once — a running invocation plus external-input invocations queued on the turn lock (e.g. a permission response while an async result is pending). The overwrite made stopTurn abort the wrong controller and await an outcome that couldn't settle; the unconditional delete untracked a sibling advance, so a later stopTurn missed the abort path, fell back to a cancel input, and could reject with TurnInputError if the turn had completed meanwhile — a user-visible stop failure. Durable state was never affected. Track a set of advances per turn: each advance removes only its own entry on settle, and stopTurn aborts every live controller and awaits all outcomes. A cancel input that loses the race with a concurrent settle now counts as a successful stop (the turn is already terminal) instead of rejecting. Adds four tests: concurrent invocations both aborted, an earlier settle not untracking a later advance, the settle-race cancel treated as success, and non-terminal rejections still surfacing. Updates session-design.md §9.3 and §13.5 accordingly. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
parent
284dc77f5e
commit
e22d3b4796
3 changed files with 172 additions and 23 deletions
|
|
@ -338,9 +338,14 @@ runtime's job; the session layer passes its errors through.
|
|||
|
||||
### 9.3 stopTurn and resumeTurn
|
||||
|
||||
- `stopTurn` cancels via the turn runtime: aborting the active invocation's
|
||||
signal if one is running, else advancing a suspended turn with a `cancel`
|
||||
input.
|
||||
- `stopTurn` cancels via the turn runtime: aborting the signal of every
|
||||
live advance the layer has started for the turn, else advancing the turn
|
||||
with a `cancel` input. A turn can legally have several live advances at
|
||||
once — one running invocation plus external-input invocations queued on
|
||||
the turn lock — so the layer tracks them per turn and stop aborts them
|
||||
all; the queued ones observe their aborted signal when the lock frees. A
|
||||
cancel input that loses the race with a concurrent settle (the turn is
|
||||
already terminal by the time it applies) counts as a successful stop.
|
||||
- `resumeTurn` re-enters the latest turn with no input — the turn spec's
|
||||
recovery entry point — for turns left `idle` by a crash. There is no
|
||||
automatic resume sweep at startup: recovery re-issues interrupted model
|
||||
|
|
@ -499,6 +504,11 @@ All tests use the in-memory/mocked turn runtime and repo fakes.
|
|||
correct turn with the correct input type.
|
||||
- Turn-runtime rejections (unknown call, terminal turn) pass through.
|
||||
- `sendMessage` never routes to ask-human.
|
||||
- `stopTurn` aborts every live advance when a turn has concurrent
|
||||
invocations, and an earlier advance settling does not untrack a later
|
||||
one.
|
||||
- A `stopTurn` cancel input that lost the race with a concurrent settle
|
||||
resolves as a successful stop; a non-terminal rejection still surfaces.
|
||||
|
||||
### 13.6 Index
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue