What gets evaluated
The harness evaluates two session-level metrics after every turn (both scored0.0–1.0, higher is better):
| Metric | What it measures |
|---|---|
agent_reliability | Trajectory risk — worst-case failure signals across the turn’s traces. |
agent_consistency | Session stability — coherence of behavior across the whole session. |
confidence, coherence, loop_detection, tool_correctness), and the per-trace breakdown rides along in the score metadata — so a notice can point at exactly which trace and which signal degraded without any extra API call.
How a turn is scored
Because the metrics are session-level, one completed turn triggers a single batched run:- Polling is bounded:
poll_interval_s×poll_max_attempts. - Trace ingestion lags turn-end (the SDK flushes on a background thread), so transiently empty or not-found runs are retried with backoff (
eval_retry_attempts,eval_retry_backoff_s). - Any persistent CLI failure degrades to a pending score — the harness never raises into, or blocks, your agent loop.
- Optional
signal_weightsare forwarded to the platform to re-weight signal aggregation.
Before the first evaluation, a memoized health check verifies the CLI is present and authenticated (
pandaprobe version + auth status). On failure the harness runs degraded: one warning, a journal health event, and evaluations are skipped — never a crash, never a silent no-op.The four detectors
An absolute threshold is a blunt instrument, so three local detectors run over the scores the harness already fetched — O(1), no extra network calls:Absolute breach (always on)
Absolute breach (always on)
score < threshold — default 0.5, overridable per metric via reliability_threshold / consistency_threshold or the thresholds map. A None (pending) score is never a breach. This is the only detector that produces breach-severity notices — and the only one that captures eval cases.Trend (on by default)
Trend (on by default)
A dual-EWMA crossover: the fast average (span 3) dropping below the slow one (span 10) by
trend_margin_cross, after trend_min_samples samples, flags a declining trajectory — e.g. a session drifting 0.80 → 0.55 without ever crossing the floor. Per-session history persists in state/score_history.json, so trends survive restarts.Relative drop (opt-in)
Relative drop (opt-in)
adaptive_threshold=true: a score falling adaptive_margin_drop below the session’s own baseline (the slow EWMA) alerts even while above the absolute floor. Useful when different sessions have very different normal operating levels.Percentile corroborator (opt-in)
Percentile corroborator (opt-in)
percentile_window > 0: the latest score landing in the low tail (percentile_floor) of its recent window. Advisory — it corroborates other detectors and never escalates on its own.breach:agent_reliability, trend:agent_consistency, relative:…, percentile:…. Signatures drive de-duplication, rule tagging, and eval-case matching throughout the harness.
Severities
The strongest condition on a report decides the notice severity:| Severity | Meaning |
|---|---|
trend | Advisory: the trajectory is declining, no floor crossed. |
relative | The session dropped sharply below its own baseline. |
breach | A score sits below the absolute threshold — a real failure by your configured definition. |
needs_human | The circuit breaker tripped: self-healing is paused, a person should look. |
De-duplication, cooldown, and recovery
A persistent problem should post one notice, not one per turn:- Per session, the harness remembers the last posted signature set. A new notice posts only when a new condition appears (or, with
alert_cooldown_turns > 0, when the cooldown expires while the same conditions persist). - When a previously-alerting session scores clean, the state resets and a
recoveryevent is journaled — a later regression of the same kind alerts again.
The circuit breaker
If something goes systemically wrong — a bad deploy, a broken tool — notices can storm. More thancircuit_breaker_max_notices within circuit_breaker_window_s escalates to a single needs_human notice and suppresses further posting until the window drains. The standing protocol instructs the agent to surface that notice to a human rather than act on it: it is the one deliberate exit from the autonomous loop.
Shadow mode
observe_only=true evaluates and journals everything but never posts to the mailbox — useful for tuning thresholds against real traffic before letting the agent act. Pair it with the calibration CLI to pick thresholds from evidence.
