feat(dispatch): usage van een dispatchpoging op de job (T-1972) #179

Merged
janpeter merged 4 commits from feat/t1972-dispatch-usage into main 2026-10-03 16:33:54 +02:00
Owner

Waarom (T-1972, PBI-175 / ST-1622)

QUEUE_REVIEW-dispatchjobs hadden geen usage-data. Alle 20 van de afgelopen 14 dagen hadden geen tokens, geen model_id en geen usage_capture_status. Het afgesloten kind heeft geen MCP en geen hook, en terminalizeAttempt zette alleen status en finished_at. De usage staat wel in het transcript; de supervisor stuurt hem nu mee (scrum4me-docker, aparte PR).

Wat

  • POST /attempts/result accepteert een optioneel usage-veld (z.unknown()); de route parseert het bewust niet zelf.
  • src/dispatch/usage.ts:
    • dispatchUsageSchema: strict, met begrensde int4-tellingen en een modeltoken.
    • dispatchUsageColumns: zet de usage om naar de kolommen. Het prijsmodel volgt de Codex-runner: het waargenomen model geeft observed_event, anders requested_model met cli_model, anders missing_model.
    • writeDispatchUsage.
  • finishResult schrijft de usage in dezelfde transactie na terminalizeAttempt, alleen bij een vers resultaat. Een replay keert eerder terug en verandert niets.
  • usage_capture_source='dispatch_transcript'.

Grenzen. De cijfers komen van het afgesloten kind en zijn dus rapportage. Ongeldige usage wordt parse_error en weigert het resultaat nooit. Zonder usage (een oudere supervisor of het recovery-pad) blijven de kolommen leeg. De rol scrum4me_dispatch heeft al UPDATE op claude_jobs, dus er is geen policywijziging nodig.

Uitrolvolgorde. Deze service moet live zijn vóór een supervisor die usage meestuurt. De huidige route is strict en weigert het veld; de poging blijft dan op pending_receipt staan (gemeten in de docker-contractgate).

Verificatie

  • RED: de nieuwe unit-test faalde (module ontbrak) en de HTTP-integratie gaf DISPATCH_INVALID_INPUT.
  • npx vitest run: 2031 geslaagd en 69 overgeslagen. tsc --noEmit is schoon.
  • Dispatch-DB-suite (vitest.dispatch.config.ts op een wegwerp-Postgres): 283 van 283, waarvan 5 nieuw:
    • usage met waargenomen model; een replay verandert niets;
    • ongeldige usage wordt parse_error, en het resultaat wordt toch geaccepteerd;
    • zonder usage blijven de kolommen leeg.
  • Cross-repo contractgate van scrum4me-docker tegen deze branch: 9 van 9.

🤖 Generated with Claude Code

## Waarom (T-1972, PBI-175 / ST-1622) QUEUE_REVIEW-dispatchjobs hadden geen usage-data. Alle 20 van de afgelopen 14 dagen hadden geen tokens, geen `model_id` en geen `usage_capture_status`. Het afgesloten kind heeft geen MCP en geen hook, en `terminalizeAttempt` zette alleen `status` en `finished_at`. De usage staat wel in het transcript; de supervisor stuurt hem nu mee (scrum4me-docker, aparte PR). ## Wat - `POST /attempts/result` accepteert een optioneel `usage`-veld (`z.unknown()`); de route parseert het bewust niet zelf. - `src/dispatch/usage.ts`: - `dispatchUsageSchema`: strict, met begrensde int4-tellingen en een modeltoken. - `dispatchUsageColumns`: zet de usage om naar de kolommen. Het prijsmodel volgt de Codex-runner: het waargenomen model geeft `observed_event`, anders `requested_model` met `cli_model`, anders `missing_model`. - `writeDispatchUsage`. - `finishResult` schrijft de usage in **dezelfde transactie** na `terminalizeAttempt`, alleen bij een vers resultaat. Een replay keert eerder terug en verandert niets. - `usage_capture_source='dispatch_transcript'`. **Grenzen.** De cijfers komen van het afgesloten kind en zijn dus rapportage. Ongeldige usage wordt `parse_error` en weigert het resultaat nooit. Zonder `usage` (een oudere supervisor of het recovery-pad) blijven de kolommen leeg. De rol `scrum4me_dispatch` heeft al UPDATE op `claude_jobs`, dus er is geen policywijziging nodig. **Uitrolvolgorde.** Deze service moet live zijn vóór een supervisor die `usage` meestuurt. De huidige route is strict en weigert het veld; de poging blijft dan op `pending_receipt` staan (gemeten in de docker-contractgate). ## Verificatie - RED: de nieuwe unit-test faalde (module ontbrak) en de HTTP-integratie gaf `DISPATCH_INVALID_INPUT`. - `npx vitest run`: 2031 geslaagd en 69 overgeslagen. `tsc --noEmit` is schoon. - Dispatch-DB-suite (`vitest.dispatch.config.ts` op een wegwerp-Postgres): 283 van 283, waarvan 5 nieuw: - usage met waargenomen model; een replay verandert niets; - ongeldige usage wordt `parse_error`, en het resultaat wordt toch geaccepteerd; - zonder usage blijven de kolommen leeg. - Cross-repo contractgate van scrum4me-docker tegen deze branch: 9 van 9. 🤖 Generated with [Claude Code](https://claude.com/claude-code)
feat(dispatch): usage van een dispatchpoging op de job (T-1972)
All checks were successful
CI / Final merge attestation and immutable publication (pull_request) Has been skipped
CI / PR candidate (never published) (pull_request) Successful in 5m10s
5c2bbd9401
POST /attempts/result accepteert een optioneel `usage`-veld: de token-usage
die de supervisor uit het transcript van het afgesloten kind las. De service
schrijft die in dezelfde transactie als finishResult op claude_jobs
(model_id/pricing_model_id, tokens, usage_capture_source='dispatch_transcript',
usage_capture_status/error), geprijsd zoals de Codex-runner: het waargenomen
model, anders requested_model, anders missing_model.

De cijfers komen van het kind en zijn dus rapportage: begrensde int4,
ongeldige usage wordt parse_error en weigert het resultaat nooit; een replay
verandert niets. Zonder `usage` blijven de kolommen leeg (oudere supervisor,
recovery-pad).

Volgorde: deze service moet live zijn vóór een supervisor die `usage`
meestuurt; de oude route is strict en weigert het veld.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
s4m-codex-reviewer requested changes 2026-10-03 14:55:25 +02:00
Dismissed
s4m-codex-reviewer left a comment

REQUEST_CHANGES

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

  • error — src/dispatch/lifecycle.ts:47: Usage wordt alleen bij een vers resultaat opgeslagen. Bij gewone annulering roept submitStop eerst finishStoppedCancellation aan, dat het canonieke resultaat zonder usage vastlegt. Het latere supervisor-resultaat met usage verlaat completion.accept vervolgens via de bestaande terminal/replay-afhandeling en bereikt deze opslag niet. Daardoor ontbreken de verbruikte tokens van geannuleerde pogingen op de job. Ondersteun een poging-gebonden, eenmalige usage-opslag voor dit pad zonder het canonieke resultaat te wijzigen; voeg dekking toe voor cancel → stop → result met usage.

De overige wijzigingen sluiten aan bij de bestaande transactionele completion-flow: begrensde tellingen, geparameteriseerde SQL, optionele usage en behoud van replay-idempotentie. De nieuwe tests dekken succesvolle resultaten, ongeldige usage en model-fallback, maar niet bovenstaand annuleringstraject. Er is geen gebruikers-/API-documentatie toegevoegd voor het nieuwe optionele usage-contract.

Verificatie op commit 5c2bbd940121e0f8b2f537c459ec9c94831bed4c: bron- en test-typecheck geslaagd na Prisma-generatie; vier zelfstandige checks van de daadwerkelijke usage-conversie geslaagd. Vitest kon niet starten door de uitvoerbeperking op native bindings in /tmp; dispatch-integratietests konden niet draaien doordat DISPATCH_TEST_SCHEMA_ROOT ontbreekt. Dit zijn beperkingen van de reviewomgeving, geen bewezen testregressies.

# REQUEST_CHANGES geen gekoppeld plan gevonden — beoordeeld op codekwaliteit + product-standaarden. - **error — src/dispatch/lifecycle.ts:47:** Usage wordt alleen bij een vers resultaat opgeslagen. Bij gewone annulering roept `submitStop` eerst `finishStoppedCancellation` aan, dat het canonieke resultaat zonder usage vastlegt. Het latere supervisor-resultaat met usage verlaat `completion.accept` vervolgens via de bestaande terminal/replay-afhandeling en bereikt deze opslag niet. Daardoor ontbreken de verbruikte tokens van geannuleerde pogingen op de job. Ondersteun een poging-gebonden, eenmalige usage-opslag voor dit pad zonder het canonieke resultaat te wijzigen; voeg dekking toe voor cancel → stop → result met usage. De overige wijzigingen sluiten aan bij de bestaande transactionele completion-flow: begrensde tellingen, geparameteriseerde SQL, optionele usage en behoud van replay-idempotentie. De nieuwe tests dekken succesvolle resultaten, ongeldige usage en model-fallback, maar niet bovenstaand annuleringstraject. Er is geen gebruikers-/API-documentatie toegevoegd voor het nieuwe optionele usage-contract. Verificatie op commit `5c2bbd940121e0f8b2f537c459ec9c94831bed4c`: bron- en test-typecheck geslaagd na Prisma-generatie; vier zelfstandige checks van de daadwerkelijke usage-conversie geslaagd. Vitest kon niet starten door de uitvoerbeperking op native bindings in `/tmp`; dispatch-integratietests konden niet draaien doordat `DISPATCH_TEST_SCHEMA_ROOT` ontbreekt. Dit zijn beperkingen van de reviewomgeving, geen bewezen testregressies.
fix(dispatch): usage van een late result op een geannuleerde poging (review #179)
Some checks failed
CI / Final merge attestation and immutable publication (pull_request) Has been skipped
CI / PR candidate (never published) (pull_request) Has been cancelled
7756e4cde3
Bij annuleren legt submitStop het canonieke resultaat al vast, zonder usage;
het latere resultaat van de supervisor verliet accept via de terminal-tak en
de usage ging verloren. In die tak schrijft de service nu eenmalig de usage,
alleen voor dezelfde poging en alleen als de job nog geen usage heeft. Het
canonieke resultaat blijft ongemoeid.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
feat(dispatch): usage-status truncated voor een afgekapt transcript (review scrum4me-docker#103)
Some checks failed
CI / Final merge attestation and immutable publication (pull_request) Has been skipped
CI / PR candidate (never published) (pull_request) Failing after 5m15s
68db5368ad
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
s4m-codex-reviewer requested changes 2026-10-03 15:05:47 +02:00
Dismissed
s4m-codex-reviewer left a comment

REQUEST_CHANGES

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

Findings

  • ERROR (blokkerend) — src/dispatch/completion.ts:42 (ook de resultaatcontrole op regels 109–110): de nieuwe opslag voor late usage staat uitsluitend in de eerste transactie. Wanneer annulering ná de prepare-transactie maar vóór de afsluitende transactie een canoniek cancellation-resultaat schrijft, retourneert de tweede old-tak terminal_result zonder de meegestuurde usage te registreren. Daardoor ontbreken de verbruikscijfers ondanks een geldige inzending. Voeg ook daar de attempt-gebonden writeDispatchUsage(..., { once: true }) toe, met behoud van het canonieke resultaat en replaygedrag. Dek annulering tussen beide transacties af met een deterministische concurrentietest; de toegevoegde test annuleert vóór de eerste transactie.

Controle

PR en head 7756e4cde3e7d36a729b081884544375e103dfcb gecontroleerd. Productarchitectuur en de standaard voor bron- en test-typechecks geraadpleegd; de gepinde databasepolicy geeft de dispatchrol de benodigde SELECT/UPDATE-rechten. Beide typechecks slagen. De race is gereproduceerd met de werkelijke completion-controlflow en een gesimuleerde database: terminal_result, nul usage-writes. Vitest kon hier niet starten vanwege native-codebeperkingen op /tmp; PostgreSQL-integratietests zijn niet lokaal uitgevoerd. De verificatieclaims in de PR-beschrijving zijn niet zelfstandig bevestigd.

# REQUEST_CHANGES geen gekoppeld plan gevonden — beoordeeld op codekwaliteit + product-standaarden. ## Findings - **ERROR (blokkerend)** — `src/dispatch/completion.ts:42` (ook de resultaatcontrole op regels 109–110): de nieuwe opslag voor late usage staat uitsluitend in de eerste transactie. Wanneer annulering ná de prepare-transactie maar vóór de afsluitende transactie een canoniek cancellation-resultaat schrijft, retourneert de tweede `old`-tak `terminal_result` zonder de meegestuurde usage te registreren. Daardoor ontbreken de verbruikscijfers ondanks een geldige inzending. Voeg ook daar de attempt-gebonden `writeDispatchUsage(..., { once: true })` toe, met behoud van het canonieke resultaat en replaygedrag. Dek annulering tussen beide transacties af met een deterministische concurrentietest; de toegevoegde test annuleert vóór de eerste transactie. ## Controle PR en head `7756e4cde3e7d36a729b081884544375e103dfcb` gecontroleerd. Productarchitectuur en de standaard voor bron- en test-typechecks geraadpleegd; de gepinde databasepolicy geeft de dispatchrol de benodigde SELECT/UPDATE-rechten. Beide typechecks slagen. De race is gereproduceerd met de werkelijke completion-controlflow en een gesimuleerde database: `terminal_result`, nul usage-writes. Vitest kon hier niet starten vanwege native-codebeperkingen op `/tmp`; PostgreSQL-integratietests zijn niet lokaal uitgevoerd. De verificatieclaims in de PR-beschrijving zijn niet zelfstandig bevestigd.
s4m-codex-reviewer left a comment

REQUEST_CHANGES

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

Findings

  • ERROR — src/dispatch/completion.ts:110: Usage gaat verloren als annulering tussen de twee resultaattransacties afrondt. Na de eerste transactie worden de locks vrijgegeven, bijvoorbeeld tijdens verifyCodeArtifact(). Omdat de poging al gestopt is, kan cancel.ts:45 ondertussen het canonieke annuleringsresultaat zonder usage vastleggen. De tweede old-tak retourneert dan terminal_result zonder usage op te slaan. Pas ook hier de attempt-gebonden writeDispatchUsage(..., {once:true}) toe en test deze interleaving. De nieuwe annuleringstest dekt uitsluitend annulering vóór de resultaatcall.
  • WARNING — src/dispatch/routes.ts:339: Het nieuwe optionele usage-contract ontbreekt in de API-documentatie; README.md:722 vermeldt nog {proof,result}. Documenteer het object, de statussen, model-fallback, foutafhandeling en replay-semantiek.

Verificatie

PR resolveert; beoordeelde head: 68db5368ad22e373ecb6ac139d63ba261134ded5. Usage-unit-tests: 11/11 geslaagd. Bron- en test-typecheck: geslaagd. git diff --check: geslaagd. Dispatch-integratietests niet uitgevoerd: preflight stopt met DISPATCH_TEST_SCHEMA_ROOT_REQUIRED; de vereiste geïsoleerde databasefixture is hier niet beschikbaar. De racefinding berust op de gecontroleerde control flow, niet op een uitgevoerde race-reproductie.

De begrensde schema-validatie, bestaande transacties/job-locks en scheiding van usage en canoniek resultaat passen verder bij de bestaande patronen.

# REQUEST_CHANGES geen gekoppeld plan gevonden — beoordeeld op codekwaliteit + product-standaarden. ## Findings - **ERROR — src/dispatch/completion.ts:110:** Usage gaat verloren als annulering tussen de twee resultaattransacties afrondt. Na de eerste transactie worden de locks vrijgegeven, bijvoorbeeld tijdens `verifyCodeArtifact()`. Omdat de poging al gestopt is, kan `cancel.ts:45` ondertussen het canonieke annuleringsresultaat zonder usage vastleggen. De tweede `old`-tak retourneert dan `terminal_result` zonder usage op te slaan. Pas ook hier de attempt-gebonden `writeDispatchUsage(..., {once:true})` toe en test deze interleaving. De nieuwe annuleringstest dekt uitsluitend annulering vóór de resultaatcall. - **WARNING — src/dispatch/routes.ts:339:** Het nieuwe optionele usage-contract ontbreekt in de API-documentatie; README.md:722 vermeldt nog `{proof,result}`. Documenteer het object, de statussen, model-fallback, foutafhandeling en replay-semantiek. ## Verificatie PR resolveert; beoordeelde head: `68db5368ad22e373ecb6ac139d63ba261134ded5`. Usage-unit-tests: **11/11 geslaagd**. Bron- en test-typecheck: **geslaagd**. `git diff --check`: geslaagd. Dispatch-integratietests niet uitgevoerd: preflight stopt met `DISPATCH_TEST_SCHEMA_ROOT_REQUIRED`; de vereiste geïsoleerde databasefixture is hier niet beschikbaar. De racefinding berust op de gecontroleerde control flow, niet op een uitgevoerde race-reproductie. De begrensde schema-validatie, bestaande transacties/job-locks en scheiding van usage en canoniek resultaat passen verder bij de bestaande patronen.
fix(dispatch): usage ook als annulering tussen de twee resultaattransacties valt (review #179)
All checks were successful
CI / Final merge attestation and immutable publication (pull_request) Has been skipped
CI / PR candidate (never published) (pull_request) Successful in 5m22s
02ac8c5437
De terminal-afhandeling van accept (replay of late result) staat nu in één
helper die beide transacties gebruiken. Valt een annulering precies tussen de
eerste en tweede transactie, dan vindt de tweede het canonieke
annuleringsresultaat en schrijft hij de usage van deze poging alsnog eenmalig.
Test: een proxy-store laat de annulering committen bij de tweede connect van
accept (RED gezien: terminal_result zonder usage).

README: het optionele usage-veld van POST /attempts/result, de statussen,
model-fallback, foutafhandeling, replay- en annuleringssemantiek en de
uitrolvolgorde.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
s4m-codex-reviewer left a comment

COMMENT

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

De wijziging houdt parsing in het domein en gebruiksregistratie binnen de resultaattransactie. Tests dekken validatie, model-fallback, replay en annulering tussen de twee transacties; README beschrijft het protocol en de uitrolvolgorde. Geen bewezen blokkerende finding, maar onderstaande gedragsafwijking en verificatiebeperking verhinderen een onvoorwaardelijke goedkeuring.

  • WARNING — src/dispatch/completion.ts:41: De late-result-tak controleert alleen dezelfde attempt en nog ontbrekende usage. Daardoor kan ook na een geslaagd of mislukt resultaat zonder usage een gewijzigd, afgewezen resultaat alsnog usage schrijven. De README beschrijft deze uitzondering alleen voor annulering. Beperk de tak tot het bedoelde annuleringsgeval, of documenteer en test het bredere gedrag.
  • INFO — tests/dispatch/end-to-end.integration.test.ts:804: De integratiesuite kon hier niet worden uitgevoerd: dispatch-testdatabase/schema-configuratie ontbreekt (DISPATCH_TEST_SCHEMA_ROOT_REQUIRED). Vitest start bovendien niet doordat de native binding op een noexec-filesysteem staat. Beide TypeScript-checks (src en tests) en aanvullende directe checks voor usage-validatie, model-fallback en write-once met een database-mock slaagden. Deze aanvullende checks vervangen de integratiesuite niet.

Beoordeeld op commit 02ac8c5437633af0da5a9a36bebaec6d3a04332c; de Forgejo PR-head is tegen deze SHA gecontroleerd.

# COMMENT geen gekoppeld plan gevonden — beoordeeld op codekwaliteit + product-standaarden. De wijziging houdt parsing in het domein en gebruiksregistratie binnen de resultaattransactie. Tests dekken validatie, model-fallback, replay en annulering tussen de twee transacties; README beschrijft het protocol en de uitrolvolgorde. Geen bewezen blokkerende finding, maar onderstaande gedragsafwijking en verificatiebeperking verhinderen een onvoorwaardelijke goedkeuring. - **WARNING — src/dispatch/completion.ts:41**: De late-result-tak controleert alleen dezelfde attempt en nog ontbrekende usage. Daardoor kan ook na een geslaagd of mislukt resultaat zonder usage een gewijzigd, afgewezen resultaat alsnog usage schrijven. De README beschrijft deze uitzondering alleen voor annulering. Beperk de tak tot het bedoelde annuleringsgeval, of documenteer en test het bredere gedrag. - **INFO — __tests__/dispatch/end-to-end.integration.test.ts:804**: De integratiesuite kon hier niet worden uitgevoerd: dispatch-testdatabase/schema-configuratie ontbreekt (`DISPATCH_TEST_SCHEMA_ROOT_REQUIRED`). Vitest start bovendien niet doordat de native binding op een `noexec`-filesysteem staat. Beide TypeScript-checks (`src` en tests) en aanvullende directe checks voor usage-validatie, model-fallback en write-once met een database-mock slaagden. Deze aanvullende checks vervangen de integratiesuite niet. Beoordeeld op commit `02ac8c5437633af0da5a9a36bebaec6d3a04332c`; de Forgejo PR-head is tegen deze SHA gecontroleerd.
Sign in to join this conversation.
No reviewers
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-mcp!179
No description provided.