* feat(PBI-67/ST-1297): datamodel-velden voor job-model-selectie
Voegt 8 nieuwe optionele velden toe verspreid over Product, Task en
ClaudeJob ten dienste van de override-cascade:
task.requires_opus → job.requested_* → product.preferred_* → kind-default
Bestaande rijen krijgen NULL (Product/ClaudeJob) of false (Task) en
vallen daarmee terug op de kind-defaults uit de resolver (ST-1298).
Migration is additief: alleen ALTER TABLE ADD COLUMN, geen RENAME of
DROP. Bestaande factories en seed-script blijven werken zonder
aanpassing omdat alle nieuwe velden default-waardes hebben.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
* feat(PBI-67/ST-1299): job-config snapshot bij enqueue + worker-flag-runbook
T-789: Snapshot van resolved JobConfig in ClaudeJob.requested_*
bij elke job-creatie. Helper in lib/job-config-snapshot.ts laadt
product (preferred_*) en task (requires_opus) en draait de resolver
uit lib/job-config.ts (mirror van scrum4me-mcp/src/lib/job-config.ts —
zelfde matrix, sync-comment in bestand). Toegepast op alle 5
enqueue-locaties:
- actions/user-questions.ts (PLAN_CHAT)
- actions/sprint-runs.ts × 3 (SPRINT_IMPLEMENTATION x2,
TASK_IMPLEMENTATION loop)
- actions/ideas.ts (IDEA_GRILL / IDEA_MAKE_PLAN)
Test-mocks uitgebreid met product.findUnique en task.findUnique zodat
de helper bij unit tests veilig terugvalt op kind-defaults (alle 563
tests groen).
T-790: Sectie 'Config doorgeven aan Claude Code' toegevoegd aan
docs/runbooks/worker-idempotency.md met CLI-flag-mapping en de
verwachte aanroep per kind. Forward-link naar
docs/runbooks/job-model-selection.md (volgt in T-794).
Plus: docs/plans/job-model-selection.md (de approved plan-doc).
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
* feat(PBI-67/ST-1300): cost-attribution voor thinking-tokens + admin UI
T-792: token-stats + token-history rekenen actual_thinking_tokens nu
mee in de totale kosten (tegen input-rate, conform Anthropic billing).
COALESCE-veilig zodat oude rijen 0 bijdragen i.p.v. NaN. Nieuwe export
`getTokenStatsByKind` aggregeert tokens en kosten per ClaudeJob.kind
zodat we relatieve uitgaven van IDEA_GRILL/IDEA_MAKE_PLAN/PLAN_CHAT/
TASK_IMPLEMENTATION/SPRINT_IMPLEMENTATION kunnen zien.
T-793: admin/jobs Kosten-tabel toont:
- Nieuwe kolom 'Thinking' (aantal verbruikte thinking-tokens)
- Mismatch-marker (rood) als requested_model afwijkt van actuele
model_id — duidt op een worker die de CLI-flag niet doorgaf.
Tooltip toont aangevraagd model. Geen Sentry/log-noise.
Page-level cost-berekening volgt dezelfde formule (input_price ×
thinking_tokens). 563 tests groen.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
* docs(PBI-67/ST-1301): runbook + CLAUDE.md updates voor model/mode-selectie
T-794: Nieuwe runbook docs/runbooks/job-model-selection.md met
override-cascade, kind-default-matrix, override-voorbeelden,
auditspoor en cost-attribution-formule. 107 regels.
T-795: CLAUDE.md hardstop-bullet voor 'Model/mode per ClaudeJob'
(verwijst naar nieuwe runbook) + patterns-quickref-rij voor
job-config resolver. CLAUDE.md blijft 139 regels (≤ 150).
T-796: docs:check-links groen — 108 files, geen broken links. Twee
externe-repo verwijzingen (scrum4me-mcp/...) ge-de-linked tot plain
text omdat de check-links script de zustertree niet traverseert; de
referenties blijven leesbaar.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
---------
Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
9.2 KiB
Plan: model + mode-selectie per ClaudeJob-kind
Context
ClaudeJob heeft 5 kinds (TASK_IMPLEMENTATION, IDEA_GRILL, IDEA_MAKE_PLAN, PLAN_CHAT, SPRINT_IMPLEMENTATION) maar er is geen per-kind model-/mode-configuratie. Alle jobs draaien op de Claude Code CLI default. ClaudeJob.model_id (prisma/schema.prisma) wordt alleen post-hoc gevuld voor kostenberekening via lib/insights/token-stats.ts en model_prices (PBI-66).
Probleem: een grill-sessie verdient meer thinking-budget en geen file-edits, terwijl een task-implementation acceptEdits/bypassPermissions in een worktree wil. Nu is dat allemaal hetzelfde — wat leidt tot:
- Te dure runs (Opus voor triviale Haiku-waardige taken)
- Te schrale runs (Sonnet zonder thinking voor architectuurkeuze in
IDEA_MAKE_PLAN) - Geen cost-attribution per kind voor budgettering
- Geen product-level override voor klanten met eigen model-voorkeur
Doel: een resolver die per ClaudeJob bepaalt: model, thinking-budget, permission-mode, max_turns, allowed_tools — gebaseerd op kind-defaults met overrides per product en per job. De worker geeft de geresolveerde config door aan Claude Code via CLI-flags.
Niet-doel: de runtime vervangen door de Claude Agent SDK. Worker blijft Claude Code CLI; we bouwen erbovenop.
Aanpak
1. Datamodel-uitbreiding
| Tabel | Veld | Type | Doel |
|---|---|---|---|
Product |
preferred_model |
String? |
Product-brede default (bv. "alle taken op Sonnet voor budget") |
Product |
thinking_budget_default |
Int? |
Idem voor thinking |
Task |
requires_opus |
Boolean @default(false) |
Per-task escalatie (cross-file refactor) |
ClaudeJob |
requested_model |
String? |
Snapshot van resolved model (audit) |
ClaudeJob |
requested_thinking_budget |
Int? |
Snapshot van resolved budget |
ClaudeJob |
requested_permission_mode |
String? |
Snapshot van resolved mode |
ClaudeJob |
actual_thinking_tokens |
Int? |
Werkelijk verbruikte thinking-tokens (cost-attribution) |
Migration is additief. Bestaande rijen krijgen NULL → resolver valt terug op kind-defaults.
2. Centrale resolver
Locatie: scrum4me-mcp/src/lib/job-config.ts (nieuw bestand in MCP-repo).
type JobConfig = {
model: 'claude-opus-4-7' | 'claude-sonnet-4-6' | 'claude-haiku-4-5-20251001'
thinking_budget: number // 0 = uit
permission_mode: 'plan' | 'default' | 'acceptEdits' | 'bypassPermissions'
max_turns: number | null // null = onbegrensd
allowed_tools: string[] | null // null = alle
}
function resolveJobConfig(job: ClaudeJob, product: Product, task?: Task): JobConfig
Resolutie-volgorde (eerste match wint):
task.requires_opus === true→ forceer model =claude-opus-4-7job.requested_*(al ingevuld door enqueue-laag)product.preferred_*- Kind-default uit deze tabel:
| Kind | Model | Thinking | Permission | max_turns | allowed_tools |
|---|---|---|---|---|---|
IDEA_GRILL |
sonnet-4-6 | 12000 | plan |
15 | Read, Grep, Glob, WebSearch, AskUserQuestion |
IDEA_MAKE_PLAN |
opus-4-7 | 24000 | plan |
20 | Read, Grep, Glob, WebSearch, AskUserQuestion, Write |
PLAN_CHAT |
sonnet-4-6 | 6000 | plan |
5 | Read, Grep, AskUserQuestion |
TASK_IMPLEMENTATION |
sonnet-4-6 | 6000 | bypassPermissions |
50 | null |
SPRINT_IMPLEMENTATION |
sonnet-4-6 | 6000 | bypassPermissions |
null | null |
bypassPermissions is verdedigbaar omdat task/sprint-implementatie altijd in een geïsoleerde git-worktree draait (zie docs/runbooks/branch-and-commit.md). Voor productie-omgevingen kan Product.preferred_permission_mode = 'acceptEdits' als opt-in.
3. wait_for_job response uitbreiden
Huidig: wait_for_job returnt { job_id, kind, context }. Toevoegen: config: JobConfig.
Worker leest config en spawnt Claude Code subprocess met:
claude --model {config.model} \
--permission-mode {config.permission_mode} \
--thinking-budget {config.thinking_budget} \
[--max-turns {config.max_turns}] \
[--allowed-tools "{config.allowed_tools.join(',')}"]
Documentatie van vlaggen verwijst naar Claude Code model-config. Als een vlag (nog) niet bestaat in de huidige CLI: skippen + log-warning, niet hardcrashen.
4. Audit + cost-attribution
Bij job-completion (in update_job_status MCP-tool):
actual_thinking_tokensschrijven naarClaudeJob(al beschikbaar in Claude Code result-payload)- Bestaande
model_id-update behouden (cost-berekening viamodel_prices)
Token-stats-laag (lib/insights/token-stats.ts) uitbreiden:
- Aggregeren per kind (nu per dag/product) — feature-gate tot ST-N nodig
- Thinking-tokens apart tonen (andere prijs dan output-tokens)
5. Documentatie
- Nieuw: docs/runbooks/job-model-selection.md — de matrix + wanneer je override gebruikt
- CLAUDE.md Hardstop-bullet: "Model/mode per ClaudeJob: kind-default → product → task — zie runbook"
- Patterns quickref in CLAUDE.md: regel toevoegen voor
job-config.tsresolver-pattern
Voorgestelde PBI/story-breakdown
Voor de Scrum4Me-MCP create_pbi / create_story / create_task ronde na goedkeuring:
PBI: "Model + mode-selectie per ClaudeJob-kind"
| Story | Doel | Tasks (indicatief) |
|---|---|---|
| ST-1: Datamodel + migration | Velden op Product/Task/ClaudeJob | Schema wijzigen · migration · Prisma generate · seed/factories updaten |
| ST-2: Resolver in scrum4me-mcp | job-config.ts met kind-defaults + override-cascade |
Resolver-functie · unit tests per kind · export voor MCP-tools |
ST-3: wait_for_job integratie |
Config in response + snapshot in requested_* |
Tool-output uitbreiden · enqueue-laag snapshot · worker-flag-passing documenteren |
| ST-4: Audit + cost-attribution | actual_thinking_tokens opslaan + tonen |
update_job_status uitbreiden · token-stats per kind · admin/jobs UI-kolom |
| ST-5: Documentatie | Runbook + CLAUDE.md updates | runbook schrijven · CLAUDE.md hardstop · patterns-row |
ST-1 → ST-2 → ST-3 zijn de kritieke pad-stories. ST-4 en ST-5 kunnen parallel met ST-3.
Bestanden
| Bestand | Repo | Actie |
|---|---|---|
prisma/schema.prisma |
scrum4me | Wijzigen — 7 nieuwe velden |
prisma/migrations/<ts>_job_model_selection/ |
scrum4me | Nieuw — additive migration |
scrum4me-mcp/src/lib/job-config.ts |
scrum4me-mcp | Nieuw — resolver |
scrum4me-mcp/src/lib/job-config.test.ts |
scrum4me-mcp | Nieuw — unit tests per kind |
scrum4me-mcp/src/tools/wait-for-job.ts |
scrum4me-mcp | Wijzigen — config in response |
scrum4me-mcp/src/tools/update-job-status.ts |
scrum4me-mcp | Wijzigen — actual_thinking_tokens |
lib/insights/token-stats.ts |
scrum4me | Wijzigen — per-kind aggregatie + thinking-prijs |
actions/admin/jobs.ts + UI-kolom |
scrum4me | Wijzigen — model/mode tonen |
docs/runbooks/job-model-selection.md |
scrum4me | Nieuw — runbook |
CLAUDE.md |
scrum4me | Wijzigen — hardstop-bullet + patterns-row |
Verificatie
Per story:
- ST-1:
npm run verifyslaagt na schema-wijziging; migration runt clean op test-DB - ST-2: unit tests dekken alle 5 kinds × 4 cascade-niveaus (default/product/job/task)
- ST-3: integratietest: enqueue een
IDEA_GRILLmet product-override →wait_for_jobreturnt config met override toegepast - ST-4: end-to-end: run een dummy-job, verifieer dat
actual_thinking_tokensingevuld wordt en dat token-stats het kostbedrag correct rekent (input + output + thinking-input rate) - ST-5:
npm run docs:check-linksgroen; CLAUDE.md ≤ 150 regels
End-to-end-validatie van het geheel:
- Maak een nieuw idee →
IDEA_GRILL-job → controleer dat de worker met--permission-mode planen--thinking-budget 12000start - Approve het idee →
IDEA_MAKE_PLAN-job → controleer Opus-aanroep met thinking 24000 - Sprint starten →
SPRINT_IMPLEMENTATIONmetbypassPermissionsin worktree - Admin-jobs-pagina toont per job het gebruikte model + thinking-tokens
Vastgelegde beslissingen (review-uitkomst)
bypassPermissionsals default voor implement-kinds (TASK_IMPLEMENTATION, SPRINT_IMPLEMENTATION). Verdedigbaar door git-worktree-isolatie.Product.preferred_permission_modeblijft beschikbaar als opt-in voor productie-product- Opus-cost-controle = per-task via
Task.requires_opus-flag. Géén product-budget, géén automatische Opus-escalatie. Ad-hoc beslissing per taak PLAN_CHATruntime bevestigd: Claude Code CLI —wait_for_job(scrum4me-mcp/src/tools/wait-for-job.ts:386) selecteertIDEA_GRILL,IDEA_MAKE_PLANénPLAN_CHATuit dezelfde queue. Resolver past 1:1, geen aparte runtime-routewait_for_job-response: pure additief (geenprotocol_version-veld). Worker negeert onbekende velden veilig; mismatch is operationeel zichtbaar viamodel_idin token-stats. Geen multi-tenant fleet → geen versioning-overhead nodig
Bij goedkeuring: PBI + 5 stories + ~20 tasks aanmaken via mcp__scrum4me__create_pbi/story/task. Volgorde: ST-1 → ST-2 → ST-3 → (ST-4 ‖ ST-5).