feat(IDEA-213): centrale dispatcher voor managed queue dispatch (ST-1590) #144
No reviewers
Labels
No labels
severity/s2
severity/s3
severity/s4
No milestone
No project
No assignees
2 participants
Notifications
Due date
No due date set.
Dependencies
No dependencies set.
Reference
janpeter/scrum4me-mcp!144
Loading…
Add table
Add a link
Reference in a new issue
No description provided.
Delete branch "feat/idea-213-dispatch"
Deleting a branch is permanent. Although the deleted branch may continue to exist for a short time before it actually gets removed, it CANNOT be undone in most cases. Continue?
Draft — niet mergen. Geopend om CI te laten draaien; IP-10 t/m IP-14 van ST-1590 zijn nog niet uitgevoerd. Hoort bij Scrum4Me #251; de zeven
feat/idea-213-dispatch-branches horen bij elkaar.Inhoud
De centrale dispatcher in
src/dispatch/(IP-03 t/m IP-09): geïsoleerd DB-testharnas, geauthenticeerde intake, capaciteitsselectie met atomische reservering, claim/start-binding met start-permit, bronpinning en artefacten, resultaatverificatie, publicatie en herstel. Het directe 'Naar watcher'-queuepad is onaangeraakt.Review-fixes (code-review 2026-09-20)
12651e6— operator-herstel kan een geclaimde maar nooit gestarte poging sluiten (begrensd door het claim-moment).74d144b— verificatiefout wordt een receipt; reconciler vangt per rij en roteert opupdated_at.1359dee— geauditeerde operator-resolutie voor een publicatie die voorgoed UNKNOWN blijft; zendt nooit.ef13273— race-test accepteert beide geldige weigeringen (faalde ~1 op 3).Verificatie (lokaal)
npm run test:dispatch: 16 files / 187 tests groen tegen postgres:17, schema-root gepind op Scrum4Me6dc581da.npm test: 1705 groen;tsc --noEmitschoon.DISPATCH_TEST_SCHEMA_ROOT; of de bestaande workflow die draait is niet nagegaan.Commits
745eecetest(IDEA-213): add isolated dispatch database and role harness1b1e299fix(IDEA-213): harden dispatch source pin and cleanup99a0a34feat(IDEA-213): authenticate and persist automatic queue requests19d67adfeat(IDEA-213): reserve eligible dispatch capacity and enqueue atomicallyb8d2ffdfix(IDEA-213): exclude managed-only workers from ordinary tier priority3a3b41efeat(IDEA-213): bind managed job attempts and start authority554fb62fix(IDEA-213): retain Task occupancy and expire uncertain attemptsda92349test(IDEA-213): refuse occupied Task execution effectsfe45e48feat(IDEA-213): bind managed runtime liveness and child capabilities4333a22feat(IDEA-213): pin execution sources and preserve code artifacts5cf2ef0fix(IDEA-213): preserve exact Git artifact data150029dfeat(IDEA-213): accept verified results and audit uncertain recoveryc41cf1cfix(IDEA-213): share bounded control reserve with operator recovery8c395aafix(IDEA-213): correct publication pooling stop expiry and admin cancellation12651e6fix(IDEA-213): let operator recovery close an attempt that never started74d144bfix(IDEA-213): keep one bad publication from wedging the reconcileref13273test(IDEA-213): accept either valid refusal in the enqueue race1359deefeat(IDEA-213): let an operator settle a publication nobody can reconcile🤖 Generated with Claude Code
janpeter referenced this pull request2026-09-20 10:21:23 +02:00
Four domain functions existed with a tested authority model and no route in front of them. This wires them, and rewrites nothing. POST /attempts/result now answers with `reason` and `canonical_result` beside the existing `status`/`result_id`, so a supervisor completes on what the service holds rather than on what it sent. PUT /attempts/collected/:key is the route `stageCollectedArtifact` was written for: original-supervisor authority proved by the historical start binding, valid only after this supervisor's own stop was accepted, which is exactly when PUT /attempts/artifacts/:key refuses by design. `authorizeArtifactAttempt` is untouched. POST /attempts/recovery/{lookup,stop,result} put NonLaunchRecoveryPort on the wire. Same authenticated original supervisor, same historical binding, no AttemptProof and no execution authority. This is not /requests/:id/recover, which is the operator recovery role. GET /agent/sources/:key and PUT /agent/outputs/:key mount `createAgentGateway` with the authority its module prescribes: the child calls the service directly holding one bounded, attempt-scoped capability and no dispatch identity at all. A bearer or assertion alongside it is refused rather than ignored, and the gateway re-derives full database authority on every call. The capability is minted by the service at POST /attempts/start and returned beside the permit, because the supervisor is the only party that can place it in the container. Without DISPATCH_AGENT_OUTPUT_KEY the two routes do not exist. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>WIP: feat(IDEA-213): centrale dispatcher voor managed queue dispatch (ST-1590)to feat(IDEA-213): centrale dispatcher voor managed queue dispatch (ST-1590)Verdict: REQUEST_CHANGES
geen gekoppeld plan gevonden — beoordeeld op codekwaliteit + product-standaarden.
Findings
ERROR
.env.example:50/README.md:533— De runtime vereist inmiddels ookDISPATCH_START_PERMIT_KEY_IDvoordatexecutorwordt geconfigureerd (src/dispatch/server.ts:103-114), maar zowel de voorbeeld-env als de environment-tabel documenteren alleenDISPATCH_START_PERMIT_PRIVATE_KEY. Een operator die de README/.env.example volgt krijgt dus geen/attempts/*executor-routes, ondanks geldige credential keys en private key. Dit maakt de nieuwe managed dispatch-uitrol niet werkend volgens de meegeleverde configuratie-instructies. Voeg de key-id expliciet toe aan.env.exampleen README, inclusief dezelfde validatie/rotatieverwachting als de code.WARNING
.env.example:50/README.md:533— De code heeft ook aparte source-manifest signing env vars (DISPATCH_SOURCE_MANIFEST_PRIVATE_KEYenDISPATCH_SOURCE_MANIFEST_KEY_IDinsrc/dispatch/server.ts:106-110) waarmee/attempts/sources/manifestbeschikbaar wordt, maar die zijn nergens in de env-matrix opgenomen. Omdat de README wel prepared source manifests beschrijft, is dit een uitrol-blinde vlek: prepared-source flows kunnen zonder zichtbare configuratie gedeeltelijk beschikbaar lijken maar de manifest-route missen.Checks
node node_modules/typescript/bin/tsc --noEmitna submodule init + Prisma generate: groen.node node_modules/typescript/bin/tsc --noEmit -p tsconfig.type-tests.json: groen.rolldownbinding-load probleem in deze tijdelijke omgeving; niet als PR-finding gebruikt.REQUEST_CHANGES
Geen gekoppeld plan gevonden — beoordeeld op codekwaliteit + product-standaarden.
Findings
src/dispatch/server.ts:45/.env.example:36/README.md:540: de productie-entrypoint vereist naastDISPATCH_START_PERMIT_PRIVATE_KEYookDISPATCH_START_PERMIT_KEY_IDvoordatexecutorwordt opgebouwd, en gebruikt daarnaastDISPATCH_SOURCE_MANIFEST_PRIVATE_KEY,DISPATCH_SOURCE_MANIFEST_KEY_IDenDISPATCH_AGENT_OUTPUT_KEYvoor de manifest- en child-gateway routes. Die variabelen ontbreken in.env.example, en de README environment table documenteert alleen de private start-permit key en agent-output key, niet de verplichte start-permit key id of de manifest key/id. Een operator die de meegeleverde configuratie volgt krijgt daardoor een service waarbij/executors/*,/attempts/*en/of/attempts/sources/manifestals niet-geconfigureerd/404 blijven, terwijl de docs suggereren dat de private key + credential keys voldoende zijn. Dit blokkeert rollout van de managed queue dispatcher omdat de centrale dispatch wel intake/selectie kan draaien, maar workers geen start/manifest-contract kunnen krijgen.Verdict
REQUEST_CHANGES — de nieuwe dispatcher is uitgebreid getest en de architectuur sluit grotendeels aan bij de productdocs, maar de runtime-configuratie is niet compleet gedocumenteerd voor verplichte routes. Werk de env example en README environment table bij met alle daadwerkelijk gelezen dispatch-vars en hun required/optional semantics voordat dit veilig te deployen is.
Verdict: COMMENT
Geen gekoppeld plan gevonden — beoordeeld op codekwaliteit + product-standaarden.
Findings:
README.md:555/.env.example— De README documenteertDISPATCH_AGENT_OUTPUT_KEYals door de dispatch service gelezen configuratie, maar.env.examplebevat geen voorbeeldregel voor deze variabele. Daardoor is de operatorconfig niet volledig reproduceerbaar vanuit de voorbeeld-env, terwijl de rest van de nieuwe dispatch-config daar juist uitgebreid is vastgelegd.README.md:701— De nieuwe README-sectie zegt nog dat de start permit geen key id draagt en daardoor niet in-place roteerbaar is. De code en tests in deze PR introduceren juistDISPATCH_START_PERMIT_KEY_ID,startPermitKeyIden v2-permitverificatie metkid. Dit maakt de operationele documentatie intern tegenstrijdig.README.md:699— De documentatie noteert dat praktische acceptance tegen een live dispatch service nog niet heeft gelopen. Dat is geen code-blocker op zichzelf, maar bij deze grote dispatcher-introductie blijft het een expliciete rollout/test-gap om vóór productiegebruik af te sluiten.Geen blocking/error-severity findings gevonden in de beoordeelde diff. Omdat de PR groot is, geen gekoppeld plan heeft en de docs nog inconsistenties/test-gap noemen, kies ik safe-default voor
COMMENTin plaats vanAPPROVED.Verdict: COMMENT
Geen gekoppeld plan gevonden — beoordeeld op codekwaliteit + product-standaarden.
Findings
.env.example:63: de README claimt dat de environment-tabel alle variabelen bevat die de dispatch-code leest en documenteertDISPATCH_AGENT_OUTPUT_KEY, ensrc/dispatch/server.tsleest die variabele ook om de/agent/*gateway te activeren. In.env.exampleontbreekt deze variabele echter in het dispatch-blok. Dat maakt lokale/operator-configuratie onvolledig voor deployments die child output capabilities willen inschakelen.Samenvatting
De PR introduceert een grote, goed afgeschermde centrale dispatch-service met expliciete off-by-default configuratie, beperkte route-activatie op basis van aanwezige keys, managed-job guards op bestaande jobtools en uitgebreide dispatch-testdekking. Ik heb geen blokkerende correctness- of architectuurfinding gevonden in de beoordeelde diff; bovenstaande configuratie-docs drift is klein genoeg voor een comment-verdict.
Review afgehandeld — F-M1 + F-M2 gerepareerd (docs).
.env.exampleen de README env-tabel mistenDISPATCH_START_PERMIT_KEY_ID, dat de executor-routes vereist (executor = credentials && permit && permitKid). Toegevoegd met de kid-eis (key zonder kid = ongeconfigureerde signer → geen/attempts/*).DISPATCH_SOURCE_MANIFEST_PRIVATE_KEY+DISPATCH_SOURCE_MANIFEST_KEY_ID(beide vereist of de manifest-route blijft unavailable; geen fallback op de permit-sleutel).Commit
a67a75a. Verificatie:npm test1762 passed | 42 skipped. Deze branch is ook metorigin/maingemerged (b2f353e) en herpind op sharedc65f5a8(1b0b50f, parity groen).Re-review-comment afgehandeld (low).
.env.examplemisteDISPATCH_AGENT_OUTPUT_KEY(server.ts leest 'm voor de/agent/*-gateway; README documenteerde 'm al). Toegevoegd in het dispatch-blok, comment gelijk aan het echte gedrag (opt-in HMAC ≥32 bytes; afwezig → geen/agent/*-routes, geen capability). Commitb59cdbf,npm test1762 passed | 42 skipped.Verdict: COMMENT
Geen gekoppeld plan gevonden — beoordeeld op codekwaliteit + product-standaarden.
Findings
node node_modules/typescript/bin/tsc --noEmitis groen nagit submodule update --init --recursiveennode node_modules/prisma/build/index.js generate.node node_modules/typescript/bin/tsc --noEmit -p tsconfig.type-tests.jsonis groen, conform de product-doc over aparte typecheck voorsrcen tests.node node_modules/vitest/vitest.mjs run --config vitest.config.tskon in deze review-container niet starten door een nativerolldownbinding/DLOPEN-fout (failed to map segment from shared object). Dit is geen inhoudelijke failing test uit de PR, maar daardoor is de gewone Vitest-suite hier niet bewezen groen.Conclusie
Geen reden voor
REQUEST_CHANGES, maar door de niet-uitgevoerde Vitest-suite kies ik safe-defaultCOMMENTin plaats vanAPPROVED.