feat(dispatch): model-claude-kind voor Claude-reviews als dispatchjob (M41 5b C1, T-1964) #101

Merged
janpeter merged 5 commits from feat/m41-model-claude into master 2026-10-03 10:17:47 +02:00
Owner

Samenvatting

M41 increment 5b, taak C1 (Scrum4Me T-1964, story ST-1619, plan §14): een model-claude-kind, zodat een QUEUE_REVIEW met runtime CLAUDE als afgeschermde dispatchjob kan draaien. Het kind authenticeert met een eigen claude setup-token, dat als operatorbron claude_oauth_token wordt aangeleverd.

  • Runtime van het kind. De supervisor leidt de runtime af uit het profiel en geeft hem mee in de broker-create, als runtime: 'CLAUDE'. De broker zet dan DISPATCH_CHILD_RUNTIME=CLAUDE. Zonder die variabele start het bestaande Codex-kind, met exact dezelfde container-args als nu.
  • Claude-adapter in lib/dispatch-child.ts.
    • Het token wordt gelezen met dezelfde regels als de Codex-sleutel: een gewoon bestand van hoogstens 4096 bytes. Het hoort niet bij source_artifacts en wordt uit de uitvoer geredigeerd.
    • Het token gaat alleen als CLAUDE_CODE_OAUTH_TOKEN naar de env van de CLI. Daarbij staan CLAUDE_CODE_DISABLE_NONESSENTIAL_TRAFFIC=1 en DISABLE_AUTOUPDATER=1 gezet.
    • De prompts zijn queue/review.md en queue/task.md.
    • Args: -p … --output-format stream-json --verbose --permission-mode acceptEdits --allowedTools Read,Glob,Grep,Bash,Write,Edit --add-dir /sources --add-dir /output, plus --model en --effort. Dat is geen bypassPermissions.
    • De foutteksten zijn runtime-neutraal.
  • Model en effort.
    • childModelFromConfig werkt nu ook voor CLAUDE. Een numeriek budget gaat via de gedeelde mapBudgetToEffort, dezelfde mapping als de gewone Claude-runner.
    • De effort-enum is uitgebreid met max, dat alleen voor Claude geldt.
    • De env heet DISPATCH_CLAUDE_MODEL en DISPATCH_CLAUDE_EFFORT.
    • Een modelconfig van de andere runtime wordt nooit doorgegeven.
  • Run-log. De spawn-args in de run-log hangen nu af van de runtime.
  • Dockerfile.dispatch.
    • Nieuwe stages model-claude en model-claude-probe, met dezelfde node-digest, uid 10001 en entrypoint als Codex.
    • CLAUDE_CODE_VERSION=2.1.287, met een pariteitstest tegen Dockerfile.
    • De deploymenttest staat claude alleen in die stages toe.
  • Operator-doc. Er is een sectie voor het Claude-kind: bron, env, egress api.anthropic.com, en één broker/egress/supervisor per slot.

Praktijkbewijs (C0, scrum4me-server, 2026-10-03)

Opzet:

  • CLI 2.1.287 als uid 10001, met --network none, een read-only rootfs en --cap-drop ALL.
  • De echte egressproxy, met als allowlist alleen api.anthropic.com, en dezelfde startEgressBridge als het kind.
  • Precies de flagset hierboven en het setup-token als bronbestand.

Uitkomst:

  • Exit 0; model claude-opus-5-5; 3 turns in 6,1 s.
  • /output/result.json bevat de regel uit de read-only /work.
  • De egresslog toont geen weigeringen; het token komt in geen enkele uitvoer voor.

Test

  • tsc -p tsconfig.dispatch.json is groen.
  • npm test: 1066 tests groen. Er falen 2 tests, in transcript-retention; die falen alleen op macOS en zijn bekend.
  • Red→green per gedrag: model (7/7), kind (35/35), run-log (15/15) en deployment (12/12).
  • De docker-integratieproef met het probe-image is niet gedraaid.

Uitrol

Pas bij C2 en op opdracht van JP. Deze PR raakt ook supervisorcode (prepare in lib/dispatch-runtime.ts). Bij de uitrol moet het supervisor-image dus ook opnieuw gebouwd worden, voor beide slots.

🤖 Generated with Claude Code

## Samenvatting M41 increment 5b, taak C1 (Scrum4Me T-1964, story ST-1619, plan §14): een **model-claude**-kind, zodat een `QUEUE_REVIEW` met runtime CLAUDE als afgeschermde dispatchjob kan draaien. Het kind authenticeert met een eigen `claude setup-token`, dat als operatorbron `claude_oauth_token` wordt aangeleverd. - **Runtime van het kind.** De supervisor leidt de runtime af uit het profiel en geeft hem mee in de broker-`create`, als `runtime: 'CLAUDE'`. De broker zet dan `DISPATCH_CHILD_RUNTIME=CLAUDE`. Zonder die variabele start het bestaande Codex-kind, met exact dezelfde container-args als nu. - **Claude-adapter in `lib/dispatch-child.ts`.** - Het token wordt gelezen met dezelfde regels als de Codex-sleutel: een gewoon bestand van hoogstens 4096 bytes. Het hoort niet bij `source_artifacts` en wordt uit de uitvoer geredigeerd. - Het token gaat **alleen** als `CLAUDE_CODE_OAUTH_TOKEN` naar de env van de CLI. Daarbij staan `CLAUDE_CODE_DISABLE_NONESSENTIAL_TRAFFIC=1` en `DISABLE_AUTOUPDATER=1` gezet. - De prompts zijn `queue/review.md` en `queue/task.md`. - Args: `-p … --output-format stream-json --verbose --permission-mode acceptEdits --allowedTools Read,Glob,Grep,Bash,Write,Edit --add-dir /sources --add-dir /output`, plus `--model` en `--effort`. Dat is geen `bypassPermissions`. - De foutteksten zijn runtime-neutraal. - **Model en effort.** - `childModelFromConfig` werkt nu ook voor CLAUDE. Een numeriek budget gaat via de gedeelde `mapBudgetToEffort`, dezelfde mapping als de gewone Claude-runner. - De effort-enum is uitgebreid met `max`, dat alleen voor Claude geldt. - De env heet `DISPATCH_CLAUDE_MODEL` en `DISPATCH_CLAUDE_EFFORT`. - Een modelconfig van de andere runtime wordt nooit doorgegeven. - **Run-log.** De spawn-args in de run-log hangen nu af van de runtime. - **`Dockerfile.dispatch`.** - Nieuwe stages `model-claude` en `model-claude-probe`, met dezelfde node-digest, uid 10001 en entrypoint als Codex. - `CLAUDE_CODE_VERSION=2.1.287`, met een pariteitstest tegen `Dockerfile`. - De deploymenttest staat `claude` alleen in die stages toe. - **Operator-doc.** Er is een sectie voor het Claude-kind: bron, env, egress `api.anthropic.com`, en één broker/egress/supervisor per slot. ## Praktijkbewijs (C0, scrum4me-server, 2026-10-03) Opzet: - CLI 2.1.287 als uid 10001, met `--network none`, een read-only rootfs en `--cap-drop ALL`. - De echte egressproxy, met als allowlist alleen `api.anthropic.com`, en dezelfde `startEgressBridge` als het kind. - Precies de flagset hierboven en het setup-token als bronbestand. Uitkomst: - Exit 0; model `claude-opus-5-5`; 3 turns in 6,1 s. - `/output/result.json` bevat de regel uit de read-only `/work`. - De egresslog toont geen weigeringen; het token komt in geen enkele uitvoer voor. ## Test - `tsc -p tsconfig.dispatch.json` is groen. - `npm test`: 1066 tests groen. Er falen 2 tests, in `transcript-retention`; die falen alleen op macOS en zijn bekend. - Red→green per gedrag: model (7/7), kind (35/35), run-log (15/15) en deployment (12/12). - De docker-integratieproef met het probe-image is niet gedraaid. ## Uitrol Pas bij C2 en op opdracht van JP. Deze PR raakt ook supervisorcode (`prepare` in `lib/dispatch-runtime.ts`). Bij de uitrol moet het supervisor-image dus ook opnieuw gebouwd worden, voor beide slots. 🤖 Generated with [Claude Code](https://claude.com/claude-code)
childModelFromConfig now resolves CLAUDE configs through the shared mapBudgetToEffort;
the runtime port passes the profile runtime to the broker create, which names
DISPATCH_CHILD_RUNTIME and the runtime-specific model env. Codex args are unchanged and
max never reaches a Codex child.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Runtime switch on DISPATCH_CHILD_RUNTIME: claude_oauth_token credential, queue/review.md
and task.md prompts, buildClaudeArgs/buildClaudeEnv, runtime-neutral failure text and a
claude spawn line in the run-log.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
docs(dispatch): Claude flag set and proxy proven live (M41 5b C0)
All checks were successful
CI / Compose config (pull_request) Successful in 7s
CI / Build-arg coverage (pull_request) Successful in 4s
CI / Docker build (pull_request) Successful in 1m17s
c02e14ce4c
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
s4m-codex-reviewer left a comment

REQUEST_CHANGES

  • error — lib/dispatch-child.ts:255 — Claude krijgt geen cwd mee. Het nieuwe image gebruikt WORKDIR /opt/dispatch (Dockerfile.dispatch:78) en de containerargs zetten geen werkdirectory. Daardoor start Claude in /opt/dispatch, terwijl de checkout in /work staat. Codex corrigeert dit via --cd /work; Claude heeft die correctie niet en voegt alleen /sources en /output toe. Relatieve repositorycommando's werken dus in de verkeerde directory en edits raken het read-only rootfs. Zet cwd: '/work' expliciet bij spawn en voeg een entrypoint-test toe die de cwd controleert.
  • warning — lib/dispatch-run-log.ts:100 — De logging kiest runtime/model uit modelConfig, maar de runtimeport kiest de runtime uit het profiel en laat een model van de andere runtime weg. Bij de ondersteunde mismatch kan de log daarom Codex/GPT vermelden terwijl Claude met CLI-default draaide. Gebruik dezelfde profielruntime en model-resolutie voor uitvoering en logging; test de mismatch ook in de run-log.

geen gekoppeld plan gevonden — beoordeeld op codekwaliteit + product-standaarden.

De adapter hergebruikt de bestaande credential-, egress- en resultaatvalidatie; unit-tests en operator-documentatie zijn uitgebreid. Productdocs architecture/overview en runbooks/agent-shared-tsx-env-and-redeploy zijn geraadpleegd. De onafhankelijke checkout is gecontroleerd op commit c02e14ce4c. Dispatch-typecheck en git diff --check slagen. Vitest kon hier niet starten doordat /tmp noexec is (native rolldown-binding); Docker is niet beschikbaar, dus de image-/egress-integratietests zijn niet uitgevoerd. De bestaande model-image-integratiescript bouwt bovendien alleen de Codex-probe; de nieuwe Claude-stub wordt daar nog niet aangeroepen.

# REQUEST_CHANGES - **error — lib/dispatch-child.ts:255** — Claude krijgt geen `cwd` mee. Het nieuwe image gebruikt `WORKDIR /opt/dispatch` (Dockerfile.dispatch:78) en de containerargs zetten geen werkdirectory. Daardoor start Claude in `/opt/dispatch`, terwijl de checkout in `/work` staat. Codex corrigeert dit via `--cd /work`; Claude heeft die correctie niet en voegt alleen `/sources` en `/output` toe. Relatieve repositorycommando's werken dus in de verkeerde directory en edits raken het read-only rootfs. Zet `cwd: '/work'` expliciet bij spawn en voeg een entrypoint-test toe die de cwd controleert. - **warning — lib/dispatch-run-log.ts:100** — De logging kiest runtime/model uit `modelConfig`, maar de runtimeport kiest de runtime uit het profiel en laat een model van de andere runtime weg. Bij de ondersteunde mismatch kan de log daarom Codex/GPT vermelden terwijl Claude met CLI-default draaide. Gebruik dezelfde profielruntime en model-resolutie voor uitvoering en logging; test de mismatch ook in de run-log. geen gekoppeld plan gevonden — beoordeeld op codekwaliteit + product-standaarden. De adapter hergebruikt de bestaande credential-, egress- en resultaatvalidatie; unit-tests en operator-documentatie zijn uitgebreid. Productdocs architecture/overview en runbooks/agent-shared-tsx-env-and-redeploy zijn geraadpleegd. De onafhankelijke checkout is gecontroleerd op commit c02e14ce4ca6afafd4c5845441e6e8e792005930. Dispatch-typecheck en git diff --check slagen. Vitest kon hier niet starten doordat /tmp noexec is (native rolldown-binding); Docker is niet beschikbaar, dus de image-/egress-integratietests zijn niet uitgevoerd. De bestaande model-image-integratiescript bouwt bovendien alleen de Codex-probe; de nieuwe Claude-stub wordt daar nog niet aangeroepen.
fix(dispatch): claude starts in /work; run-log follows the profile runtime (review #101)
All checks were successful
CI / Compose config (pull_request) Successful in 4s
CI / Build-arg coverage (pull_request) Successful in 7s
CI / Docker build (pull_request) Successful in 1m22s
5582a41c89
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Author
Owner

Beide punten van review 952 zijn verwerkt in 5582a41, test-first: de nieuwe tests faalden eerst en slagen nu.

  • error, cwd: het Claude-kind start nu in /work. De spawn krijgt cwd: '/work' uit de Claude-adapter (lib/dispatch-child.ts); bin/run-dispatch-child.ts geeft de opties ongewijzigd door aan spawn. De Codex-spawn blijft zoals hij was en krijgt geen cwd; Codex gebruikt --cd /work. Test: "starts claude in the /work checkout, and leaves the codex spawn as it was".
  • warning, run-log: writeRunLog krijgt nu de runtime van het profiel, met runtime in RunLogInput, uit config.profile.runtime in bin/run-dispatch-attempt.ts. Een modelconfig van de andere runtime wordt niet gelogd; dat is dezelfde regel als in de runtime-port. Test: "logs the profile runtime and the CLI default when the model config is of the other runtime".

tsc -p tsconfig.dispatch.json is groen. npm test geeft 1068 groen; daarnaast falen de 2 bekende macOS-tests in transcript-retention.

Opmerking over de integratieproef: het script draait de Claude-stub nog niet mee. De echte CLI is in C0 al op srv bewezen, met precies deze flags. Ik heb het script daarom niet uitgebreid.

Beide punten van review 952 zijn verwerkt in `5582a41`, test-first: de nieuwe tests faalden eerst en slagen nu. - **error, cwd:** het Claude-kind start nu in `/work`. De spawn krijgt `cwd: '/work'` uit de Claude-adapter (`lib/dispatch-child.ts`); `bin/run-dispatch-child.ts` geeft de opties ongewijzigd door aan `spawn`. De Codex-spawn blijft zoals hij was en krijgt geen cwd; Codex gebruikt `--cd /work`. Test: "starts claude in the /work checkout, and leaves the codex spawn as it was". - **warning, run-log:** `writeRunLog` krijgt nu de runtime van het profiel, met `runtime` in `RunLogInput`, uit `config.profile.runtime` in `bin/run-dispatch-attempt.ts`. Een modelconfig van de andere runtime wordt niet gelogd; dat is dezelfde regel als in de runtime-port. Test: "logs the profile runtime and the CLI default when the model config is of the other runtime". `tsc -p tsconfig.dispatch.json` is groen. `npm test` geeft 1068 groen; daarnaast falen de 2 bekende macOS-tests in `transcript-retention`. Opmerking over de integratieproef: het script draait de Claude-stub nog niet mee. De echte CLI is in C0 al op srv bewezen, met precies deze flags. Ik heb het script daarom niet uitgebreid.
s4m-codex-reviewer left a comment

COMMENT

geen gekoppeld plan gevonden — beoordeeld op codekwaliteit + product-standaarden.

Findings

  • warning — tests/dispatch-model-image/claude-stub.cjs:2: De nieuwe Claude-probe wordt niet aangeroepen door de testharness. tests/dispatch-model-image.integration.sh bouwt uitsluitend model-codex-probe; de bijbehorende TypeScript-harness test uitsluitend Codex. Koppel de Claude-probe aan een scenario dat runtimekeuze, OAuth-env, redactie en toegestaan/geweigerd CONNECT-verkeer controleert. De nieuwe image en stub alleen leveren nog geen uitvoerbare Claude-integratiedekking.

Beoordeling en verificatie

Beoordeeld op commit 5582a41c892715af9ecdb0075df3184c1de0df62. De runtime wordt vanuit het profiel doorgegeven; modelconfig van een andere runtime wordt geweigerd voor doorgifte. De Claude-token blijft buiten de payload en wordt uit transcript/resultaat geredigeerd. De wijziging hergebruikt de bestaande containerisolatie, gedeelde effort-mapping en resultaatvalidatie; de operator-documentatie beschrijft het nieuwe slot en de credentialbron. Geen blokkerend defect vastgesteld bij statische review.

Dispatch-typecheck geslaagd (node node_modules/typescript/bin/tsc -p tsconfig.dispatch.json). Testsuite niet uitgevoerd: Vitest faalt vóór testcollectie doordat /tmp met noexec is gemount en de native Rolldown-binding niet kan laden. Docker ontbreekt, dus image-/egress-integratietests konden evenmin draaien. De in code/docs genoemde live C0-proef is niet onafhankelijk herhaald. Door deze verificatiebeperking en de integratiedekkingsopmerking is het verdict COMMENT.

# COMMENT geen gekoppeld plan gevonden — beoordeeld op codekwaliteit + product-standaarden. ## Findings - **warning — tests/dispatch-model-image/claude-stub.cjs:2:** De nieuwe Claude-probe wordt niet aangeroepen door de testharness. `tests/dispatch-model-image.integration.sh` bouwt uitsluitend `model-codex-probe`; de bijbehorende TypeScript-harness test uitsluitend Codex. Koppel de Claude-probe aan een scenario dat runtimekeuze, OAuth-env, redactie en toegestaan/geweigerd CONNECT-verkeer controleert. De nieuwe image en stub alleen leveren nog geen uitvoerbare Claude-integratiedekking. ## Beoordeling en verificatie Beoordeeld op commit `5582a41c892715af9ecdb0075df3184c1de0df62`. De runtime wordt vanuit het profiel doorgegeven; modelconfig van een andere runtime wordt geweigerd voor doorgifte. De Claude-token blijft buiten de payload en wordt uit transcript/resultaat geredigeerd. De wijziging hergebruikt de bestaande containerisolatie, gedeelde effort-mapping en resultaatvalidatie; de operator-documentatie beschrijft het nieuwe slot en de credentialbron. Geen blokkerend defect vastgesteld bij statische review. Dispatch-typecheck geslaagd (`node node_modules/typescript/bin/tsc -p tsconfig.dispatch.json`). Testsuite niet uitgevoerd: Vitest faalt vóór testcollectie doordat `/tmp` met `noexec` is gemount en de native Rolldown-binding niet kan laden. Docker ontbreekt, dus image-/egress-integratietests konden evenmin draaien. De in code/docs genoemde live C0-proef is niet onafhankelijk herhaald. Door deze verificatiebeperking en de integratiedekkingsopmerking is het verdict `COMMENT`.
janpeter merged commit aef66fdd27 into master 2026-10-03 10:17:47 +02:00
Sign in to join this conversation.
No reviewers
No labels
severity/s3
No milestone
No project
No assignees
2 participants
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set.

Reference
janpeter/scrum4me-docker!101
No description provided.