runner.rb:48, run.rb:137, supervisor.rb:76. Run.adopt decides whether a run is being resumed by reading row[:status] == 'blocked', but resumed flips the row to running before the thread ever calls adopt. So every poller-driven resume takes reload, not restore.
Consequence: a stage out of strikes re-blocks with the identical message on every answer, forever. Only rake mill:answer still reaches restore.
Checked 2026-08-21: the start/reap race fix does not free this, and it cannot. Keeping the status flip ahead of the thread is deliberate — the poller reads the status straight back after start returns, and two tests pin that. The fix probably belongs in Run.adopt: be told it is a resume rather than inferring it from a row another thread is allowed to change.
Blocks a merge. Context: docs/notes/2026-08-20-plan-3a-review-triage.md, HIGH.
runner.rb:48,run.rb:137,supervisor.rb:76.Run.adoptdecides whether a run is being resumed by readingrow[:status] == 'blocked', butresumedflips the row torunningbefore the thread ever callsadopt. So every poller-driven resume takesreload, notrestore.Consequence: a stage out of strikes re-blocks with the identical message on every answer, forever. Only
rake mill:answerstill reachesrestore.Checked 2026-08-21: the
start/reaprace fix does not free this, and it cannot. Keeping the status flip ahead of the thread is deliberate — the poller reads the status straight back afterstartreturns, and two tests pin that. The fix probably belongs inRun.adopt: be told it is a resume rather than inferring it from a row another thread is allowed to change.Blocks a merge. Context:
docs/notes/2026-08-20-plan-3a-review-triage.md, HIGH.