feat(PBI-4/ST-006): mirror job-config naar webapp + runbook-fix CLI-flags (#171)

Spiegelt de scrum4me-mcp wijzigingen naar de Scrum4Me web-app zodat
enqueue-laag (lib/job-config-snapshot.ts) en claim-laag dezelfde
defaults gebruiken. Plus runbook-correctie van een eerder gedocumenteerde
maar niet-bestaande Claude CLI-flag.

- T-25: lib/job-config.ts — mapBudgetToEffort export + KIND_DEFAULTS
  .allowed_tools voor TASK/SPRINT/IDEA_GRILL/IDEA_MAKE_PLAN omgezet
  naar expliciete lijsten zonder wait_for_job/check_queue_empty/
  get_idea_context. Comment-block over CLI-flag-mapping en sync met
  scrum4me-mcp.
- T-26: docs/runbooks/worker-idempotency.md sectie "Config doorgeven aan
  Claude Code (PBI-67)" herschreven. --thinking-budget vervangen door
  --effort (mapping-tabel toegevoegd); --max-turns geschrapt (CLI heeft
  die flag niet — audit-only). Sectie "Wie doet wat in de runner-
  architectuur" toegevoegd.
- T-27: docs/runbooks/job-model-selection.md — notes over max_turns,
  thinking_budget en allowed_tools onder de matrix. Nieuwe sectie
  "Runner-architectuur" met verwijzing naar plan + worker-idempotency.
- T-28: __tests__/lib/job-config.test.ts (nieuw) — 22 tests:
  mapBudgetToEffort grenswaarden + KIND_DEFAULTS.allowed_tools structurele
  checks + cascade regression.

Plus: docs/plans/queue-loop-extraction.md (geschreven in plan-mode,
nu gepubliceerd in repo).

Verify: lint OK, typecheck OK, 587 tests in 78 files passed.
Build niet lokaal uitgevoerd (vereist DATABASE_URL voor "Collecting page
data" — diff raakt geen API-route).

Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
Janpeter Visser 2026-05-09 07:11:52 +02:00 committed by GitHub
parent 10c52e8b8f
commit 00c5045558
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
6 changed files with 602 additions and 27 deletions

View file

@ -3,7 +3,7 @@ title: "Job-model-selectie per ClaudeJob-kind"
status: active
audience: [ai-agent, contributor]
language: nl
last_updated: 2026-05-08
last_updated: 2026-05-09
when_to_read: "Vóór het wijzigen van model/thinking/permission-mode-keuze of bij debugging van 'verkeerd model gebruikt'-incidents."
---
@ -45,6 +45,21 @@ altijd kind-default — geen product- of task-override.
| `TASK_IMPLEMENTATION` | `claude-sonnet-4-6` | 6 000 | `bypassPermissions` | 50 | (alle) |
| `SPRINT_IMPLEMENTATION` | `claude-sonnet-4-6` | 6 000 | `bypassPermissions` | (geen) | (alle) |
**Note over `max_turns`** (sinds queue-loop-refactor): dit veld blijft
audit-only. Claude CLI 2.1.x heeft géén `--max-turns` flag — de waarde
wordt gesnapshot in `ClaudeJob.requested_*` voor cost-attribution maar
niet doorgegeven aan Claude. Zie
[worker-idempotency.md](./worker-idempotency.md#config-doorgeven-aan-claude-code-pbi-67).
**Note over `thinking_budget`**: de CLI heeft alleen `--effort
{low,medium,high,xhigh,max}`. De runner mapt het numerieke budget naar
de juiste effort-laag via `mapBudgetToEffort()` in `lib/job-config.ts`.
**Note over `allowed_tools`**: de defaults sluiten bewust
`mcp__scrum4me__wait_for_job`, `check_queue_empty` en
`get_idea_context` uit. De runner claimt voor Claude — vangrail tegen
recursieve claims binnen één invocation.
**`bypassPermissions`** is verdedigbaar voor de implement-kinds omdat
elke run in een geïsoleerde git-worktree start (zie
[branch-and-commit.md](./branch-and-commit.md)). Productie-product?
@ -82,6 +97,25 @@ controleer de worker-script tegen de flag-tabel in
---
## Runner-architectuur (sinds 2026-05-09 queue-loop-refactor)
`scrum4me-docker/bin/run-one-job.ts` draait **één Claude-invocation per
geclaimde job**. De runner leest de `config` uit de
`wait_for_job`-payload (resolved via deze module) en bouwt
kind-specifieke CLI-flags. Voor de exacte flag-mapping (incl. `--effort`
en `--allowedTools`) zie
[worker-idempotency.md](./worker-idempotency.md#config-doorgeven-aan-claude-code-pbi-67).
Praktische gevolgen:
- Per job-spawn een nieuwe Claude-invocation met andere flags — geen
config-mismatch tussen jobs in dezelfde queue-run.
- Verschillen tussen `requested_model` en `model_id` in admin → Jobs
duiden óf op handmatige DB-overrides tussen enqueue en claim, óf op
Claude die zelf een ander model rapporteerde (bv. fallback bij
overload).
- Plan: [queue-loop-extraction.md](../plans/queue-loop-extraction.md).
## Cost-attribution
Thinking-tokens worden bij Anthropic-billing gerekend tegen de

View file

@ -3,7 +3,7 @@ title: "Worker idempotency & job-status protocol"
status: active
audience: [ai-agent, contributor]
language: nl
last_updated: 2026-05-05
last_updated: 2026-05-09
when_to_read: "Vóór het implementeren of debuggen van Claude-CLI-worker logica die `update_job_status` aanroept."
---
@ -113,43 +113,71 @@ Drie protocol-overtredingen die we met deze runbook + de nieuwe
## Config doorgeven aan Claude Code (PBI-67)
`wait_for_job` levert sinds PBI-67 een `config`-object mee in de
response. Geef deze door aan `claude` als CLI-flags:
response. **De runner** (`scrum4me-docker/bin/run-one-job.ts`) leest deze
config en bouwt per geclaimde job de juiste Claude CLI-flags. Eén
Claude-invocation per job — niet één lange sessie die zelf claimt.
```bash
claude \
-p "$PROMPT" \
--model "$MODEL" \
--permission-mode "$PERMISSION_MODE" \
--thinking-budget "$THINKING_BUDGET" \
${MAX_TURNS:+--max-turns $MAX_TURNS} \
${ALLOWED_TOOLS:+--allowed-tools "$ALLOWED_TOOLS"}
${EFFORT:+--effort $EFFORT} \
--allowedTools "$ALLOWED_TOOLS" \
--mcp-config /opt/agent/mcp-config.json \
--add-dir /opt/agent \
--output-format text
```
Waar:
| Variabele | Bron in response | Voorbeeld |
|---|---|---|
| `PROMPT` | `getKindPromptText(kind)` met `$PAYLOAD_PATH` vervangen | (kind-prompt-md) |
| `MODEL` | `config.model` | `claude-sonnet-4-6` |
| `PERMISSION_MODE` | `config.permission_mode` | `bypassPermissions` |
| `THINKING_BUDGET` | `config.thinking_budget` (0 = uit) | `12000` |
| `MAX_TURNS` | `config.max_turns` (null = onbegrensd) | `15` of leeg |
| `ALLOWED_TOOLS` | `config.allowed_tools.join(',')` (null = alle) | `Read,Grep,WebSearch` |
| `EFFORT` | `mapBudgetToEffort(config.thinking_budget)` (null = vlag weg) | `medium` |
| `ALLOWED_TOOLS` | `config.allowed_tools.join(',')` | `Read,Edit,…,mcp__scrum4me__update_task_status,…` |
Verwachte CLI-aanroep per kind (kind-defaults zonder overrides):
### Claude CLI 2.1.x flag-correctie
| Kind | Model | thinking | permission_mode | max_turns |
De Claude CLI 2.1.x heeft géén numerieke `--thinking-budget` en géén
`--max-turns`. Mapping:
| `config.thinking_budget` | CLI-flag |
|---|---|
| 0 | (geen `--effort` flag) |
| 1-6000 | `--effort medium` |
| 6001-12000 | `--effort high` |
| 12001-24000 | `--effort xhigh` |
| >24000 | `--effort max` |
`config.max_turns` blijft **audit-only** — wordt gesnapshot in
`ClaudeJob.requested_*` voor cost-attribution maar niet doorgegeven aan
Claude. De resolver in `lib/job-config.ts` exporteert
`mapBudgetToEffort(budget)` voor deze mapping.
### Verwachte CLI-aanroep per kind (defaults zonder overrides)
| Kind | Model | thinking_budget | --effort | permission_mode |
|---|---|---|---|---|
| `IDEA_GRILL` | sonnet-4-6 | 12000 | plan | 15 |
| `IDEA_MAKE_PLAN` | opus-4-7 | 24000 | plan | 20 |
| `PLAN_CHAT` | sonnet-4-6 | 6000 | plan | 5 |
| `TASK_IMPLEMENTATION` | sonnet-4-6 | 6000 | bypassPermissions | 50 |
| `SPRINT_IMPLEMENTATION` | sonnet-4-6 | 6000 | bypassPermissions | (geen) |
| `IDEA_GRILL` | sonnet-4-6 | 12000 | high | plan |
| `IDEA_MAKE_PLAN` | opus-4-7 | 24000 | xhigh | plan |
| `PLAN_CHAT` | sonnet-4-6 | 6000 | medium | plan |
| `TASK_IMPLEMENTATION` | sonnet-4-6 | 6000 | medium | bypassPermissions |
| `SPRINT_IMPLEMENTATION` | sonnet-4-6 | 6000 | medium | bypassPermissions |
**Onbekende flag:** als de huidige Claude Code-versie een vlag niet
kent, log een waarschuwing en sla 'm over — geen hard error. De server
blijft jobs queuen.
### Wie doet wat in de runner-architectuur
| Component | Verantwoordelijkheid |
|---|---|
| `bin/run-agent.sh` | Daemon-loop, exponential backoff, UNHEALTHY-marker, log-rotation, TOKEN_EXPIRED-detectie via exit-code 3 of stdout-regex |
| `bin/run-one-job.ts` | **Claim** (tryClaimJob + LISTEN-fallback 270s), config-resolve (getFullJobContext), payload schrijven, **CLI-flags bouwen**, spawn `claude`, lease-renewal voor SPRINT (setInterval 60s), rollbackClaim bij Claude exit≠0 zonder update_job_status, cleanup |
| `claude` (per invocation) | Voert exclusief de geclaimde job uit. **Mag geen** `wait_for_job`, `check_queue_empty`, of `job_heartbeat` aanroepen — zit niet in `allowed_tools` |
Volledige resolver-uitleg + override-cascade staat in
[job-model-selection.md](./job-model-selection.md).
[job-model-selection.md](./job-model-selection.md). Refactor-plan:
[queue-loop-extraction.md](../plans/queue-loop-extraction.md).
---