feat(openzaak): bounded retry + flagged write divergence (WP-60)
Local aanvraag/document writes and their paired ZGW writes aren't transactional; a ZGW failure after the local write succeeds used to diverge silently. ZgwHttpClient now retries transport-shaped failures (not 500, which can follow a partial commit on the non-idempotent statussen/rollen POSTs), and a ZGW failure that survives retry sets Aanvraag.ZgwError plus a zgw:divergence audit row instead of failing or diverging quietly. No outbox/reconcile job: three request-triggered write paths don't justify a persisted queue that would also need to carry citizen PII for the JWT audit claims. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
This commit is contained in:
@@ -110,7 +110,7 @@ for its existing violations, so every WP ends green.
|
||||
| [WP-57](WP-57-openzaak-least-privilege-scopes.md) | Least-privilege client scopes | 10 · OpenZaak hardening | done |
|
||||
| [WP-58](WP-58-openzaak-notifications.md) | Real notifications (celery + scripted abonnement) | 10 · OpenZaak hardening | done |
|
||||
| [WP-59](WP-59-document-confidentialiteit-config.md) | Per-document-type confidentialiteit config | 10 · OpenZaak hardening | done |
|
||||
| [WP-60](WP-60-write-divergence-resilience.md) | Write-divergence resilience (local + ZGW writes) | 10 · OpenZaak hardening | todo |
|
||||
| [WP-60](WP-60-write-divergence-resilience.md) | Write-divergence resilience (local + ZGW writes) | 10 · OpenZaak hardening | done |
|
||||
| [WP-61](WP-61-behandelportal-bootstrap.md) | Bootstrap the behandelportal app | 11 · Behandelportal | todo |
|
||||
| [WP-62](WP-62-medewerker-identity-authz.md) | Backend: medewerker caller identity + authz seam | 11 · Behandelportal | todo |
|
||||
| [WP-63](WP-63-aanvraag-status-lifecycle.md) | Backend: aanvraag status lifecycle as a published DTO | 11 · Behandelportal | todo |
|
||||
@@ -149,17 +149,16 @@ deployment of 49–52) and **54** (a docker OpenZaak harness + opt-in integratio
|
||||
CRUD arc and can land any time; 54 depends on 49 (something to read) and unlocks realistic
|
||||
testing for the rest. Both are self-contained (each WP file carries its own current-state
|
||||
handoff) and sized for a fresh Sonnet session.
|
||||
Phase 10 (OpenZaak production hardening, WP-55..60) and Phase 11 (Behandelportal,
|
||||
WP-61..66) are two independent tracks that can be worked concurrently — neither blocks
|
||||
the other. Within phase 10: 55/59/60 are fully independent; 57 and 58 both build on 56's
|
||||
provisioning mechanism, otherwise independent of each other. Within phase 11: 61
|
||||
Phase 10 (OpenZaak production hardening, WP-55..60 — now **done**) and Phase 11
|
||||
(Behandelportal, WP-61..66) are two independent tracks that can be worked concurrently —
|
||||
neither blocks the other. Within phase 10: 55/59/60 were fully independent; 57 and 58 both
|
||||
built on 56's provisioning mechanism, otherwise independent of each other. Within phase 11: 61
|
||||
(bootstrap), 62 (backend medewerker identity), and 63 (backend status DTO) are
|
||||
independent of each other and can land in any order; 64 needs all three (61 for the app
|
||||
to exist, 62 for identity, 63 for the status it reads); 65 needs 64; 66 needs 65 and
|
||||
benefits from — but doesn't strictly require — phase 10's WP-60 landing first (WP-66 is
|
||||
a second, currently-unprotected write pair otherwise). WP-60 is the one slice in phase 10
|
||||
sized for a `planner`-agent kickoff rather than direct implementation — its Decisions
|
||||
block is deliberately left open (outbox vs. retry+reconcile).
|
||||
to exist, 62 for identity, 63 for the status it reads); 65 needs 64; 66 needs 65 and — now
|
||||
that WP-60 has landed (bounded retry + flagged divergence in `ZgwHttpClient`/`Program.cs`) —
|
||||
inherits that retry for free, but must call `RecordZgwDivergence` on its own besluit write path
|
||||
to get the flagging half too.
|
||||
|
||||
## WP template
|
||||
|
||||
|
||||
Reference in New Issue
Block a user