Cross-repo sprints (sprint-product = repo X, maar een taak heeft
task.repo_url naar repo Y) faalden op twee plekken omdat sprint-brede
beslissingen werden toegepast op per-repo git-state.
1. createWorktreeForJob (src/git/worktree.ts)
reuseBranch wordt sprint-breed bepaald in wait-for-job.ts. De eerste
job die repo Y target krijgt reuseBranch=true terwijl de branch daar
nooit is aangemaakt -> `git worktree add <path> <branch>` faalt met
"invalid reference" -> job vast, worker UNHEALTHY. Idem na een
container-recreate (clone is dan vers).
Fix: 3-weg fallback in het reuseBranch-pad:
- lokale branch bestaat -> hergebruik
- alleen op origin -> recreate lokaal vanaf origin/<branch>
- nergens -> fresh vanaf baseRef
Lost ook het container-recreate-verlies op.
2. maybeCreateAutoPr (src/tools/update-job-status.ts)
De sprint/story sibling-lookup voor pr_url-hergebruik filterde niet
op repo. Een repo-Y-job erfde de pr_url van een repo-X-sibling ->
job.pr_url wees naar de verkeerde repo en er werd nooit een PR voor
de repo-Y-branch aangemaakt (branch wel gepusht, maar PR-loos).
Fix: siblings groeperen per repo-bucket ((task.repo_url ?? null));
alleen een sibling uit dezelfde bucket levert een herbruikbare
pr_url. Geldt voor SPRINT- en STORY-mode. createPullRequest zelf was
al repo-correct (gh pr create draait in de worktree).
Tests: 3 nieuwe in worktree.test.ts (reuse-local / recreate-from-origin
/ fresh-fallback), 2 nieuwe in update-job-status-auto-pr.test.ts
(cross-repo story + sprint). update-job-status-mock omgezet naar
findMany. Alle 373 tests groen, build groen.
package-lock.json: version 0.7.0 -> 0.8.0 (was niet mee-gesynced in de
v0.8.0-bump commit 55fa133).
Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Implementeert vier open stories uit PBI 'Veilige Claude-agent-workflow':
**Branch per story (cmon11tbe001zbortx35n155c)**
- `resolveBranchForJob`: zoek sibling-job in dezelfde story; reuse z'n
branch (1 PR per story i.p.v. per task).
- Branch-naam: `feat/story-<8-char>` voor nieuwe stories.
- `createWorktreeForJob` kent nu `reuseBranch=true`: detecteert stale
sibling-worktree die de branch nog vasthoudt en verwijdert die eerst.
- `attachWorktreeToJob` neemt `storyId` mee.
**PR-hergebruik (zelfde story)**
- `maybeCreateAutoPr`: als sibling-job in story al een pr_url heeft,
hergebruik die zonder nieuwe `gh pr create`-call. PR-titel komt nu
van de story (was task) zodat het als 'story-PR' leest.
**Worktree-cleanup uitgesteld bij actieve siblings**
- `cleanupWorktreeForTerminalStatus`: count active sibling-jobs in
dezelfde story; defer als > 0 (volgende sub-task gebruikt branch).
**Worktree-cleanup logging (cmon0jc14001ubortjxf2a2ck)**
- Warning bij ontbrekende repoRoot, met productId + jobId in message.
- Warning bij removeWorktreeForJob-failure met keepBranch in message.
**resolveRepoRoot fallback (cmon0jc14001ubortjxf2a2ck)**
- Convention-based fallback: `~/Projects/<repo-name>` afgeleid uit
`product.repo_url` als noch env-var noch config-bestand iets oplevert.
- `repoNameFromUrl` helper geëxporteerd voor herbruikbaarheid.
**Verify EMPTY-detection edge-case (cmon0kdq6001xbort2kgbcqmr)**
- `classifyDiffAgainstPlan`: na file-paths-check ook content-lines
checken; als alle +/- regels alleen headers of whitespace zijn,
return EMPTY met duidelijke reasoning.
Tests: 120/120 groen (3 nieuwe), tsc clean, build clean.
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.