--- key: release.live-e2e-required title: 2026-07-12 — Live-E2E is a required step for API write-path handler changes (#303) status: active since: '2026-07-12' supersedes: none superseded-by: none rule: A PR that changes an API write-path handler must include a live-E2E pass (driving the real endpoint/screen and confirming the round-trip through a subsequent read), not only unit/characterization tests, and must state whether live-E2E ran or wasn't required. signals: 'lazy LanguageExt `Map` blind spot, #229 finding · paths: `docs/e2e-local.md`, `docs/api-conventions.md` §7 · issues: #303, #229' mechanics: '`docs/e2e-local.md`' --- **A PR that changes an API write-path handler (a `POST`/`PUT`/`DELETE` `/api/*` command that mutates state and reloads it through the read path) MUST include a live-E2E pass** — driving the real endpoint or its SPA screen and confirming the mutation round-trips through a subsequent read — not only unit / characterization tests. Rationale: this class has a **correlated blind spot** unit and characterization tests share. A green fixed-point test passed while the write-path returned a production 500 because the handler returned a *lazy* LanguageExt `Map` the test never enumerated (#229; reload-through-read-path mechanics in `api-conventions.md` §7); the failure surfaces only when the result is materialised, which the SPA does and the test did not. Live driving is the only reliable net for it. Non-write-path (pure-SPA/read-only) and docs PRs don't need it. The requirement is auditable, not silent: the PR/close comment states that live-E2E ran, or — for a non-write-path change — that it wasn't required (the same stated-exemption discipline as the review skip rubric). Recipe + "When live-E2E is required": `docs/e2e-local.md`. This formalizes the #229 lore bullet ("live E2E remains the only net for this class") into a standing convention.