PBI-50 F0-2 + F5: PER_TASK verify-gate + SPRINT_IMPLEMENTATION-loop

PER_TASK-loop uitgebreid met verify_task_against_plan en update_task_status
vóór update_job_status (eenmalige investering, ook PER_TASK-flow profiteert).

Nieuwe SPRINT_IMPLEMENTATION-sectie met:
- heartbeat-loop met sprint_run_status-check voor cancel/pause-detectie
- per-task quota-probe → QUOTA_PAUSE flow
- update_task_execution lifecycle (RUNNING → DONE/FAILED)
- verify_sprint_task per execution
- één branch voor de hele sprint, base_sha auto-fill via vorige
  DONE-execution head_sha
- cascade-stop bij eerste FAIL

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
Madhura68 2026-05-07 12:54:42 +02:00
parent d01c8956d7
commit b6bea1ecbb

View file

@ -50,31 +50,103 @@ of equivalent:
ST-code in de titel). ST-code in de titel).
5. Voer de project-verificaties uit die de project-CLAUDE.md voorschrijft 5. Voer de project-verificaties uit die de project-CLAUDE.md voorschrijft
(typisch `npm run lint && npm test && npm run build`). (typisch `npm run lint && npm test && npm run build`).
6. **Niet zelf pushen of PR's maken.** Lokaal committen op een 6. **Verify-gate** (PBI-50 F0-2). Roep
`mcp__scrum4me__verify_task_against_plan({ task_id, worktree_path })`
aan. De tool draait `git diff <base_sha>...HEAD` en classificeert tegen
het frozen `implementation_plan`. Antwoord bevat `verify_result` +
`allowed_for_done`. Als `allowed_for_done=false`:
- Bij `verify_result=PARTIAL` of `DIVERGENT`: roep opnieuw aan met
`summary: "<2-3 zinnen waarom afwijking gerechtvaardigd is>"`.
- Geen summary forceren als die er niet is — dan is `failed` correcter
dan een PARTIAL met fake-summary.
7. **Per-task status** (PBI-50 F0-2). Roep
`mcp__scrum4me__update_task_status({ task_id, status: 'DONE' })` aan
vóór `update_job_status`. Cascade naar Story → PBI gebeurt
server-side via `propagateStatusUpwards`.
8. **Niet zelf pushen of PR's maken.** Lokaal committen op een
feature-branch is goed. De MCP-tool `update_job_status('done')` feature-branch is goed. De MCP-tool `update_job_status('done')`
verzorgt push + auto-PR + auto-merge zelf (mits `Product.auto_pr=true`). verzorgt push + auto-PR + auto-merge zelf (mits `Product.auto_pr=true`).
7. Roep `mcp__scrum4me__update_job_status` aan met: 9. Roep `mcp__scrum4me__update_job_status` aan met:
- `status: "done"` als verificaties slaagden, plus `branch` en - `status: "done"` als verify-gate én verificaties slaagden, plus
`summary`. `branch` en `summary`.
- `status: "failed"` met `error` als iets onomkeerbaar misging. - `status: "failed"` met `error` als iets onomkeerbaar misging.
- Bij `done`: de tool pusht je commits automatisch en maakt - Bij `done`: de tool pusht je commits automatisch en maakt
zo nodig een PR aan met auto-merge actief. Verwacht dus dat zo nodig een PR aan met auto-merge actief. Verwacht dus dat
de respons `pushed_at` en `pr_url` kan bevatten. de respons `pushed_at` en `pr_url` kan bevatten.
8. Roep `mcp__scrum4me__check_queue_empty` aan (geen args). Dit is een 10. Roep `mcp__scrum4me__check_queue_empty` aan (geen args). Dit is een
synchrone non-blocking poll die in één keer teruggeeft of er nog synchrone non-blocking poll die in één keer teruggeeft of er nog
werk in de queue staat: werk in de queue staat:
- `empty: false` → ga direct naar stap 3 (`wait_for_job` opnieuw). - `empty: false` → ga direct naar stap 3 (`wait_for_job` opnieuw).
- `empty: true` → batch is klaar; geef recap en exit. Geen extra - `empty: true` → batch is klaar; geef recap en exit. Geen extra
`wait_for_job`-call die 600 s blokt. `wait_for_job`-call die 600 s blokt.
9. Roep `bash /opt/agent/bin/job-cleanup.sh <job_id>` aan om de 11. Roep `bash /opt/agent/bin/job-cleanup.sh <job_id>` aan om de
working tree op te ruimen en logs naar `/var/log/agent` te kopiëren. working tree op te ruimen en logs naar `/var/log/agent` te kopiëren.
3. Op basis van stap 8: bij `empty: false` opnieuw `wait_for_job`; bij 3. Op basis van stap 10: bij `empty: false` opnieuw `wait_for_job`; bij
`empty: true` direct naar stap 4. Stop niet midden in de loop, vraag `empty: true` direct naar stap 4. Stop niet midden in de loop, vraag
niets. niets.
4. Pas wanneer `wait_for_job` na de volledige block-time terugkomt zonder 4. Pas wanneer `wait_for_job` na de volledige block-time terugkomt zonder
claim, óf `check_queue_empty` empty=true retourneerde, sluit de turn claim, óf `check_queue_empty` empty=true retourneerde, sluit de turn
af met een korte recap (aantal jobs, success/fail). af met een korte recap (aantal jobs, success/fail).
## SPRINT_IMPLEMENTATION-modus (PBI-50)
Wanneer `wait_for_job` een job teruggeeft met `kind === 'SPRINT_IMPLEMENTATION'`:
context bevat geen single-task-velden (`task`, `story`, `pbi`, `commit_strategy`)
maar in plaats daarvan:
- `sprint`, `sprint_run`, `product`
- `pbis[]`, `stories[]` (alle in scope)
- `task_executions[]` — per task: `{ execution_id, task_id, code, title,
story_id, order, plan_snapshot, verify_required, verify_only, base_sha }`
- `worktree_path`, `branch_name`, `repo_url`
- `heartbeat_interval_seconds: 60`
**Loop voor de hele sprint (één claude-sessie):**
1. Lees project-CLAUDE.md (voor coding-standards) — dezelfde stap als PER_TASK.
2. Start een achtergrond-heartbeat-loop: elke 60 s
`mcp__scrum4me__job_heartbeat({ job_id })`. De respons bevat
`sprint_run_status` + `sprint_run_pause_reason`. Bij `sprint_run_status !==
'RUNNING'`: breek de task-loop direct (UI-cancel of sibling-fail).
3. Voor elke `execution` in `task_executions[]` (al gesorteerd op order):
1. **Quota-probe** (PBI-50 F4-T3). `worker_quota-probe.sh`
`worker_heartbeat({ last_quota_pct })`. Als `pct < min_quota_pct`:
maak de huidige task af (commit + verify + execution DONE), roep
dan `update_job_status('failed', error: "QUOTA_PAUSE: pct=<x>")`
aan. De server zet de SprintRun op PAUSED en de resume-flow maakt
een nieuwe SprintRun met previous_run_id + branch-hergebruik.
2. `update_task_execution({ execution_id, status: 'RUNNING' })`.
3. Voer `plan_snapshot` uit. Commit per laag in dezelfde branch
(`branch_name` is gelijk aan `sprint_run.branch`). ST-codes per task.
4. Project-verificaties (`npm run lint && npm test && npm run build`)
— per task draaien is duurzamer maar voor sprints van >5 tasks
kun je tussentijds skippen mits geen impact buiten task-scope.
5. `verify_sprint_task({ execution_id, worktree_path, summary? })`.
Bij `allowed_for_done=false`: roep opnieuw aan met `summary` of
markeer de execution als `FAILED`. Bij FAILED: cascade-stop —
`update_task_execution(FAILED)` + `update_task_status(FAILED,
sprint_run_id)` + `update_job_status('failed', error: "task <code>:
<reason>")`. De rest van de task_executions wordt niet uitgevoerd.
6. `update_task_execution({ execution_id, status: 'DONE', head_sha:
<huidige HEAD> })`.
7. `update_task_status({ task_id, status: 'DONE', sprint_run_id })`
— verplicht meegeven zodat de token-coupling-check slaagt en
cascade naar Story → PBI gebeurt binnen deze SprintRun.
4. Aan het eind van alle tasks (geen FAIL en geen quota-pause):
`update_job_status('done', branch, summary: "<sprint-recap>")`. De
tool roept `checkSprintVerifyGate` aan, pusht de branch, maakt één
draft-PR met `sprint.sprint_goal` als titel en — als alle stories
DONE/FAILED zijn — markeert de SprintRun zelf op DONE en de PR op
ready-for-review.
5. Stop de heartbeat-loop, ga naar `check_queue_empty` zoals PER_TASK.
**Belangrijk:** SPRINT-modus gebruikt **één branch** voor alle tasks
(branch_name uit context). Geen branch-wissels per task. De
`base_sha` voor task[0] zit in execution.base_sha; task[1..N] krijgt
`base_sha` automatisch ingevuld door `verify_sprint_task` op basis van
`head_sha` van de vorige DONE-execution — dus `update_task_execution(DONE,
head_sha=...)` is **kritiek** voor de chain.
## Foutscenario's ## Foutscenario's
- **`job-prepare.sh` faalt** (clone-fout, disk-fout): rapporteer - **`job-prepare.sh` faalt** (clone-fout, disk-fout): rapporteer