Drift Reports¶
DriftReport is the structured output of compare(baseline, current_run).
It captures every change at the (probe, prompt) granularity, plus derived
severity and summary fields for quick consumption.
Structure¶
drift_report.has_drift # bool — True if any regressions were found
drift_report.severity # DriftSeverity: NONE | LOW | MEDIUM | HIGH | CRITICAL
drift_report.summary # one-sentence human-readable summary
drift_report.regressions # list[ProbeComparison] — probes that got worse
drift_report.improvements # list[ProbeComparison] — probes that got better
drift_report.stable # list[ProbeComparison] — unchanged probes
drift_report.overall_baseline_score
drift_report.overall_current_score
drift_report.overall_score_delta
ProbeComparison¶
Each entry in comparisons, regressions, improvements, and stable
is a ProbeComparison:
| Field | Description |
|---|---|
probe_id, probe_name, category, prompt_id |
Identifies which probe/prompt pair this is. |
baseline_score, current_score, score_delta |
The numbers. |
baseline_passed, current_passed |
Pass/fail on each side. |
regression |
True if this is a meaningful regression. |
improvement |
True if this is a meaningful improvement. |
baseline_details, current_details |
The details string from each ProbeResult. |
Severity Heuristic¶
Severity is derived from regression rate and worst-case delta:
| Severity | Trigger |
|---|---|
NONE |
No regressions detected. |
LOW |
Regression rate < 15% and worst delta < 0.2. |
MEDIUM |
Regression rate ≥ 15% or worst delta ≥ 0.2. |
HIGH |
Regression rate ≥ 30% or worst delta ≥ 0.4. |
CRITICAL |
Regression rate ≥ 50% or worst delta ≥ 0.6. |
This heuristic is intentionally simple and transparent — see
promptcanary/core/models.py
for the exact implementation, and the Decision Log
for the rationale.
Generating Reports¶
from promptcanary.core.reporter import DriftReporter
reporter = DriftReporter(drift_report)
reporter.print_terminal() # Rich colour-coded terminal output
reporter.to_markdown("drift_report.md") # GitHub-flavoured Markdown
reporter.to_html("drift_report.html") # Self-contained dark-theme HTML
reporter.to_json("drift_report.json") # Full structured JSON
CI Gating¶
Exits with code 1 if drift_report.has_drift is True — wire this
directly into a CI pipeline to block deployment on detected regressions.