Take stuck work back out of Symphony's queue - #1
Merged
Conversation
Unscheduling refused any ticket Symphony held a session for, on the grounds that removing the label would not stop the work. That is true while an agent is running, but not for the two states where nothing is progressing: blocked, waiting for an operator, and retrying, backing off after failing to start. Those are exactly the tickets that need taking back, fixed, and putting in again — and they were the ones the toggle refused. Symphony re-reads the required labels before it acts on either. A retry that fires re-tests routability and drops the claim when the label is gone; blocked issues are reconciled the same way, releasing anything no longer routed to the worker. So removing the label really does stop the work rather than merely hiding it from the dashboard, which was the objection. Only a running agent is refused now, since no label change interrupts a turn already in progress — that needs stopping the session in Symphony, which has no API for it here. symphonyHasIt becomes symphonyIsWorkingOnIt to say which state it means. The long-form help still described the old rule, so it was corrected alongside the key table. The README gains the grey scheduled marker it never listed, and a note on what the toggle leaves alone: unrelated labels, and the status. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
A change that only exists in the source tree is not usable: devdash is driven as a real tool while it is being worked on, so the binary on PATH is what actually gets exercised. Leaving the install as a manual step meant testing yesterday's build without noticing. A Stop hook runs the build and the tests, and installs to ~/.local/bin only if both pass, so a broken binary never lands on PATH — a failure reports the compiler or test output and leaves the last good build in place. Roughly a second and a half per turn once Go's cache is warm. It installs from the working tree rather than the go install @latest the README documents, which resolves from the remote and would quietly deploy without the changes being tested. Note that the deploy path is specific to one machine. If this becomes awkward for anyone else, .claude/settings.local.json is the untracked place for it. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Srefused to unschedule any ticket Symphony held a session for. That is right while an agent is running, but wrong for the two states where nothing is progressing — blocked (waiting for an operator) and retrying (backing off after failing to start). Those are precisely the tickets you need to pull back, fix, and put in again, and they were the ones being refused.Why removing the label is enough
The previous reasoning was that unscheduling "would not stop the work, only make the dashboard disagree with what is happening". Checked against Symphony's orchestrator rather than assumed, that does not hold for either stuck state:
retry_candidate_issue?→Issue.routable?(issue, required_labels). With the label gone that is false, so it falls through torelease_issue_claim("Issue left active states, removing claim").reconcile_blocked_issue_statehas an explicit!issue_routable?→release_issue_claimbranch ("Blocked issue no longer routed to this worker").Both re-read the required labels before acting, so the claim really is dropped.
running is still refused: no label change interrupts a turn already in progress. That needs stopping the session in Symphony, whose API is read-only apart from
POST /api/v1/refresh, so devdash cannot do it for you.symphonyHasItbecomessymphonyIsWorkingOnItto name the state it actually means.Also in here
?help still described the old rule and contradicted the new behaviour — corrected alongside the key table in the help, the in-app view, and the README.scheduledmarker it never listed.Stophook (.claude/settings.json) builds, tests, and installs to~/.local/binonly when both pass, so the binary onPATHmatches the source. Its deploy path is machine-specific;.claude/settings.local.jsonis the untracked home for it if that becomes awkward.Verification
gofmt -l .clean,go vet ./...clean,go test -race -cover ./...passes (53.1% of statements).TestCannotUnscheduleWhileAnAgentIsRunningcovers the refusal;TestCanUnscheduleStuckWorkcoversblocked,retrying,scheduledand no-session, asserting each removes the label and leaves the status untouched./api/v1/statereally does return ablockedarray — worth checking, since Symphony'sSPEC.mddoes not document one and the Go implementation does not emit it, so on that backendblockedwould never appear.Not covered: the live dry-run harness (
DEVDASH_DRYRUN_DIR=... go test -run TestDryRunSchedulePlans) needs JIRA credentials that were not available, so the plan for every real ticket has not been eyeballed.🤖 Generated with Claude Code