Diagnostic Rules
Provon ships five built-in Diagnostic Rules. Each Rule runs its signal detectors over the normalized conversation trajectory, applies thresholds, and decides which candidates need model review. Rules are configured per project: enable or disable a Rule, tune its thresholds, and override individual finding types.
The unified finding taxonomy#
The catalog uses one set of 14 finding types; a detected type is exported verbatim with no remapping layer. Each type sits on three orthogonal axes:
- type — what went wrong (the user-facing defect class);
- stage — where in the agent loop it surfaced (6 stages);
- attribution — who is responsible:
agent,environment, orinput.
A weak causal role prior (root / symptom) seeds root-cause ranking; actual causality comes from
detector-declared edges and shared evidence. The Detector column distinguishes types a deterministic family
can close (signal) from types reachable only through model discovery (review).
| Type | Label | Stage | Attribution | Causal role | Detector |
|---|---|---|---|---|---|
goal-misunderstood |
Goal Misunderstood | planning | agent | root | review |
plan-step-omitted |
Plan Step Omitted | execution | agent | symptom | signal |
constraint-violated |
Constraint Violated | execution | agent | root | signal |
capability-mismatch |
Capability Mismatch | execution | agent | root | signal |
capability-unavailable |
Capability Unavailable | execution | environment | root | review |
invalid-tool-precondition |
Invalid Tool Precondition | execution | agent | root | signal |
tool-result-misread |
Tool Result Misread | verification | agent | root | signal |
retrieval-insufficient |
Retrieval Insufficient | execution | agent | root | review |
unsupported-claim |
Unsupported Claim | final-answer | agent | symptom | signal |
safety-policy-block |
Safety Policy Block | runtime | environment | root | signal |
runtime-interruption |
Runtime Interruption | runtime | environment | root | signal |
input-underspecified |
Input Underspecified | understanding | input | root | review |
incoherent-answer |
Incoherent Answer | final-answer | agent | symptom | signal |
repetition-no-progress |
Repetition / No Progress | execution | agent | root | signal |
Stages, in agent-loop order: understanding, planning, execution, verification, final-answer,
runtime.
Built-in Rules#
| Rule | Key | Finding types |
|---|---|---|
| Runtime reliability | runtime-reliability |
runtime-interruption, safety-policy-block, incoherent-answer |
| Tool correctness | tool-correctness |
tool-result-misread, invalid-tool-precondition, repetition-no-progress |
| Task fulfillment | task-fulfillment |
goal-misunderstood, plan-step-omitted, retrieval-insufficient, capability-mismatch, input-underspecified |
| Answer grounding | answer-grounding |
unsupported-claim |
| Safety | safety |
constraint-violated |
capability-unavailable is not bound to a built-in Rule's signal set; it can be proposed by model discovery
(whole_trajectory policy) and reviewed like any other candidate. Signal overrides apply only to types the Rule
actually detects; overrides for unknown types are ignored.
What the pure-rule sweep can recall#
On the no-model rule-signals profile (provon diagnose --mode rule-signals), a candidate publishes only when a
detector closes it from structured or lexical evidence. The deterministic sweep covers:
safety-policy-block— an explicit provider content-filter error (content filter, Azure content-management policy, jailbreak detected) or a self-reported rendered gate (anti-bot challenge page).repetition-no-progress— the same operation repeated past a threshold, or a blind run of consecutive operations returning no usable observation.incoherent-answer— a terminal answer that is empty, garbled, or an uncontextualized bare value with no sentence structure; a surface-form test, so a task that genuinely needs a bare value is not a defect.unsupported-claim,invalid-tool-precondition,tool-result-misread,plan-step-omitted,constraint-violated, andcapability-mismatchin their high-confidence closed cases.
The remaining types require semantic or causal inference and are reachable only via model discovery or review:
goal-misunderstood, retrieval-insufficient, input-underspecified, capability-unavailable, and the bulk of
tool-result-misread. A budget marker ("max time/rounds reached") is detected, but whether it is the independent
root cause versus a symptom needs attribution, so it is reviewed rather than auto-published.
Configuration options#
| Option | Default | Where set | Description |
|---|---|---|---|
keywords |
[] |
Popover + API | One per line; when non-empty, the Rule only evaluates conversations containing at least one keyword (case-insensitive over captured conversation text) |
minDiagnosticConfidence |
0.25 |
Popover + API | Minimum diagnostic confidence to publish a candidate; lower candidates are filtered |
reviewModel |
null |
Popover + API | Override the deployment-default reviewer model; null uses the default |
signalOverrides |
{} |
Popover signal list | Per-type enabled: false or severity override |
lexicon |
{} |
Popover lexicon section | Locale selection, built-in cue ids to disable, and extra cues appended to lexicon tables; the supported way to add product/domain wording |
minSignalScore |
0.25 |
API | Minimum signal score to enter the pipeline; lower signals discarded before review and grouping |
reviewerDiscoveryPolicy |
candidates_only |
API | candidates_only reviews only Rule-produced candidates (clean conversations make no call; fail-closed); whole_trajectory also scans the full trajectory (one model call even on a clean conversation) |
detectorSettings |
{} |
Popover field (must stay empty) + API | Reserved for internal detector thresholds and switches. Only an absent/empty object is accepted; the popover field renders but must be left empty, and any populated group is rejected by the API. No public per-detector tuning groups exist in this build |
A Rule PATCH sends a complete configuration object (it replaces the stored configuration rather than merging),
so include every key together. Production Rules always run the reviewed-diagnosis profile; the no-model
deterministic screen is only available locally through provon diagnose --mode rule-signals.
Signal triage and admission#
Each signal passes two deterministic layers. The detector-layer triage reads only the signal's own evidence and uses no review vocabulary:
admissiblewith an evidence kind:mechanical_predicate— the Rule can establish the finding mechanically;verifiable_predicate— the finding holds once its deterministic proof closes;lexical_lead— a concrete lexical seed the Rules cannot close themselves.
proof_not_closed— the deterministic proof for averifiable_predicatesignal does not close.withheldwith an objective mechanical reason (below threshold, recovered, no precise evidence, no terminal impact, and so on).
The outer admission layer applies runtime policy:
- model review enabled: every admissible signal goes to the reviewer (mechanical/verifiable ones for confirmation; lexical leads for closure judgment);
- no-model
rule-signalsprofile:mechanical_predicateand closedverifiable_predicatesignals publish asdeterministic; alexical_leadis withheld asmodel_review_unavailable.
Evidence requirements apply per review family (the signal's evidence-collection strategy), not per type.
Production is fail-closed: no available model withholds as model_review_unavailable; a throwing call or
execution failure becomes model_review_error; a model returning no definite verdict becomes
model_review_inconclusive. No candidate is promoted, and the run retains audit counters.
Publication funnel#
Every diagnosis reports an unambiguous, model-first funnel returned on the discovery API, printed by
provon diagnose (funnel), emitted as diagnostics.* span attributes, and aggregated in eval metadata.
| Layer / Field | Meaning |
|---|---|
profile |
rule-signals / reviewed-diagnosis; aggregate of unlike runs reports mixed; carried on the result, never guessed |
candidate.ruleCount |
Candidates from the deterministic detector sweep |
candidate.modelDiscoveredCount |
Candidates from the conversation-level discovery pass that survived the deterministic post gate; 0 when nothing new is proposed |
candidate.mergedCount |
Deduped union entering the gate |
mechanicalGate.filteredCount |
Candidates stopped by score/confidence/evidence/impact/corroboration before review or publication |
mechanicalGate.verifiedCount |
Candidates that cleared the gate |
mechanicalGate.weakLeadWithheldCount |
Weak one-event lexical leads withheld for insufficient corroboration; never surfaced even as a lead |
mechanicalGate.withheldReasons |
Per-reason breakdown keyed by stable reason code |
publication.publishedCount |
Confirmed Findings actually recorded; provider failure leaves this 0 while counters remain |
publication.deterministicPublishedCount |
Findings confirmed deterministically, no model adjudication |
publication.leadCount |
Credible-but-unclosed leads in the non-scored review tier |
publication.postFilteredCount |
Verified candidates absorbed by causal grouping or the publication cap |
publication.rejectionReasons |
Per-reason breakdown (reviewer dismiss/duplicate plus deterministic rejection) |
review.* |
Structured-review outcomes; absent entirely in rule-signals mode; holds reviewed/accepted/rejected/abstained/failure counters, model usage flags, and error |
Reconciliation: under reviewed mode, review.acceptedCount = publication.publishedCount + review.postGateRejectedCount. A one-event lexical lead without corroboration is withheld at the mechanical gate
as insufficient_corroboration (weakLeadWithheldCount); it differs from model_review_unavailable, the
fail-closed withhold of a candidate the review boundary never closed.
How to tune#
Reduce false positives#
- Increase
minDiagnosticConfidencefor the Rule. - Disable noisy finding types with
signalOverrides. - Add
keywordsso the Rule only runs on relevant conversations.
Example API patch (the whole configuration is replaced):
{
"configuration": {
"keywords": ["payment", "refund"],
"minSignalScore": 0.25,
"minDiagnosticConfidence": 0.7,
"reviewerDiscoveryPolicy": "candidates_only",
"reviewModel": null,
"signalOverrides": {
"repetition-no-progress": { "enabled": false },
"incoherent-answer": { "severity": "info" }
},
"lexicon": {},
"detectorSettings": {}
}
}Control cost in high-volume pipelines#
The default candidates_only policy bounds cost: a clean conversation where no Rule fired makes no model
call; any conversation with a candidate is still reviewed.
- Switch to
whole_trajectoryonly when you want issues the Rules never hinted; it makes one model call on every conversation, including clean ones. - Production Rules always run the reviewed-diagnosis profile; there is no server-side no-model option. Use the
local
rule-signalsprofile for deterministic screening.
CI screening#
provon diagnose --mode rule-signals skips the model and publishes only signals confirmable from structured
evidence; expect lower recall for review-gated types such as unsupported-claim. Server-side Rules stay on the
candidates_only default for persisted Findings.
Severity levels#
| Severity | When to use |
|---|---|
critical |
Agent produced a wrong or harmful outcome with high confidence |
high |
Clear failure mechanism likely affecting user value |
medium |
Detected problem that may be recoverable or context-dependent |
low |
Minor degradation, noise, or best-practice violation |
info |
Observation that does not require immediate action |
Limitations#
- Review-only types never publish under the local deterministic profile; absence locally is not absence on the reviewed server profile.
- Keyword filters narrow scope but also suppress every type on unmatched conversations.
- A high-confidence deterministic signal still follows the Rule's configured confidence and publication gates.