Outbound validator + refine loop

WhatsApp block alerts

When the outbound validator blocks a send + the operator is reachable via WA, the platform fires an interactive 3-button WA alert (gh#879) — the operator can decide from their phone without opening the app.

Alert shape

⚠ Send BLOCKED — Pre-checkout reminder
Castle&River Vydrica · Johanna
Validator: Parking-info-relevance (MAJOR)
"draft mentions parking but guest never asked"

[ Refine ]  [ Send Anyway ]  [ Dismiss ]

The buttons map 1:1 to the in-app Refine / Send Anyway / Dismiss surface.

  • Refine → runs one refine pass server-side; the new validator verdict + new draft come back as a follow-up WA message.
  • Send Anyway → fires the send + writes the override audit row.
  • Dismiss → marks the task done without sending.

When the alert fires

  • An autonomous auto-refine loop exhausted attempts → operator notified.
  • An operator-in-loop draft was generated by a cron-fired auto-send → operator needs to decide.
  • A manual SEND that the operator triggered fails validation → the alert lands as a follow-up to the operator's send action.

Bursts are de-duped: one alert per episode (gh#754 — earlier the alert spammed every cron tick).

Dedup window

If multiple blocked sends fire for the same task within a few minutes, only ONE WA alert goes out. Subsequent blocks accumulate into the operator's daily-overview WA summary instead of paging again.

Closed WA window

The standard 24h window rules apply (see WhatsApp Bot):

  • Window open → free-text interactive 3-button alert.
  • Window closed → falls back to the task_resolved_with_actions template (3 button params).

After gh#849, the alert is always delivered even when the WA window is closed — earlier the alert was silently suppressed and the operator never heard about the block.


Implements: gh#879 (WA — interactive 3-button block alert), gh#754 (dedup hold), gh#849 (window-closed delivery via template).

Source: the FlatsBratislava operator manual.