From 7ba01a6dfaf95c66224680fff23835af6ec92ac9 Mon Sep 17 00:00:00 2001 From: "bert.hausmans" Date: Fri, 8 May 2026 08:57:02 +0200 Subject: [PATCH] docs(runbooks): add form-builder binding failures section MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Per RFC-WS-6 §Q3 v1.3 + ARCH-BINDINGS §11. Nieuwe runbook-sectie §7 (na §6 Audit trail) die de triage-flow documenteert wanneer GlitchTip een FormBindingApplicatorException event opbrengt: - §7.1 failure_response_code classificatie (schema_config_error / temporary_error / data_integrity_error / unknown_error) drijft het initiële triage-pad - §7.2 form_schema.has_public_token tag onderscheidt klant-zichtbare failures (alert-waardig) van organizer-driven failures (admin-UI only) - §7.3 retry/dismiss decision-matrix met form-failures:retry artisan command + DismissalReasonType enum cases - §7.4 severe-failure escalatie criteria (>10/uur op één schema = P1) - §7.5 cross-references naar RFC, ARCH-BINDINGS, en erasure-runbook Companion van de operationele GlitchTip alert-rule (apart geconfigureerd in de GlitchTip web UI op monitoring.hausdesign.nl). Co-Authored-By: Claude Opus 4.7 --- dev-docs/runbooks/observability-triage.md | 112 ++++++++++++++++++++++ 1 file changed, 112 insertions(+) diff --git a/dev-docs/runbooks/observability-triage.md b/dev-docs/runbooks/observability-triage.md index 88b6b466..c2559ee3 100644 --- a/dev-docs/runbooks/observability-triage.md +++ b/dev-docs/runbooks/observability-triage.md @@ -268,3 +268,115 @@ Voor incidents waar 1+ klant geraakt is, log een externe incident-summary (klant, impact, timeline, fix) in een aparte incident-tracker — niet in GlitchTip zelf, want GlitchTip data wordt na 90 dagen gepurged. + +--- + +## §7 Form-builder binding failures + +### Context + +`FormBindingApplicator` draait synchroon binnen +`ApplyBindingsOnFormSubmit::handle` voor elke form-submission. Als die +throwt — schema-misconfiguratie, infra-issue, data-integrity violation +of deadline-timeout — vangt de listener de throw op, schrijft een +`form_submission_action_failures` rij in de outer-transaction, en zet +`apply_status='failed'` op de parent-submission. GlitchTip vangt het +exception-event op met de `crewli-api` project-tags. + +De alert-rule op `apply_status=failed AND form_schema.has_public_token=true` +brengt alleen de klant-zichtbare failures naar boven — organizer-driven +private-form failures zijn zichtbaar in de Form Failures admin-UI zonder +alert, omdat hun blast radius beperkt is tot één organisatie. + +Per RFC-WS-6.md §Q3 v1.3 + ARCH-BINDINGS.md §6 (two-transaction pattern) +en §11 (failures lifecycle). + +### 7.1 Eerste check — `failure_response_code` + +De submission-rij draagt een denormalised classification-token in +`failure_response_code`. Vier waardes: + +| Token | Oorzaak | Triage-pad | +|---|---|---| +| `schema_config_error` | Organizer-config issue (renamed kolom, deleted target-entity, ontbrekende identity-key binding die publish-guards toch doorlieten) | Contact de organizer van het schema; **NIET retryen** — retry produceert dezelfde exception | +| `temporary_error` | Infra-issue (DB-connection, lock-for-update wait, deadline-wrapper timeout) | Retry via `php artisan form-failures:retry --id={failure_ulid}` of admin-UI; als een tweede retry óók faalt, escaleer als infra-incident | +| `data_integrity_error` | Data-shape violation (type-mismatch, FK-violation, soft-deleted target-entity) | Onderzoek de failing binding's `target_entity` + `target_attribute` in `form_field_bindings`; lost meestal op als een schema-config issue verkleed als data | +| `unknown_error` | Iets buiten de binding-applicator hiërarchie (raw `\Throwable`, `IdentityMatchInvariantViolation`) | Triage via de GlitchTip exception-trace; dit is dev-investigation territory | + +De exception-class op de action-failure rij is de canonical truth; +`failure_response_code` is de afgeleide classificatie die door de +response-renderer gebruikt wordt. + +### 7.2 Tweede check — public-token presence + +De GlitchTip event-tag `form_schema.has_public_token` onderscheidt: + +| Tag-waarde | Betekenis | Severity | +|---|---|---| +| `true` | Public submission flow (vrijwilliger registratie-window, public form-fill) | Customer-impact bevestigd; mobiliseer binnen minuten tijdens active festival registratie | +| `false` | Organizer-driven private flow (managed crew roster, internal data import) | Blast radius beperkt tot één organisatie; onderzoek binnen uren | + +### 7.3 Retry vs dismiss + +Gebruik het artisan-command: + +```bash +# Retry een enkele failure +php artisan form-failures:retry --id={failure_ulid} + +# Retry alle open failures voor een submission +php artisan form-failures:retry --submission={submission_ulid} + +# Dry-run eerst als onzeker +php artisan form-failures:retry --id={failure_ulid} --dry-run +``` + +Wanneer wel retryen: + +- `temporary_error` — ja, bijna altijd; de deadline-wrapper of infra-hiccup + is waarschijnlijk inmiddels weg. +- `unknown_error` — alleen na dev-investigatie die bevestigt dat de + throw transient was. + +Wanneer dismissen: + +- `schema_config_error` nadat de organizer het schema heeft gefixt en + opnieuw heeft gesubmit — de originele failure-rij blijft staan als + audit, dismiss met reden `schema_deleted` of `binding_removed` per + het relevante geval. +- `data_integrity_error` nadat dev-investigatie het herleidt tot een + one-off data-state die niet meer geldt — dismiss met + `data_quality_issue`. +- Iedere failure voor een submission die de organizer expliciet als + duplicaat geclassificeerd heeft — dismiss met `duplicate_submission`. + +De `DismissalReasonType` enum heeft zes cases; `OTHER` vereist een +free-text note. Per ARCH-BINDINGS §11.3. + +### 7.4 Severe-failure escalatie + +Als GlitchTip `>10` events in 1 uur toont gescoped op één +`form_schema_id`, behandel als P1: + +1. Acknowledge de alert in het team-channel. +2. Identificeer het schema via `form_submission.form_schema_id` op een + willekeurige failed submission. +3. Pauzeer publieke toegang tot het schema tijdelijk — disable het + public token tot de root-cause geïdentificeerd is. +4. Standaard incident-triage geldt verder. + +Dit patroon wijst bijna altijd op een publish-guard gap: een +schema-configuratie die de guards hadden moeten weigeren is er toch +doorheen geslipt, en elke submission ertegen produceert dezelfde +exception. + +### 7.5 Cross-references + +- [`RFC-WS-6.md`](../RFC-WS-6.md) v1.3.1 — volledige architectuur, in + het bijzonder §Q3 v1.3 additions. +- [`ARCH-BINDINGS.md`](../ARCH-BINDINGS.md) v1.2 — §6 two-transaction + pattern, §11 failures lifecycle, §11.3 dismissal reasons. +- [`observability-erasure.md`](./observability-erasure.md) — Art. 17 + procedure als triage in een GDPR-deletion-verzoek omdraait. +- BACKLOG `TECH-CHANNEL-AUTH-ORG-ADMIN` — bekende follow-up voor + live-update channel-auth uitbreiding (org-admin scope).