fix(cleanup): keepBranch + sprint-scope siblings voor SPRINT pr_strategy
Symptoom: in een sprint met pr_strategy=SPRINT (5 tasks, 3 stories) werden de eerste twee tasks SKIPPED door Claude (werk al in main na een externe PR). De derde task crashte op: git worktree add /home/agent/.scrum4me-agent-worktrees/<id> feat/sprint-uhrbtc8z fatal: invalid reference: feat/sprint-uhrbtc8z Root cause: cleanupWorktreeForTerminalStatus checkte op active siblings binnen dezelfde **story** + verwijderde de branch bij keepBranch=false. Voor SPRINT pr_strategy delen alle stories in de sprint één branch (feat/sprint-<id>). Eerste task SKIPPED, story ST-1304 had geen actieve siblings meer (T-807 was ook al SKIPPED), branch werd verwijderd. T-808 in story ST-1305 wilde reuse'n maar branch bestond niet meer. Fix: 1. Sibling-check verbreden voor SPRINT pr_strategy: kijk naar alle actieve jobs in dezelfde sprint_run_id (niet alleen story_id). 2. keepBranch=true voor SKIPPED bij SPRINT pr_strategy: andere stories in dezelfde sprint hebben de branch nog nodig. Tests: 341 passed (38 files). Typecheck OK. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
parent
7d217cf443
commit
be2b5aef3d
1 changed files with 40 additions and 14 deletions
|
|
@ -71,31 +71,57 @@ export async function cleanupWorktreeForTerminalStatus(
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
// Branch-per-story: only remove the worktree if no sibling job in the same
|
// Branch-shared check: bepaal welke siblings dezelfde branch reuse'n.
|
||||||
// story is still active. If siblings are queued/claimed/running they will
|
// - SPRINT pr_strategy → alle TASK_IMPLEMENTATION jobs in dezelfde
|
||||||
// re-use this branch — destroying the worktree now wastes the next claim.
|
// sprint_run delen feat/sprint-<id>.
|
||||||
|
// - STORY pr_strategy / legacy → alle TASK_IMPLEMENTATION jobs in
|
||||||
|
// dezelfde story delen feat/story-<id>.
|
||||||
|
// Bij active siblings: defer cleanup (en in elk geval keepBranch=true)
|
||||||
|
// zodat de volgende claim de branch kan reuse'n.
|
||||||
const job = await prisma.claudeJob.findUnique({
|
const job = await prisma.claudeJob.findUnique({
|
||||||
where: { id: jobId },
|
where: { id: jobId },
|
||||||
select: { task: { select: { story_id: true } } },
|
select: {
|
||||||
|
task: { select: { story_id: true } },
|
||||||
|
sprint_run_id: true,
|
||||||
|
sprint_run: { select: { pr_strategy: true } },
|
||||||
|
},
|
||||||
})
|
})
|
||||||
if (job?.task) {
|
|
||||||
const activeSiblings = await prisma.claudeJob.count({
|
let activeSiblings = 0
|
||||||
|
let scope = ''
|
||||||
|
if (job?.sprint_run && job.sprint_run.pr_strategy === 'SPRINT') {
|
||||||
|
activeSiblings = await prisma.claudeJob.count({
|
||||||
|
where: {
|
||||||
|
sprint_run_id: job.sprint_run_id,
|
||||||
|
status: { in: ['QUEUED', 'CLAIMED', 'RUNNING'] },
|
||||||
|
id: { not: jobId },
|
||||||
|
},
|
||||||
|
})
|
||||||
|
scope = `sprint_run ${job.sprint_run_id}`
|
||||||
|
} else if (job?.task) {
|
||||||
|
activeSiblings = await prisma.claudeJob.count({
|
||||||
where: {
|
where: {
|
||||||
task: { story_id: job.task.story_id },
|
task: { story_id: job.task.story_id },
|
||||||
status: { in: ['QUEUED', 'CLAIMED', 'RUNNING'] },
|
status: { in: ['QUEUED', 'CLAIMED', 'RUNNING'] },
|
||||||
id: { not: jobId },
|
id: { not: jobId },
|
||||||
},
|
},
|
||||||
})
|
})
|
||||||
if (activeSiblings > 0) {
|
scope = `story ${job.task.story_id}`
|
||||||
console.log(
|
|
||||||
`[update_job_status] cleanup deferred for job=${jobId}: ${activeSiblings} sibling(s) still active in story ${job.task.story_id}`,
|
|
||||||
)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Keep branch when job is done and a branch was reported (agent pushed)
|
if (activeSiblings > 0) {
|
||||||
const keepBranch = status === 'done' && branch !== undefined
|
console.log(
|
||||||
|
`[update_job_status] cleanup deferred for job=${jobId}: ${activeSiblings} sibling(s) still active in ${scope}`,
|
||||||
|
)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// Keep branch when:
|
||||||
|
// - job is done en agent rapporteerde push (branch !== undefined), of
|
||||||
|
// - SPRINT pr_strategy job is skipped — andere stories delen branch.
|
||||||
|
const keepBranch =
|
||||||
|
(status === 'done' && branch !== undefined) ||
|
||||||
|
(status === 'skipped' && job?.sprint_run?.pr_strategy === 'SPRINT')
|
||||||
try {
|
try {
|
||||||
await removeWorktreeForJob({ repoRoot, jobId, keepBranch })
|
await removeWorktreeForJob({ repoRoot, jobId, keepBranch })
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue