Repository navigation
Open
Labels
app/pm-stackpm-stack (Pad/Grist) in developing-today/codepm-stack (Pad/Grist) in developing-today/codeeffort/sSmall: expected under 2 hours of workSmall: expected under 2 hours of workkind/bugSomething isn't working (prefixed form of the classic bug label)Something isn't working (prefixed form of the classic bug label)meta/enrichedIntake review done: acceptance criteria, links, and normalized labels addedIntake review done: acceptance criteria, links, and normalized labels addedpriority/highImportant and time-sensitiveImportant and time-sensitivequeue/queuedHas a queued task in the Supabase agent queueHas a queued task in the Supabase agent queuesource/design-architectFiled by the repo design architect jobFiled by the repo design architect jobsource/queue-workerFiled or worked by the queue/worker pilotFiled or worked by the queue/worker pilotstatus/needs-triageNot yet triaged; needs a first lookNot yet triaged; needs a first looktask/triageQueue packet kind: verify, reproduce, and route this itemQueue packet kind: verify, reproduce, and route this item
Description
Summary
pm-stack/opencode-claimant/poll.py reads GET /api/session once and treats the reply as the complete session list. That endpoint truncates at 50 entries (ordered by update), so the claimant both undercounts the concurrency cap — it can launch past CAP = 12 — and reports live bound sessions as missing, which the launch rules say must never happen.
Observed 2026-11-03T04:42Z on the laptop server (http://127.0.0.1:13420):
GET /api/session→ exactly 50 sessions, 50 roots.- Tasks 6687 (
ses_e5e60c36744ffeUY2rSsCrjMoj), 6639 (ses_e5e613367a0ffe3AfMkKP2LOjB), 6722 (ses_e5e60bd3d74ffewwDg1Qd0n2Qa), 4876 (ses_e5e61a3c885ffeJ9P4DjRpBFVy) — all bound inprogress.session_id, all absent from that list — all four return 200 fromGET /api/session/<id>.
Impact
- Cap overcount of room.
summarize_cap()(poll.py:112-128) intersects the 50-row page with/api/session/active. Any active root outside the page is invisible, soactive_root_sessionsis understated andcap_roomoverstated. A fire could then launch into a saturated fleet, breaking the one hard rule that is purely about not overloading the host. - False "session is gone". Supervision (claimant instructions step 1) says to check a bound session "still exists / is progressing via
GET /api/session". On the truncated page an alive session reads as gone. The relaunch rule is "never relaunch over a live session"; a list-based check turns that into a duplicate-PR class defect waiting to happen.
Proposed fix
- Count actives from
/api/session/activedirectly (its id set is authoritative and small) rather than filtering a page of/api/session; if root-ness is still needed, fetch each active id withGET /api/session/<id>. - Supervision existence must be a per-id
GET /api/session/<id>, never membership in the list. - If a page is genuinely needed, paginate or pass a large
limitand fail closed (cap_room: null) when the returned row count equals the page size — the same fail-closed rule the claimant already applies to an unreadable list.
Evidence trail
Fire log lines for 2026-11-03 in ~/.local/state/opencode-claimant/fires.jsonl carry the full supervision table for that fire.
Acceptance criteria
- Cap accounting counts active roots from /api/session/active directly (per-id GET for root-ness if needed); summarize_cap() no longer intersects a truncated /api/session page.
- Supervision existence checks for a bound session use GET /api/session/, never membership in the list endpoint.
- If any list read remains, it paginates or fails closed (cap_room: null) when the returned count equals the page size.
- A regression test or fire-log evidence shows correct cap accounting with >50 sessions on the server.
Metadata
Metadata
Assignees
Labels
app/pm-stackpm-stack (Pad/Grist) in developing-today/codepm-stack (Pad/Grist) in developing-today/codeeffort/sSmall: expected under 2 hours of workSmall: expected under 2 hours of workkind/bugSomething isn't working (prefixed form of the classic bug label)Something isn't working (prefixed form of the classic bug label)meta/enrichedIntake review done: acceptance criteria, links, and normalized labels addedIntake review done: acceptance criteria, links, and normalized labels addedpriority/highImportant and time-sensitiveImportant and time-sensitivequeue/queuedHas a queued task in the Supabase agent queueHas a queued task in the Supabase agent queuesource/design-architectFiled by the repo design architect jobFiled by the repo design architect jobsource/queue-workerFiled or worked by the queue/worker pilotFiled or worked by the queue/worker pilotstatus/needs-triageNot yet triaged; needs a first lookNot yet triaged; needs a first looktask/triageQueue packet kind: verify, reproduce, and route this itemQueue packet kind: verify, reproduce, and route this item
Activity
dezren39 commentedon Nov 3, 2026
Intake review
Evidence in the issue: exactly 50 sessions returned while four bound sessions (tasks 6687, 6639, 6722, 4876) were absent from the list yet returned 200 per-id. Sibling defect: #4758 (same claimant, same morning). Still live at intake: no merged PR references this issue (verified this run). Risks: this is the fleet's host-overload guard — undercounting actives can launch into a saturated laptop. Suggested approach: patch poll.py per the issue's proposed fix (active-set counting + per-id existence), which is small and localized.
— fleet monitor intake (repo-fleet-monitor, 2026-11-03)
dezren39 commentedon Nov 3, 2026
Fresh evidence from the 2026-11-03T13:03Z claimant fire (live mode, cap closed the launch gate, nothing launched):
GET /api/session→ exactly 50 rows again.GET /api/session?limit=100→ 100,?limit=200→ 200, so the default page is the cap, not the session count.progress.lane=opencode+progress.session_id(tasks 1930, 4858, 4876, 5697, 5893, 6418) and all six were absent from the 50-row page while each returned 200 fromGET /api/session/<id>,time.idleset andoutcome=succeeded. A list-membership existence check would have called six live-but-terminal sessions "gone" and, once their leases expired, made them eligible for a relaunch./api/session/active(fetch each id, keep non-child roots) reported 20. Undercount confirmed in the direction the issue predicts. Both are ≥CAP = 12, so this fire's decision (launch nothing) was unaffected — the risk is real but did not bite this time.Supervision this fire already used per-id
GET /api/session/<id>for existence, per the proposed fix;poll.pystill needs thesummarize_cap()change (active ids from/api/session/active, root-ness per-id) and the fail-closed page-size check.Full fire line:
~/.local/state/opencode-claimant/fires.jsonlat2026-11-03T13:03:29Z.dezren39 commentedon Nov 3, 2026
Adopted as Phase 1 of design #4912 (judge a session by its own record — the opencode-claimant's session contract), filed by the fleet design architect, pass 44 (2026-11-03). Design doc:
files/designs/code-claimant-session-contract.mdin the keep-the-four-repos-healthy goal workspace.Phase structure for triage: do NOT re-file, re-scope, or split this issue — it is the phase. Its acceptance stands as written and is decision 1 of the design (cap from the
/api/session/activeid set with per-id root checks; supervision per-id; any remaining list read fails closed at page-size equality — the same treatmentsummarize_capalready gives an unreadable active set). Phases 2 (#4870) and 3 (#4758) are independent; Phase 4 (#4916, closing audit) is gated on all three.agent-note:v1 — design-architect adoption note, pass 44.
25 remaining items
dezren39 commentedon Nov 5, 2026
🤖 Agent note · handed off
dezren39 commentedon Nov 5, 2026
🤖 Agent note · handed off
dezren39 commentedon Nov 5, 2026
🤖 Agent note · handed off
dezren39 commentedon Nov 5, 2026
Agent note — handed off to opencode claimant (task 7566) — ATTEMPTS 23/24, ONE CYCLE FROM CAP
opencode; the laptop claimant launches the bound session. This is attempt 23 of 24: if this lease also expires unlaunched (the pattern all last shift — every opencode handoff expired unlaunched, plausibly because of this very issue's truncation bug), task 7566 hits its attempt cap and becomes unclaimable until a cap raise or monitor repair. Flagging for the fleet monitor / Drew: cap raise for task 7566, or direct-lane reassignment so a worker lane can triage issue opencode-claimant: cap and supervision read GET /api/session, which truncates at 50 — active roots undercounted, live bound sessions reported gone #4757 itself.dezren39 commentedon Nov 5, 2026
🤖 Agent note · handed off