Context
A PR-fix item that exhausts its attempt budget is marked BLOCKED, and from there has no route back into the loop.
Two live examples right now:
misospace/pinchflat #33 lane=NORMAL status=BLOCKED "Failing check: Lint and Test (failure)"
misospace/pr-reviewer-action #502 lane=NORMAL status=BLOCKED "Failing check: validate (failure)"
Nothing can move them. The bridge drains only QUEUED items (drain_pr_fixes -> list_pr_fix_queued), so BLOCKED is invisible to it. mark_pr_fix accepts fixed, blocked, stale and ignored — there is no value that returns an item to QUEUED. Once the cap is hit, the only way to get the PR moving again is to push a commit by hand and hope the resulting check failure enqueues a fresh item.
The lane built for this is never used. The bridge knows about it:
# bridge/prfix.py:9-11# Lane values dispatch assigns to a PR-fix item. NEEDS_HUMAN is never actionedACTIONABLE_LANES= ("NORMAL", "ESCALATED")GET /api/pr-fix-queue/queued?lane=NEEDS_HUMAN is a valid request and returns 200. But the give-up path sets status=BLOCKED while leaving lane=NORMAL, so blocked items never land in the lane that was built to hold them. NEEDS_HUMAN sits empty while two items are blocked in NORMAL.
The visibility half is already solved and does not need work: src/app/automation/pr-fix-queue/page.tsx:61 filters status === "BLOCKED" into its own section, and line 125 already badges lane === "NEEDS_HUMAN" in red. So these two items are findable today. What is missing is any way to act on them from there.
The ask (one imperative sentence)
Route give-up items into the NEEDS_HUMAN lane and give the operator a way to return a blocked PR-fix item to QUEUED.
Expected files
src/lib/pr-fix-queue.ts
src/app/api/pr-fix-queue/mark/route.ts
src/mcp/server.ts
src/app/automation/pr-fix-queue/page.tsx
Acceptance criteria
- When a PR-fix item is marked
BLOCKED after exhausting its attempts, its lane becomes NEEDS_HUMAN rather than staying NORMAL. The bridge already refuses to action that lane, so this changes which bucket the item sits in without changing what the loop picks up. The existing red NEEDS_HUMAN badge on the queue page then means something. - A blocked item can be returned to
QUEUED with its attempt counter reset, so the loop works it again. Whether that is a new mark_pr_fix status value (queued / requeued), a separate tool, or a UI-only action is an implementation choice; the requirement is that it exists and does not need a hand-pushed commit to trigger. - The requeue action is reachable from
src/app/automation/pr-fix-queue/page.tsx — a button on each BLOCKED row. The page already lists them; this is the missing verb. - Requeueing writes an audit row like the other outcome transitions, so the history shows a human put it back rather than the loop deciding on its own.
- Requeueing an item whose PR is already merged or closed is refused, consistent with
classify_pr_lifecycle treating those as nothing-left-to-fix.
Context
A PR-fix item that exhausts its attempt budget is marked
BLOCKED, and from there has no route back into the loop.Two live examples right now:
Nothing can move them. The bridge drains only
QUEUEDitems (drain_pr_fixes->list_pr_fix_queued), soBLOCKEDis invisible to it.mark_pr_fixacceptsfixed,blocked,staleandignored— there is no value that returns an item toQUEUED. Once the cap is hit, the only way to get the PR moving again is to push a commit by hand and hope the resulting check failure enqueues a fresh item.The lane built for this is never used. The bridge knows about it:
GET /api/pr-fix-queue/queued?lane=NEEDS_HUMANis a valid request and returns 200. But the give-up path setsstatus=BLOCKEDwhile leavinglane=NORMAL, so blocked items never land in the lane that was built to hold them.NEEDS_HUMANsits empty while two items are blocked inNORMAL.The visibility half is already solved and does not need work:
src/app/automation/pr-fix-queue/page.tsx:61filtersstatus === "BLOCKED"into its own section, and line 125 already badgeslane === "NEEDS_HUMAN"in red. So these two items are findable today. What is missing is any way to act on them from there.The ask (one imperative sentence)
Route give-up items into the
NEEDS_HUMANlane and give the operator a way to return a blocked PR-fix item toQUEUED.Expected files
Acceptance criteria
BLOCKEDafter exhausting its attempts, its lane becomesNEEDS_HUMANrather than stayingNORMAL. The bridge already refuses to action that lane, so this changes which bucket the item sits in without changing what the loop picks up. The existing redNEEDS_HUMANbadge on the queue page then means something.QUEUEDwith its attempt counter reset, so the loop works it again. Whether that is a newmark_pr_fixstatus value (queued/requeued), a separate tool, or a UI-only action is an implementation choice; the requirement is that it exists and does not need a hand-pushed commit to trigger.src/app/automation/pr-fix-queue/page.tsx— a button on each BLOCKED row. The page already lists them; this is the missing verb.classify_pr_lifecycletreating those as nothing-left-to-fix.