feat(slice-4): honest delivery failure — send-before-commit + 502 delivery_failed (INV-9; closes #7)

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
2026-06-10 23:35:01 -07:00
parent 1b8c60fcb5
commit 22d738fc74
6 changed files with 77 additions and 12 deletions
@@ -64,3 +64,28 @@ def test_request_code_rejects_invalid_email(conn):
with pytest.raises(accounts.InvalidEmail):
accounts.request_code(conn, m, "not-an-email")
assert m.outbox == []
class _FailingMailer:
"""A mailer whose relay always refuses — the INV-9 honest-failure path."""
def send(self, to: str, subject: str, body: str) -> None:
raise mailer.MailerError("relay refused")
def test_delivery_failure_leaves_no_orphan_code(conn):
# ecomm#7: send happens BEFORE commit — a failed delivery must not strand an
# auth_code row (which would also trip the resend cooldown for 60s).
with pytest.raises(accounts.DeliveryFailed):
accounts.request_code(conn, _FailingMailer(), "merchant@example.com")
rows = conn.execute("SELECT count(*) FROM auth_code").fetchone()[0]
assert rows == 0
def test_delivery_failure_does_not_trip_cooldown(conn):
with pytest.raises(accounts.DeliveryFailed):
accounts.request_code(conn, _FailingMailer(), "merchant@example.com")
# the immediate retry (relay back up) succeeds — no ResendCooldown
m = mailer.LogMailer()
accounts.request_code(conn, m, "merchant@example.com")
assert len(m.outbox) == 1
+16
View File
@@ -128,3 +128,19 @@ def test_puc_09_logout_clears_session(fresh_db_url):
# after logout the cookie is cleared -> /me is unauthenticated again
client.cookies.clear()
assert client.get("/api/auth/me").status_code == 401
def test_request_code_delivery_failure_is_502(fresh_db_url, monkeypatch):
# INV-9 honest failure over HTTP (§6.4): the relay refused -> 502 delivery_failed,
# never a fake 204. Force the app's mailer to fail after startup.
from app.platform import mailer as mailer_mod
class _FailingMailer:
def send(self, to, subject, body):
raise mailer_mod.MailerError("relay refused")
with _client(fresh_db_url) as client:
client.app.state.mailer = _FailingMailer()
resp = client.post("/api/auth/request-code", json={"email": "merchant@example.com"})
assert resp.status_code == 502
assert resp.json()["error"]["code"] == "delivery_failed"