Surface thinking-only model output clearly instead of returning empty te - #359
Merged
Merged
Conversation
This was referenced Aug 6, 2026
randomm
added a commit
that referenced
this pull request
Aug 6, 2026
… issue (#363) The driver never asked whether an issue already had a PR. runBranch did no lookup, and mechanizedCommitPr calls `gh pr create` unconditionally, so `--restart` — which wipes the state file but not GitHub — made the driver treat an in-flight issue as greenfield. Live evidence, issue #5 on 2026-08-05: PR #358 was open when `/work 5 --restart` ran. The driver picked a near-identical slug, rebuilt the whole issue, and merged it as #359. #358 is orphaned (its issue is closed, so it can never auto-close), a full cycle was paid for twice, and the two implementations had diverged — #359 guards `toolUses.length === 0`, #358 does not. Merge order decided the winner. The load-bearing detail is that the second cycle chose a DIFFERENT branch name, so a branch-scoped lookup would have missed it. The idempotency key has to be the issue number: a closing keyword in the PR body (the driver writes `Fixes #N` for every active issue), falling back to the head branch naming the issue for human-authored PRs. Both reject a numeric continuation so #5 does not match #55. Halts rather than adopts. Attaching new commits to a PR whose head is a different branch is the false-MERGED class (#245/#253), and choosing between resume / retarget / close is judgment — so per §7 this is a cap-hit with a structured handoff, not a question. Adoption needs mechanized branch setup and belongs to #287. The check runs BEFORE the ops dispatch, so a duplicate cycle costs zero tokens, and fails OPEN on any gh or parse error: the cost of missing a duplicate is one wasted cycle, the cost of a false halt is every cycle. explainCap and both handoff renderers get a case for the new cap, so it does not fall into the `else` branch that advises raising a spawn timeout. Also corrects the stale claim at work-driver-context.ts:177 that branch-step existing-branch detection already existed. Escape hatch: PI_ENSEMBLE_PR_PREFLIGHT=0. Fixes #362
randomm
added a commit
that referenced
this pull request
Aug 6, 2026
…365) * feat(#287): repoRoot is never a dev tree — always-worktree isolation Development happened in the operator's own checkout. runBranch set `worktrees = {default: repoRoot}` for N=1, the ops branch dispatch ran fetch/checkout/pull against repoRoot, and mechanizedCommitPr staged in place there. That single fact caused three separate failure classes: - stale repoRoot residue swept into a merged PR (incident #602); - an aborted step left a dirty tree, and because the branch step refused to run against one, that wedged EVERY downstream issue in the queue until a human intervened; - parallel groups were impossible — two cycles would fight over one checkout. After this, repoRoot is an integration point only. A. Mechanized branch setup (work-driver-branch-mechanized.ts). Resolves the base from origin/<mainline> rather than repoRoot's HEAD, names the branch deterministically, and creates one DETACHED worktree per workstream — including the degenerate N=1 `default`. `git fetch` is the only repoRoot command and it mutates refs, never the tree, so an operator's uncommitted work is both untouched and no longer able to block the cycle. The deterministic slug also removes the #358/#359 precondition where one issue got two LLM-authored branch names. B. integrate() (work-driver-integrate.ts) is now the ONLY writer to repoRoot: preflight clean → checkout -B <branch> <baseSha> → per worktree stage + `git diff --cached` → `git apply --index` → commit → push. Concentrating it here is what makes "no git at repoRoot between branch and commit-pr" a checkable property rather than a convention. #283's dirty-tree gate moves here, where it actually guards something. C. Lens-fix re-integration. lens-fix runs in the worktree, so committing at repoRoot found a clean tree and silently skipped — the fix never reached the PR. Follow-up integration fixes that latent bug. D. fetchIntegratedDiff reads origin/<base>..origin/<branch> at repoRoot. Worktrees stay detached at baseSha, so the old inside-the-worktree read would have returned empty on every cycle and skipped six-pass review — the same failure PR11 fixed once, from the other direction. E. runMerged tears down the cycle's worktrees. worktreeRemove had been exported and never invoked, so worktrees accumulated indefinitely. worktree.ts is rewritten: it had no importers, shelled out in process.cwd(), always created a scratch branch, and returned relative paths. It now takes the driver's ExecFn, so worktree setup is observable through the same injection seam the verify gates use. requireAllNonEmpty preserves an important existing behaviour I initially regressed: if ANY workstream produced no diff, commit-pr refuses rather than consolidating the rest. That is the v0.12.13 incident where 1 of 3 workstreams shipped and the issue closed with the root fix missing. The existing M3 fixture caught it. Lens-fix opts out — a fix round legitimately touches only the worktree that had findings. mechanizeOpsEnabled moves to the integrate leaf so the branch step can read it without closing an import cycle (#356 flags the same shape). Escape hatch PI_ENSEMBLE_ALWAYS_WORKTREE=0 restores the prior behaviour; the pre-existing mechanized-commit and skeleton fixtures now run under it, which makes the whole legacy suite the standing proof that the hatch works. Refs #287 * fix(#287): real-git test catches two showstoppers; worktree-aware handoff Adds test-work-driver-integrate-realgit.ts — the same flow against the real git binary in a throwaway repo with a local bare origin. The mocked sibling proves we ASK git the right things; it cannot prove git DOES the right thing. It immediately found two bugs that would have made #287 broken end-to-end in production: 1. `.worktrees/` read as untracked residue at the repo root, so integrate()'s dirty-root preflight refused EVERY integration, forever. Fixed by writing `.worktrees/` to .git/info/exclude (per-clone, never committed — the convention AGENTS.md §7 already mandates for tmp/), plus a defensive filter in the preflight for when that write fails. 2. After integrating, the worktree kept its slice staged, so the next integration re-captured the same patch. That is exactly how a lens-fix round would have silently re-committed the pre-fix content. Worktrees now advance to the commit their work became; reset --hard is safe there precisely because everything porcelain listed was staged and applied a moment earlier, so the commit is a superset of the worktree state. Also makes captureWorktreeSnapshot worktree-aware. The developer's uncommitted work lives in the worktrees now, so snapshotting the repo root alone reported "0 files modified" on exactly the handoffs where the operator needs to know what survived. Paths are prefixed with the workstream id when there is more than one. Docs: README gains PI_ENSEMBLE_ALWAYS_WORKTREE and PI_ENSEMBLE_PR_PREFLIGHT; work.md Step 2 no longer claims single-task cycles skip worktrees. 63/63 offline smoke tests, tsc + biome clean. Refs #287
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Automated by pi-ensemble /work driver (mechanized commit-pr).
Fixes #5