---
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.
