diff --git a/CLAUDE.md b/CLAUDE.md index 566c755..0b85bf0 100644 --- a/CLAUDE.md +++ b/CLAUDE.md @@ -115,3 +115,5 @@ PBI (niet: Feature/Epic) · Story (niet: Ticket) · Sprint Goal (niet: Objective ```bash npm run lint && npm test && npm run build ``` + +Worker job-status protocol (wanneer `DONE` / `SKIPPED` / `FAILED`): zie [docs/runbooks/worker-idempotency.md](./docs/runbooks/worker-idempotency.md). diff --git a/docs/INDEX.md b/docs/INDEX.md index 78e2edf..e575498 100644 --- a/docs/INDEX.md +++ b/docs/INDEX.md @@ -114,6 +114,7 @@ Auto-generated on 2026-05-05 from front-matter and headings. | [Vercel Deployment](./runbooks/deploy-vercel.md) | `runbooks/deploy-vercel.md` | active | 2026-05-03 | | [MCP Integration — Scrum4Me Tools](./runbooks/mcp-integration.md) | `runbooks/mcp-integration.md` | active | 2026-05-03 | | [v1.0 Smoke Test Checklist](./runbooks/v1-smoke-test.md) | `runbooks/v1-smoke-test.md` | active | 2026-05-04 | +| [Worker idempotency & job-status protocol](./runbooks/worker-idempotency.md) | `runbooks/worker-idempotency.md` | active | 2026-05-05 | | [StoryDialog Profiel](./story-dialog.md) | `story-dialog.md` | active | 2026-05-03 | | [TaskDialog Profiel](./task-dialog.md) | `task-dialog.md` | active | 2026-05-03 | | [Scrum4Me — API Test Plan](./test-plan.md) | `test-plan.md` | active | 2026-05-03 | diff --git a/docs/runbooks/worker-idempotency.md b/docs/runbooks/worker-idempotency.md new file mode 100644 index 0000000..38e023b --- /dev/null +++ b/docs/runbooks/worker-idempotency.md @@ -0,0 +1,122 @@ +--- +title: "Worker idempotency & job-status protocol" +status: active +audience: [ai-agent, contributor] +language: nl +last_updated: 2026-05-05 +when_to_read: "Vóór het implementeren of debuggen van Claude-CLI-worker logica die `update_job_status` aanroept." +--- + +# Worker idempotency & job-status protocol + +Beschrijft hoe de Scrum4Me-worker `ClaudeJob.status` moet zetten op basis +van `VerifyResult` × git-diff-staat × branch-staat. Doel: voorkom +status-divergentie zoals geconstateerd in de **PBI-33 batch (5-5-2026 +22:22)** waarin werk dat al gemerged was via PR #102/#103/#104 leidde +tot inconsistente combinaties van `verify=EMPTY → FAILED` en +`verify=DIVERGENT → DONE`. + +--- + +## Beslissingsboom + +Aan het einde van een story-job, ná `verify`-pass: + +| `verify_result` | netto diff t.o.v. `origin/main` | branch al gemerged | → `ClaudeJob.status` | `Task.status` | +|---|---|---|---|---| +| `ALIGNED` of `PARTIAL` | nieuwe commit aanwezig | n.v.t. | **`DONE`** | `DONE` | +| `EMPTY` | leeg (niets gewijzigd) | werk zit al op `origin/main` | **`SKIPPED`** | `DONE` | +| `EMPTY` | leeg, maar werk staat **niet** op origin | n.v.t. | **`FAILED`** (`error: "verify produced no output"`) | `IN_PROGRESS` (handmatig onderzoeken) | +| `DIVERGENT` | aanwezig, maar identiek aan al-gemergde branch | ja (PR closed/merged) | **`SKIPPED`** | `DONE` | +| `DIVERGENT` | aanwezig, niet matchend met main | nee | **`FAILED`** (`error: "verify divergent — handmatige review"`) | `IN_PROGRESS` | +| (compile-fail, test-fail, push-fail, exception) | n.v.t. | n.v.t. | **`FAILED`** met concrete `error` | `IN_PROGRESS` | +| (gebruiker drukt cancel) | n.v.t. | n.v.t. | **`CANCELLED`** | `TO_DO` | + +### Vuistregels + +- **`SKIPPED`** = "geen netto-output, maar geen fout" — werk was al + gedaan vóór deze job draaide. Task mag op `DONE` omdat het beoogde + resultaat in main aanwezig is. +- **`FAILED`** is gereserveerd voor échte fouten: code-fouten, + test-failures, push-fouten, onverklaarde diff. Niet voor + "implementatie was al gedaan". +- **`DONE`** alleen bij `ALIGNED`/`PARTIAL` mét nieuwe commit op de + feature-branch. Een lege `DIVERGENT` op een al-gemergde branch is + géén `DONE`. + +--- + +## StoryLog-verplichting + +Tijdens elke job moet de worker `story_logs`-entries schrijven via de +MCP-tools, anders is de Sync-tab leeg: + +| Wanneer | MCP-tool | Inhoud | +|---|---|---| +| Bij claim | `log_implementation` | "Start implementatie van T-XXX. Branch X. Plan: …" | +| Per commit | `log_commit` | hash + message + samenvatting van wijzigingen | +| Na verify | `log_test_result` | status `PASSED` of `FAILED` + samenvatting van checks | + +In **PBI-33 batch** zijn deze tools **niet** aangeroepen — `story_logs` +voor ST-1208/1209/1210 is leeg. Worker MAG geen job afronden zonder +minimaal één `log_implementation` (start) en één `log_test_result` +(eind). + +--- + +## Idempotency-protocol (vóór schrijven) + +Bij claim van een job: + +1. Lees `Task.implementation_plan` — beschrijft expliciet welke files + gewijzigd moeten worden. +2. Vergelijk de huidige `origin/main`-staat met die plan-instructies: + - Bestaat het bestand al met de beoogde inhoud? + - Bestaat de migratie al? + - Bevat de relevante codepad de nieuwe symbolen/types? +3. Bij **volledige hit**: roep `log_implementation` met inhoud "Werk + reeds aanwezig op origin/main vanaf commit X (Y)." Sla + verify-stap over en zet `JobStatus.SKIPPED`. Task naar `DONE`. +4. Bij **gedeeltelijke hit**: log de bevindingen via + `log_implementation` en doe alleen het resterende werk. Eindig met + `DONE` (`ALIGNED` of `PARTIAL`) als je netto-output hebt. + +Dit voorkomt dubbele commits op al-gemergde branches en houdt +`pushed_at` semantisch correct (alleen gevuld als er werkelijk +gepusht is). + +--- + +## Case-study: PBI-33 (5-5-2026 22:22) + +PBI-33 ("PLAN_CHAT — gebruikersvragen over plan") werd opnieuw aangemaakt +nadat de feature al via een eerdere batch was gemerged onder cuid-style +story-codes (`ST-bsjoqjnr`, `ST-p6d1odh0`, …). De worker draaide om +22:22 en zag: + +- **T-533** (`ST-1208` schema-werk): diff = leeg → `verify=EMPTY` → + `Job.FAILED` met error "Implementatie reeds voltooid en gemerged". + Volgens het nieuwe protocol had dit **`SKIPPED`** moeten zijn. +- **T-534…538**: diff niet leeg op feature-branches `feat/story-7pl4dsb6` + en `feat/story-0vtnydpi` (al-gemergde branches uit eerdere PR's) → + `verify=DIVERGENT` → `Job.DONE` met `pushed_at=now()`. Volgens het + nieuwe protocol had dit ook **`SKIPPED`** moeten zijn — branch was + al closed/merged, geen nieuwe commit. +- **`story_logs` voor ST-1208/1209/1210 is leeg** — geen + `log_implementation`, geen `log_commit`, geen `log_test_result`. + +Drie protocol-overtredingen die we met deze runbook + de nieuwe +`SKIPPED`-status aanpakken. + +--- + +## Referenties + +- Enum: `prisma/schema.prisma` → `enum ClaudeJobStatus` +- Mapping: `lib/job-status.ts` (DB↔API) en + `components/shared/job-status.ts` (label + kleur) +- Status-data-cleanup: `app/api/cron/cleanup-agent-artifacts/route.ts` +- KPI-aggregatie: `lib/insights/agent-throughput.ts` (terminal_7d + inclusief SKIPPED) +- Gerelateerd plan: `docs/plans/auto-pr-deploy-sync.md` Deel D + (Sync-tab toont per-Story job-status incl. SKIPPED)