Three findings from PBI-47 review:
P1 — primary_worktree_path scheiden van lock-volgorde
setupProductWorktrees acquired locks in alphabetical order (deadlock prevention)
but also returned worktrees in that order, so worktrees[0] could point at a
secondary product when its id sorted before the primary's. Lock-acquire stays
sorted; output now preserves caller's input order so worktrees[0] is always
the primary.
P1 — Idea-claim rollback bij worktree setup failure
setupProductWorktrees runs after tryClaimJob has already flipped the job to
CLAIMED. A failure in lock-acquire/git-fetch/reset/sync left the job hanging
until the 30-min stale-reset and the lock-map populated. Wrapped in try/catch
with releaseLocksOnTerminal + rollbackClaim mirror of the task-pad behaviour.
P2 — SPRINT mark-ready fallback when last task didn't push
The mark-ready path used updated.pr_url, which is null when the closing task
was verify-only or had no diff. Now falls back to a Prisma findFirst on the
SprintRun's earliest job with pr_url IS NOT NULL.
Tests: 31 files, 243 passing (incl. new input-order regression for setupProductWorktrees).
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Two related fixes for the agent-workflow defects exposed by the
2-May-2026 batch:
1. **Cross-repo task routing** (`task.repo_url` override).
`resolveRepoRoot` now consults `task.repo_url` first; matches against
per-repo env-var (`SCRUM4ME_REPO_ROOT_REPO_<name>`),
`~/.scrum4me-agent-config.json` `repoRoots[<name>]`, and finally
`~/Projects/<name>/.git`. Falls back to product-level resolution
when null. Tasks tracked under one product but targeting another
repo (e.g. MCP-server tasks under the main product's PBI) now work.
`getFullJobContext` exposes `task.repo_url` to the agent.
`attachWorktreeToJob` accepts and forwards it.
2. **Orphan-branch cleanup** in `createWorktreeForJob`.
Previously a name-collision suffixed with a timestamp, leaving the
agent on an unpredictable `feat/story-XXX-<ms>`-name. Worse, in the
2-May batch the agent ended up reusing an orphan branch from an
earlier story (`feat/story-x35n155c`) and pushed to a remote ref
that did not exist, causing 'src refspec does not match any'.
Now: detect orphan, attempt to remove its (stale) worktree if any,
delete the local branch, and recreate with the predictable name.
Timestamp-suffix is the last resort.
Vendor submodule bumped to pick up `Task.repo_url` from Scrum4Me #54.
Tests: 129/129 — `suffixes branch name with timestamp` updated to
`removes orphan branch and reuses the predictable name`.
Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
New src/git/pr.ts helper wraps 'gh pr create'; returns { url } or { error }.
maybeCreateAutoPr() in update-job-status checks product.auto_pr, builds title
from story.code + task.title, writes pr_url to DB. Non-fatal: gh failure logs
a warning and leaves DONE status intact. Also syncs schema: auto_pr on Product,
pr_url on ClaudeJob.
Runs git push -u origin <branch> in the worktree. Detects no-changes
(HEAD = origin/main) before pushing. Classifies push failures into
no-credentials, conflict, or unknown via stderr pattern matching.
5 unit tests covering all paths.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Removes worktree dir via `git worktree remove --force` and deletes
the local branch by default; keepBranch=true preserves the branch.
Returns { removed: false } when the worktree path doesn't exist.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>