Outbound validator + refine loop

Autonomous auto-refine loop

For templates configured autonomous (instead of operator-in-loop), the platform runs the refine loop itself — no operator step on first block.

How it runs

Send fires → validator → verdict
  ├─ clean → send
  └─ blocked → auto-refine loop:
       attempt 1: refine + re-validate → clean? send. blocked? continue
       attempt 2: refine + re-validate → clean? send. blocked? continue
       ...
       attempt 5: re-validate → clean? send. blocked? notify operator (WA + in-app)

Cap = 5 attempts (gh#879). After 5 the loop stops + escalates to the operator.

What gets fed back

Each refine attempt feeds the LLM:

  • The original draft
  • The validator's findings (severity, slug, plain-English reason)
  • The thread history (so the refined draft stays consistent with prior context)
  • The template's outbound language (per Languages)

The validator runs against the refined draft; if any finding remains above the blocking threshold, the loop continues.

Operator visibility

While the loop runs, the task surface shows:

  • A auto-refining (attempt N/5) chip on the task card.
  • The current validator finding.
  • A CANCEL button — operator can stop the loop + take over manually.

After the loop ends (success or escalation):

  • Success — task settles done; audit row captures autoRefineAttempts=N + verdict=clean.
  • Escalation — task stays open; WA + in-app notification fires (see WA block alerts); operator gets the 3-button surface to decide.

Retry-rolls-validator anti-pattern guard (gh#854)

Before gh#854, an auto-resolve that re-tried every 6 minutes could re-roll the non-deterministic validator until a blocked send happened to PASS — defeating the validator's purpose. A blocked check-in reminder reached a guest (Patrik) this way.

Fix in gh#854: validator verdicts are cached for the same draft body + context for N minutes. Re-rolls within the cache window return the same verdict. The retry can't randomly pass.

When to use autonomous vs operator-in-loop

  • autonomous — high-volume low-stakes templates (Pre-checkout reminder, Thank-you message). Operator doesn't want to babysit every send.
  • operator-in-loop — high-stakes templates (Send Check-in with access code, dispute response, partial-refund message). Operator confirms every send.

Per-template configuration lives in the Task Templates editor → Auto-refine behavior field — see also Auto-refine drafts.


Implements: gh#879 (autonomous loop cap 5 + notify), gh#854 (validator-verdict cache guard).

Source: the FlatsBratislava operator manual.