RunOutcome now names the turn and its open question on every Ok path
(Ran/Replayed), and PlayError::EmptyAnswer/StaleAnswer carry the still-open
question a caller can retry against, so a consumer never has to read the
store to learn a QuestionId. PlayTable::current_turn_view is the small new
door a later, separate reader uses instead, since world.play's own route
spawns run in a task and answers before that call resolves (PA.f134).
Dispatch now resubmits its recorded subject list on resume instead of
re-parsing the tool call's arguments against whatever the round's own
snapshot says now, matching every other door's "recorded body decides" rule
(PA.f136). run_lock is acquired with try_lock, not a blocking wait, so a
request racing an in-flight turn is refused at once with TurnStillRunning
rather than queued behind up to ROUND_BUDGET rounds of inference (PA.f142).
turn.refusal is cleared when a player act commits, so it names only the most
recent one (PA.f144). service/play-turn-v1.cc joins the admitted state
layout's own pre-flight symlink/hardlink check (PA.f140).
Soul's own findings get their production-path tests: round_snapshot's two
callers pinned behaviorally through infer_round and execute_round separately
(PA.f137), dispatch_owner's earliest-call-wins rule pinned against a
duplicate dispatch (PA.f139), and three-subject concurrent dispatch pinned
against JSON order in both the summary and persona_turns (PA.f143). The
world.play routing test now polls current_turn_view to prove the spawned
task actually calls table.run, not just returns the same accepted JSON
(PA.f138).
PA.f147 (missing idempotency key) and PA.f141/f145/f146 (doc claims) were
investigated and are covered in Hands' own report rather than landed as
code: the described idempotency-key hole is already closed by
execute_world's own unconditional command_id parse before world.play's
branch is ever reached (mutation-verified), and the doc fixes are the
smaller diff already included in eve.rs/play.rs/runtime.rs here.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>