Proposal
Why
The spec-queue loop (loop-spec-queue) resolves its cursor by reading tasks.md
from the working tree (resolveQueue → readTasks → fs.readFileSync). When a
loop iteration checks out a different branch (e.g. loop/change-a) and the next
iteration targets a different change (e.g. loop/change-b), the queue resolution
reads tasks.md from whichever branch is currently checked out — not the branch
that belongs to the change being worked.
Observed failure:
The loop was working change A (all tasks checked, working tree on loop/a). It
then switched to loop/b for change B. When it returned to change A, the working
tree was still on loop/b, so resolveQueue read branch B's tasks.md and reported
a stale "next unchecked task" for change A. The loop burned 6+ iterations
re-reporting the same task, and the VERIFY gate reviewer hit its step limit
trying to verify a change that was already done.
What
The queue loop SHALL ensure the working tree is on the correct branch
(loop/<change-slug>) before reading tasks.md to derive the cursor and next
unchecked task. Alternatively, the queue resolution SHALL read tasks.md from
the change's branch directly (e.g. git show loop/<slug>:openspec/changes/<slug>/tasks.md)
without requiring a checkout.
Scope
packages/opencode/src/loop/spec-queue/queue.ts — resolveQueue / readTasks
packages/opencode/src/loop/spec-queue/brief.ts — buildBrief (reads tasks.md again)
- Possibly
packages/opencode/src/loop/loop.ts — branch checkout before iteration
Risks
git show reads are slower than direct file reads, but tasks.md is small
- If the branch doesn't exist yet (first iteration of a new change), fall back to
the working tree read
- Concurrent loops on different branches in the same repo could race on checkout;
git show avoids this entirely
Tasks
Phase 1: Reproduce and confirm
Phase 2: Fix
Phase 3: Verify
Proposal
Why
The spec-queue loop (
loop-spec-queue) resolves its cursor by readingtasks.mdfrom the working tree (
resolveQueue→readTasks→fs.readFileSync). When aloop iteration checks out a different branch (e.g.
loop/change-a) and the nextiteration targets a different change (e.g.
loop/change-b), the queue resolutionreads
tasks.mdfrom whichever branch is currently checked out — not the branchthat belongs to the change being worked.
Observed failure:
The loop was working change A (all tasks checked, working tree on
loop/a). Itthen switched to
loop/bfor change B. When it returned to change A, the workingtree was still on
loop/b, soresolveQueueread branch B's tasks.md and reporteda stale "next unchecked task" for change A. The loop burned 6+ iterations
re-reporting the same task, and the VERIFY gate reviewer hit its step limit
trying to verify a change that was already done.
What
The queue loop SHALL ensure the working tree is on the correct branch
(
loop/<change-slug>) before readingtasks.mdto derive the cursor and nextunchecked task. Alternatively, the queue resolution SHALL read
tasks.mdfromthe change's branch directly (e.g.
git show loop/<slug>:openspec/changes/<slug>/tasks.md)without requiring a checkout.
Scope
packages/opencode/src/loop/spec-queue/queue.ts—resolveQueue/readTaskspackages/opencode/src/loop/spec-queue/brief.ts—buildBrief(reads tasks.md again)packages/opencode/src/loop/loop.ts— branch checkout before iterationRisks
git showreads are slower than direct file reads, but tasks.md is smallthe working tree read
git showavoids this entirelyTasks
Phase 1: Reproduce and confirm
bun test packages/opencode/test/loop/spec-queue/queue-mode.test.tsPhase 2: Fix
readTasksbranch-aware: read tasks.md from the change's branch viagit showwhen the working tree is on a different branchbun typecheckin packages/opencodegit show loop/<slug>:openspec/changes/<slug>/tasks.mdwith fallback to direct file read when branch doesn't exist or git failsbuildBriefto use the same branch-aware read for the tasks.md content it embeds in the promptbun test packages/opencode/test/loop/spec-queue/bun test packages/opencode/test/loop/spec-queue/queue-mode.test.tsPhase 3: Verify
bun test packages/opencode/test/loop/bun typecheckin packages/opencode