Skip to content

fleet(queue): tasks can sit at status=queued with attempts=max_attempts, permanently unclaimable — health reports them as available work #2937

Open

Description

@dezren39

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:

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:

  1. Make the contradiction unrepresentable. On lease expiry, if attempts has reached max_attempts, park/fail the row with a reason class instead of returning it to queued. Terminal states should be terminal.
  2. Surface it. Add unclaimable_queued_count (or similar) to repo_queue_health, and have repo-queue.py health print 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.
  3. 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_health distinguishes queued-claimable from queued-at-cap, and repo-queue.py health shows both.
  • The claim path cannot leave a row in queued with attempts >= max_attempts (or health flags 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 → null while health shows 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

  1. added
    kind/bugSomething isn't working (prefixed form of the classic bug label)
    priority/highImportant and time-sensitive
    area/infraInfrastructure, deployment, and operations
    kind/infrastructureInfrastructure / host-portability work
    on Oct 31, 2026
  2. added
    queue/queuedHas a queued task in the Supabase agent queue
    source/creatorFiled by the new-issue-creator job
    task/triageQueue packet kind: verify, reproduce, and route this item
    on Nov 3, 2026
  3. developing-today commented on Nov 3, 2026

    @developing-today
    Contributor

    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

  4. added
    queue/claimedQueue worker lifecycle state
    work/assignedQueue worker lifecycle state
    and removed
    queue/queuedHas a queued task in the Supabase agent queue
    on Nov 4, 2026
  5. 11 remaining items

  6. dezren39 commented on Nov 4, 2026

    @dezren39
    MemberAuthor

    🤖 Agent note · handed off

  7. added
    queue/claimedQueue worker lifecycle state
    work/assignedQueue worker lifecycle state
    and removed
    status/parkedDeliberately paused with a recorded resume condition
    queue/queuedHas a queued task in the Supabase agent queue
    queue/parkedQueue task is parked (waiting on CI, time, or an event)
    on Nov 4, 2026
  8. dezren39 commented on Nov 4, 2026

    @dezren39
    MemberAuthor

    🤖 Agent note · handed off

  9. added
    queue/queuedHas a queued task in the Supabase agent queue
    and removed
    queue/claimedQueue worker lifecycle state
    work/assignedQueue worker lifecycle state
    on Nov 5, 2026
  10. dezren39 commented on Nov 5, 2026

    @dezren39
    MemberAuthor

    🤖 Agent note · handed off

    • Agent: fleet monitor
    • Session / ID: task 7373 (repo-fleet-monitor run 2026-11-05T15:39:47Z)
    • Found via: monitor reconciliation (Duty 1 claim/label divergence repair)
    • Task: Claim evaporated: task 7373 is queued and unclaimed in repo-health-code-pilot, but this issue still carried claimed labels. Labels reset to the truth (queue/queued + status/needs-triage). Checkpoint stage at evaporation: handed_off.
    • Expectation: The next lane claim picks task 7373 up from the queued state and posts a fresh pickup note.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

Labels

area/infraInfrastructure, deployment, and operationskind/bugSomething isn't working (prefixed form of the classic bug label)kind/infrastructureInfrastructure / host-portability workpriority/highImportant and time-sensitivequeue/queuedHas a queued task in the Supabase agent queuesource/creatorFiled by the new-issue-creator jobstatus/needs-triageNot yet triaged; needs a first looktask/triageQueue packet kind: verify, reproduce, and route this item

Type

No type

Projects

No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions