Problem
The driver never asks whether an issue already has an open PR before building it again.
work-driver-commit.ts:212 calls gh pr create unconditionally. runBranch (work-driver-branch-develop.ts:45) never runs git rev-parse --verify <branch> or gh pr list. The only gh pr list --head call anywhere is a post-hoc repair inside the verification gate (work-driver-verify.ts:167), which adopts a PR number only when ops forgot to print the pr: marker.
The comment at work-driver-context.ts:177 — "Branch step's existing existing-branch detection handles worktree / branch leftovers at runtime" — describes logic that does not exist.
Live evidence — issue #5, 2026-08-05
/work was run with --restart while PR #358 was open for issue #5 on branch feature/issue-5-surface-thinking-only-output. --restart wipes the state file, so the driver treated #5 as greenfield: it branched a near-identical slug (feature/issue-5-surface-thinking-only-**model**-output), redid the entire implementation, and opened and merged PR #359.
Outcome:
Note the key insight: a branch-name-scoped lookup would not have caught this, because the second cycle chose a different branch name. The idempotency key has to be the issue number.
Proposed fix
A deterministic pre-flight at the top of runBranch, before the ops dispatch (so a doomed cycle burns zero tokens):
gh pr list --state open --json number,headRefName,body in repoRoot.
- Match an existing PR for this cycle's issue by either signal:
- body contains
Fixes #<N> — the driver writes this into every PR body it creates (work-driver-commit.ts:178), so it is reliable for driver-authored PRs;
headRefName matches issue-?<N> on a word boundary — catches human-authored and pre-driver branches.
- If a match is found, emit
cap-hit { cap: "existing-pr-detected", nextStep: "handoff" } carrying the PR number and its head branch.
Halt rather than auto-adopt. Adopting the PR number while the driver has committed to a different branch would attach our commits to a PR that does not contain them — the false-MERGED class this project has already hit twice (#245/#253). Deciding whether to resume the existing branch, retarget the PR, or close it is a judgment call, and per §7 doctrine a cap-hit produces a structured handoff rather than a question.
Escape hatch: PI_ENSEMBLE_PR_PREFLIGHT=0.
Acceptance criteria
Out of scope
Problem
The driver never asks whether an issue already has an open PR before building it again.
work-driver-commit.ts:212callsgh pr createunconditionally.runBranch(work-driver-branch-develop.ts:45) never runsgit rev-parse --verify <branch>orgh pr list. The onlygh pr list --headcall anywhere is a post-hoc repair inside the verification gate (work-driver-verify.ts:167), which adopts a PR number only when ops forgot to print thepr:marker.The comment at
work-driver-context.ts:177— "Branch step's existing existing-branch detection handles worktree / branch leftovers at runtime" — describes logic that does not exist.Live evidence — issue #5, 2026-08-05
/workwas run with--restartwhile PR #358 was open for issue #5 on branchfeature/issue-5-surface-thinking-only-output.--restartwipes the state file, so the driver treated #5 as greenfield: it branched a near-identical slug (feature/issue-5-surface-thinking-only-**model**-output), redid the entire implementation, and opened and merged PR #359.Outcome:
toolUses.length === 0before flaggingthinkingOnly; Surface thinking-only model output clearly instead of returning empty te #358 omits it and would false-positive on "thinking + tool calls". Whichever merged first won by accident, not by review.Note the key insight: a branch-name-scoped lookup would not have caught this, because the second cycle chose a different branch name. The idempotency key has to be the issue number.
Proposed fix
A deterministic pre-flight at the top of
runBranch, before the ops dispatch (so a doomed cycle burns zero tokens):gh pr list --state open --json number,headRefName,bodyinrepoRoot.Fixes #<N>— the driver writes this into every PR body it creates (work-driver-commit.ts:178), so it is reliable for driver-authored PRs;headRefNamematchesissue-?<N>on a word boundary — catches human-authored and pre-driver branches.cap-hit { cap: "existing-pr-detected", nextStep: "handoff" }carrying the PR number and its head branch.Halt rather than auto-adopt. Adopting the PR number while the driver has committed to a different branch would attach our commits to a PR that does not contain them — the false-MERGED class this project has already hit twice (#245/#253). Deciding whether to resume the existing branch, retarget the PR, or close it is a judgment call, and per §7 doctrine a cap-hit produces a structured handoff rather than a question.
Escape hatch:
PI_ENSEMBLE_PR_PREFLIGHT=0.Acceptance criteria
/work Nagainst an issue with no open PR is unaffected (no extraghcall on the hot path beyond the single pre-flight query)./work N --restartagainst an issue with an open PR halts atbranchwith capexisting-pr-detected, before any ops/developer dispatch.explainCaprenders a cause specific to this cap — not the genericelseboilerplate that currently advises raising a spawn timeout.execFncovers: no-PR (proceeds), matching PR byFixes #Nbody, matching PR by head-branch pattern, non-matching open PRs for other issues (proceeds), andghfailure (proceeds — fail-open, a lookup outage must not block work).work-driver-context.ts:177is corrected.Out of scope