/cancel endpoint: accept an agent param instead of cancelling the first busy worker #87
Labels
No labels
area:agents
area:dashboard
area:database
area:design
area:design-review
area:flows
area:infra
area:meta
area:security
area:sessions
area:webhook
area:workdir
security
type:bug
type:chore
type:meta
type:user-story
No milestone
No project
No assignees
1 participant
Notifications
Due date
No due date set.
Dependencies
No dependencies set.
Reference
charles/claude-hooks#87
Loading…
Add table
Add a link
Reference in a new issue
No description provided.
Delete branch "%!s()"
Deleting a branch is permanent. Although the deleted branch may continue to exist for a short time before it actually gets removed, it CANNOT be undone in most cases. Continue?
User story
As the operator, I want
/cancelto take an explicitagentname so that cancelling one agent's dupe / stuck task doesn't
collateral-damage another agent's critical work.
What happened (concrete)
During a 3-ticket parallel dispatch (#81 / #82 / #83) today, two
workers were simultaneously busy:
bossrunningf98fe733— theaddress-reviewtask for PR #85(ticket #81) after reviewer's REQUEST_CHANGES.
devrunning8cdcd807— a leftover dupe from an earlierassignee-pivot trick; harmless but burning cycles on an
already-solved issue.
Intent: cancel dev's dupe. Actual behaviour:
/cancelwalksworkers.values()in map order, aborts the first worker withcurrentAbort + currentTask, thenbreaks — so it killedboss's critical address-review. Dev kept running its dupe
untouched. PR #85 got stuck in "changes requested" with no
one addressing it; had to manually re-request review to
resurrect the flow.
See
src/main.ts:332(/cancelhandler).Why this matters
Today the default 5-agent pool runs independent flows in
parallel (designer + dev + reviewer + boss merge step, plus
design-reviewer). The multi-agent pool config in #47 / #49
makes this the norm, not the exception. A non-targetable
/cancelis a foot-gun: operators reach for it expecting tostop one specific task and get a random cancellation instead.
Acceptance criteria
Endpoint shape
POST /cancelaccepts a JSON body:-
{}— keep today's "cancel the one running task" behaviouronly if exactly one worker is busy; otherwise return
409 { "error": "multiple workers busy; specify agent or task_id" }.-
{ "agent": "<name>" }— cancel that worker's currenttask.
404if the agent name isn't known.-
{ "task_id": "<uuid>" }— cancel the specific runningtask wherever it lives.
404if the id isn't currentlyrunning. Preferred over
agentwhen both are given.id,agent, andissue_numberso the operator can confirm the right targetwas hit.
Dashboard
src/dashboard.htmlper-row cancel button already exists(line 245). Update
cancelTask(event)(line 351) to POST{"task_id": "<taskId>"}instead of an empty body — makesthe button behave correctly under concurrent load.
that POSTs
{"agent": "<name>"}.Tests
main.test.tsPOST /cancelsuite:- current: a single test that doesn't distinguish the "no
body" / "stale body" cases. Split into body-shape cases.
- add:
cancels only the named agent's task— two workersbusy, body targets one, the other keeps running.
- add:
rejects empty body when >1 worker busy— 409.- add:
returns 404 on unknown agent / unknown task_id.Out of scope
currentTask). The queue manipulation is a separate ticketwhen someone needs it.
curl -X POST -d '{"agent":"boss"}'isfine for the operator for now.
References
src/main.ts:332— the handler to split.src/dashboard.html:245,351— the button/fetch pair to update.makes this class of bug more likely.
Dependencies
per agent type concurrently — a pool makes the foot-gun
strictly worse.
main.