You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
{{ message }}
Repository navigation
[bug] Task cancel/delete/read routes still dispatch through stale default runtime rows #218
But nearby routes still use the old default-row helpers:
GET /tasks/:taskId uses requireRuntime(...) at platform/workers/api/src/routes/instances.ts:1093.
DELETE /tasks/:taskId uses getRuntime(...) at platform/workers/api/src/routes/instances.ts:1174.
POST /tasks/:taskId/cancel uses requireRuntime(...) at platform/workers/api/src/routes/instances.ts:1186.
/task-events also refreshes through getRuntime(...) at platform/workers/api/src/routes/instances.ts:1208.
On multi-machine accounts, instance_runtimes can point at a disconnected/default runner while the active task lives on a node-scoped relay. Approve was fixed for this exact class of bug, but cancel/delete/read/event refresh still diverge.
Impact
Users can see a task as active, then cancel/delete it and have the request hit the wrong relay or no-op against a stale runner. The board mirror may hide a task while the real runner keeps working, or task detail/event refresh may show stale data even though the live node is connected.
Expected Fix
Route all live task operations through the same live, pin-aware path:
Use requireLiveRuntime(...) for mutating runner task operations.
For reads/events, either use getBoundRunnerConn/live runtime when refreshing or skip refresh and serve the mirror when no live node exists.
Keep runner-less mirrored tickets working as they do today.
Acceptance Criteria
Cancel/delete reaches the same runner node that approve/create uses.
A pinned runner that is offline returns a clear offline response rather than dispatching to another/stale row.
Tests cover two registered nodes where the default row is stale and the live node owns the task.
The root cause worth recording: the reads reached for getRuntime because it was the only non-throwing option — requireLiveRuntime throws, and a read that must fall back to the mirror can't use it. So the shape of the helper pair pushed callers onto the stale default row.
Added getLiveRuntime, the missing non-throwing half (mirroring getRuntime/requireRuntime). Now:
POST /tasks/:id/cancel → requireLiveRuntime: reaches the live node or returns a clear offline response, instead of dispatching at a dead relay and reporting a cancel that never happened.
GET /tasks/:id → requireLiveRuntime inside the existing try, so no live runner falls through to the mirror as before.
DELETE and /task-events → getLiveRuntime, mirror fallback unchanged.
Runner-less mirrored tickets behave exactly as before.
Activity
fix: tool dedup missed reordered args; upload identity trusted the cl…
serge-ivo commentedon Aug 6, 2026
Fixed in de2505f.
The root cause worth recording: the reads reached for
getRuntimebecause it was the only non-throwing option —requireLiveRuntimethrows, and a read that must fall back to the mirror can't use it. So the shape of the helper pair pushed callers onto the stale default row.Added
getLiveRuntime, the missing non-throwing half (mirroringgetRuntime/requireRuntime). Now:POST /tasks/:id/cancel→requireLiveRuntime: reaches the live node or returns a clear offline response, instead of dispatching at a dead relay and reporting a cancel that never happened.GET /tasks/:id→requireLiveRuntimeinside the existing try, so no live runner falls through to the mirror as before.DELETEand/task-events→getLiveRuntime, mirror fallback unchanged.Runner-less mirrored tickets behave exactly as before.
fix(runtime): the connected dot could be flatly wrong, and never said…
fix(api): the swallows that make a record say something that did not …