Outbound validator + refine loop

Validation verdicts

Every outbound draft gets a verdict from the validator: clean / has-findings / blocked. The verdict drives what happens next.

The three verdicts

clean

No findings above the blocking threshold. Send fires; no operator action.

has-findings (below threshold)

Findings exist but they're info / minor (or below confidence threshold). Send fires; findings logged in the audit log for later review. Operator can review per-template trends in the AI Cockpit → Validators tab.

blocked

At least one finding above the threshold. Send does NOT fire. Routes to the Refine button surface for operator decision OR the autonomous loop, depending on template config.

Finding fields

Each finding carries:

Field What
validatorSlug Which validator emitted it (parking_info_relevance / language_match / factual_accuracy / etc.)
severity info / minor / major / critical
confidence 0-1 score (gh#804)
reason Plain-English explanation for the operator
evidence The specific draft text that triggered it
proposedFix Optional — what the validator would change

Where verdicts are visible

  • Inline on the draft surface — V28 Inbox composer, task-drawer, Pulse task tile, mobile.
  • Audit log — every verdict + finding logged with the draft + send result (gh#832).
  • AI Cockpit → Validators — per-binding stats: fire rate, block rate, override rate, false-positive flag rate.

Verdict cache (gh#854)

A verdict is cached for the same (draft body, thread context) tuple for N minutes — prevents the cron from re-rolling a non-deterministic validator until a blocked send randomly passes. See Autonomous refine.

False-positive flag

In the audit log, operator can mark a finding false positive with a one-sentence reason. The flag feeds back into the validator's confidence tuning + surfaces on the binding's stats page so the team can see which validators need prompt work.


Related: Refine button, Threshold, Autonomous refine, AI Cockpit.

Source: the FlatsBratislava operator manual.