Outbound validator + refine loop
Every outbound message — guest reply, task auto-send, manual send — runs through the outbound validator before it leaves the platform. The validator returns a verdict (clean / has-findings / blocked) per message; the platform's response to the verdict depends on the binding mode and the operator's per-template configuration.
This section documents the unified validation + refine architecture shipped in gh#690 + gh#879.
Sections
- Validation verdicts — what the validator says about a draft.
- Refine button (Refine / Send Anyway / Dismiss) — operator's 3 options on a blocked draft.
- Autonomous auto-refine loop — when the platform retries refinement on its own, with a cap.
- WhatsApp block alerts — interactive 3-button WA notification when a send is blocked.
- Configurable blocking threshold — per-binding / per-template "block all / major+critical / critical-only" knob.
One unified validation layer (gh#690)
Before gh#690, two send paths each had their own validation logic — the unified-mode validator on send-message tasks AND a separate validator wrapping inbox sends. Drafts could pass one and fail the other; operator confusion compounded over time.
After gh#690, both paths route through one validator with two modes:
- operator-in-loop — validator surfaces findings; operator decides Refine / Send Anyway / Dismiss.
- autonomous — validator runs the auto-refine loop (cap 5 attempts), then either passes or notifies the operator.
The mode is per-template (configured in the Task Templates editor).
How a typical send flows
Operator types / accepts draft → validator runs → verdict
├─ clean → send fires
├─ has-findings (below blocking threshold) → send fires + finding logged
└─ blocked → routes to one of:
├─ operator-in-loop: Refine / Send Anyway / Dismiss buttons appear
└─ autonomous: auto-refine loop (cap 5) → re-validate → if still blocked, notify operator via WA
What used to fail silently (now caught)
Pre-gh#865 + gh#724 family: blocked sends would settle the task as done despite the message never reaching the guest. The "Task completed" notification went out even when nothing was sent. Operator only learned about it when a guest complained.
After gh#865 (general outbound delivery guard) + gh#690 (unified layer):
- A blocked send never settles the task
done. - The task surfaces with the validator's reason + the Refine / Send Anyway / Dismiss options.
- The WA notification surfaces the block, not a false completion (see WA block alerts).
Implements: gh#879 (Refine button + autonomous loop + WA actions), gh#690 (unified validation layer across both send paths), gh#850 (configurable blocking threshold), gh#865 (general outbound delivery guard). Related: gh#769 (manual-send block UX), gh#766 (legacy DueTodayTaskCard + mobile MobileTaskResolveSheet), gh#757 (task-drawer send), gh#800 (dashboard SEND ANYWAY), gh#836 (refine corruption guard), gh#860 (non-issue findings).