Repository navigation
Description
Problem
repo-health-opencode-pilot has 6 tasks with status = 'queued' that no worker can ever claim. All six sit at attempts = max_attempts (2/2). agent.claim_repo_task selects with attempts < max_attempts (design §claim, queue-worker-pilot-design-2026-10-25.md), so these rows are permanently invisible to every claim.
repo-queue.py health reports them as work available (queued_count = 6), so the worker gate in the lane instruction (§2) passes and a worker launches, only to get {"task": null} from claim with no diagnosis. Observed 2026-10-31 03:45–03:52Z: gate saw 6 queued, claim --worker repo-worker-opencode returned no task, exit 0.
The state is a contradiction: queued means "waiting to be claimed" and the row is not claimable. Nothing surfaces it — no failed/blocked/needs_review status, and health has no unclaimable column.
Evidence (2026-10-31 03:49Z)
All six rows, queue repo-health-opencode-pilot, status = queued:
| task | attempts | claimed_at | last stage | PR |
|---|---|---|---|---|
| 3636 | 2/2 | 2026-10-29T23:25:35 | verified |
#926 |
| 3730 | 2/2 | 2026-10-30T02:21:23 | awaiting_ci |
#940 |
| 3772 | 2/2 | 2026-10-30T04:17:22 | verified |
#944 |
| 3847 | 2/2 | 2026-10-30T09:12:22 | targeted_tests_passed |
#958 |
| 3913 | 2/2 | 2026-10-30T19:45:51 | pr_opened |
#1011 |
| 3943 | 2/2 | 2026-10-30T20:34:00 | pr_opened |
#1013 |
These are not abandoned tasks. Every one has a checkpointed stage and an open PR with real work behind it:
- id(web): bold links flip spelling on every save — strong+link marks have no round-trip fixpoint #944 —
MERGEABLE, all 8 non-skipped checks green. Ready to merge. - cold-store-reaper: live Google access token is cached in state.json, which the README calls '(no secrets)' and which is written without 0600 permissions #940 — all checks green but
CONFLICTING(branch needs a rebase onto currentmain). - amd: declare the muse user (sops password hash) #926 —
MERGEABLE, 6 green,basic unit(linux + windows) red on a pre-existingservice-lifecyclepty-handoff flake already documented in the task's ownpark_reason. - mcpx: ResolvedScope plumbing + spawn cwd = resolved scope root #958, test(id-web): softbreak marked-span round-trip regression tests (#981) #1011, fix(id-web): preserve footnotes in markdown codec (#945) #1013 —
MERGEABLE/CLEAN, but nopull_requestCI run was ever triggered on their head SHAs (onlyCodeRabbitreported; the only Actions runs on those branches arepush-triggered workflow failures unrelated to the PR —main-broken,Daily Upstream Sync,docs-update,stats,review,models-snapshot).
So work that is essentially complete (one PR is merge-ready, two more need only CI pickup) is stranded behind a status flag.
Other queues are affected too, in smaller numbers — fleet-wide at the same moment: repo-health-code-pilot 3 rows, repo-health-openchamber-pilot 1 row. So this is a shared the-queue-tooling issue, not an opencode-lane-only one.
Why it happens
park does not consume an attempt (migration 0012), but a worker that ends its run without a terminal verb leaves the row claimed until the lease expires. The expiry path returns it to queued and increments attempts. At the cap, queued and attempts < max_attempts disagree and the row is stuck. Task #1130 documents the evaporation side of this (run-budget cutoffs); this issue is the state it produces, which nothing currently detects or repairs.
The lane instruction says raise the cap by hand when a task goes dead-in-queue (that is what happened to tasks 1149 and 1157 per #1130). That is operator memory, not a mechanism, and it depends on someone noticing — which health actively prevents by counting these rows as queued.
Proposal
Pick per-row — the right answer differs and I do not want to guess the policy:
- Make the contradiction unrepresentable. On lease expiry, if
attemptshas reachedmax_attempts, park/fail the row with a reason class instead of returning it toqueued. Terminal states should be terminal. - Surface it. Add
unclaimable_queued_count(or similar) torepo_queue_health, and haverepo-queue.py healthprint it — the gate should see "6 queued, 0 claimable" so it can exit quietly with a reason rather than launching a worker that cannot work. - Repair the existing rows. The six here map to open PRs, so most want a cap raise plus a resume, not a cancel.
(2) is the cheap, immediately useful one and would have saved this launch.
Acceptance criteria
-
repo_queue_healthdistinguishes queued-claimable from queued-at-cap, andrepo-queue.py healthshows both. - The claim path cannot leave a row in
queuedwithattempts >= max_attempts(orhealthflags it — whichever the design pick above chooses). - The six opencode rows (3636, 3730, 3772, 3847, 3913, 3943) reach a real terminal state; the three openchamber/code rows are triaged in the same pass.
- A worker that gets
claim → nullwhilehealthshows queued work gets a diagnostic naming why (attempt cap / worker filter / lease), not a silent empty result.
Found by the OpenChamber scheduled lane (repo-worker-opencode) on its 2026-10-31 launch. Related: #1130 (evaporation cause), #1233 (queue reliability epic), #1289 (repo-queue list/inspect), #2323 (the other way a queued row becomes unreachable).
Activity
developing-today commentedon Nov 3, 2026
agent-note:v1
state: reviewed (coverage loop-back)
Coverage pass 2026-11-03, loop-back review: this issue was re-reviewed (drift / overlap / already-handled / stale / blockers / ordering) so every open issue in the four repos is reviewed and in the system. Verdict: still live; in the system as task 7373 (triage, queued, priority 50) in repo-health-code-pilot. Labels audited and synced. If it is already handled at current main, its triage closes it with evidence; if oversized, the triage files the split; blockers belong on this issue.
Found via: coverage loop-back 2026-11-03
11 remaining items
dezren39 commentedon Nov 4, 2026
🤖 Agent note · handed off
dezren39 commentedon Nov 4, 2026
🤖 Agent note · handed off
dezren39 commentedon Nov 5, 2026
🤖 Agent note · handed off