#87 FTX-87: blank policy_name will 422 ~8% of HITL notifications under mail-api strict rendering

closed high bug Created 2026-07-26 19:09 · Updated 2026-07-28 21:41

Description

Edit
EARS SPEC: Context: mail-api deployed strict rendering for TRANSACTIONAL template sends on 2026-07-26 (their thr-f60cc7a11b7d489e8727). Any variable that is not supplied is now a hard 422 template_render_error instead of rendering as an empty string. They measured our live traffic: 10 of 129 `[Action needed]` notifications in the last 7 days went out with a blank Policy field, so ~8% of our HITL notifications will now fail to send. For an approval gate a 422 we do not handle is worse than a blank field: the reviewer is never told and the decision silently waits. Root cause on our side: app/workers/mail_drain.py passes `policy_name=ctx.get("policy_name", "")`, and several notification producers never put policy_name in the outbox context at all — app/workers/runflow_reconcile.py, app/domain/escalation.py, app/domain/actions.py (reminder path). Every decision already carries its policy name in the immutable snapshot (`decision.policy_snapshot["_policy_name"]`), so the value was available and simply not threaded through. - MA-1: The Futex mail client SHALL supply a non-empty value for every template variable in a transactional send, substituting an explicit placeholder where no real value exists, so that no notification can be rejected for a missing variable. - MA-2: When a notification is enqueued for a decision, the Futex system SHALL populate `policy_name` from that decision's immutable policy snapshot. - MA-3: If mail-api rejects a notification send, THEN the Futex system SHALL NOT mark the notification sent, and SHALL retry it and dead-letter it after the configured maximum attempts so the failure is visible rather than silent.

Comments

Loading comments...

Context

Loading context...

Audit History

View All
Loading audit history...