π€ automated
Found while dogfooding the rotation end to end (#1204, evidence in #1640).
What happened. Run now on Add quick-win work to AI Queue started an agent that read nothing and aborted:
β Branch tf-triage-quick already exists β aborting
$ git branch -a --list '*tf-triage-quick*'
tf-triage-quick
remotes/origin/tf-triage-quick
No tickets were read, no branch was created, and TODO_AGENTS.md was not modified.
Cost: $0.16 for a turn that did no work. It repeats on every click until someone deletes the branch by hand β which is what unblocked the dogfood.
The cause. Both triage jobs declare a pinnedBranch (auto-pm.ts:355,362), and a pinned job aborts itself when that branch already exists (#1293). The sweep handles this: it releases a stale pinned branch before each start β
// auto-pm.ts:1006
if (item.pinnedBranch) await deps.releasePinned?.(project, item.pinnedBranch).catch(() => undefined)
releasePinned is called only from inside that sweep loop. The card's Run now for an ordinary rotation job goes down a different path β a plain start() in RoutineWork.tsx β which never calls it. So the daemon can recover from its own leftover branch and the button cannot.
The branch that blocked us had zero commits unique to main and no pull request had ever existed. Nothing was protecting it; nothing was there to release it either.
Same family as #1640. That one was: the sweep fans out, Run now did not. This one is: the sweep releases a stale pin, Run now does not. The general shape is that a card-fired routine reaches less of the sweep's preparation than the sweep does, and the difference is invisible until a click dies.
Fix. Have the plain-start path release a pinned branch first, the same way the sweep does β either by routing a pinned job's Run now through the narrowed sweep (as #1640 does for the fan-out jobs), or by calling the same seam before start(). The first keeps one code path and is the direction #1640 already points.
π€ automated
Found while dogfooding the rotation end to end (#1204, evidence in #1640).
What happened.
Run nowonAdd quick-win work to AI Queuestarted an agent that read nothing and aborted:Cost: $0.16 for a turn that did no work. It repeats on every click until someone deletes the branch by hand β which is what unblocked the dogfood.
The cause. Both triage jobs declare a
pinnedBranch(auto-pm.ts:355,362), and a pinned job aborts itself when that branch already exists (#1293). The sweep handles this: it releases a stale pinned branch before each start βreleasePinnedis called only from inside that sweep loop. The card'sRun nowfor an ordinary rotation job goes down a different path β a plainstart()inRoutineWork.tsxβ which never calls it. So the daemon can recover from its own leftover branch and the button cannot.The branch that blocked us had zero commits unique to
mainand no pull request had ever existed. Nothing was protecting it; nothing was there to release it either.Same family as #1640. That one was: the sweep fans out,
Run nowdid not. This one is: the sweep releases a stale pin,Run nowdoes not. The general shape is that a card-fired routine reaches less of the sweep's preparation than the sweep does, and the difference is invisible until a click dies.Fix. Have the plain-start path release a pinned branch first, the same way the sweep does β either by routing a pinned job's
Run nowthrough the narrowed sweep (as #1640 does for the fan-out jobs), or by calling the same seam beforestart(). The first keeps one code path and is the direction #1640 already points.