Summary
driftbase history detects behavioral epochs using Jensen-Shannon divergence on behavioral distributions — excellent for catching discrete shifts. The gap is the continuous slope layer: numeric metrics like error_count, latency_ms, and retry_count accumulate in agent_runs_local on every run, but there is no command that computes OLS regression across the ordered run sequence.
These are complementary, not competing:
- Epoch detection (JSD on outcome/tool distributions) → catches discrete behavioral shifts
- OLS slope (linear regression on numeric metrics) → catches gradual degradation that never triggers a JSD breakpoint
A 5%→8%→12%→16% error rate drift across 20 runs may never produce a JSD spike large enough to become its own epoch. It shows up as an L-H-L-H-L epoch alternation, or gets absorbed into existing epoch noise. But the slope is telling you something the epoch framing misses.
Proposed Addition: driftbase trend
Data model
@dataclass
class MetricTrend:
metric: str # "error_rate", "latency_ms", "retry_rate"
slope: float # from statistics.linear_regression (Python 3.10+)
direction: str # "worsening" | "improving" | "stable"
window_runs: int # how many runs the slope covers
any_regression: bool
@dataclass
class RunTrendReport:
agent_id: str
window: int
computed_at: str
trends: list[MetricTrend]
any_regression: bool # True if any metric is worsening
Implementation sketch
from driftbase.backends.factory import get_backend
import statistics
def compute_run_trend(window: int = 20) -> RunTrendReport:
backend = get_backend()
runs = backend.get_runs(limit=window) # most-recent-first
ordered = list(reversed(runs)) # oldest-first for OLS
n = len(ordered)
xs = list(range(n))
# error_rate = error_count / max(tool_call_count, 1)
error_rates = [r["error_count"] / max(r["tool_call_count"], 1) for r in ordered]
latencies = [r["latency_ms"] for r in ordered]
retry_rates = [r["retry_count"] / max(r["tool_call_count"], 1) for r in ordered]
def _trend(values):
slope, _ = statistics.linear_regression(xs, values)
# error_rate and retry_rate: higher = worsening; latency: higher = worsening
direction = "worsening" if slope > 0.001 else ("improving" if slope < -0.001 else "stable")
return slope, direction
trends = []
for name, values in [("error_rate", error_rates), ("latency_ms", latencies), ("retry_rate", retry_rates)]:
slope, direction = _trend(values)
trends.append(MetricTrend(
metric=name, slope=slope, direction=direction,
window_runs=n, any_regression=(direction == "worsening")
))
return RunTrendReport(
agent_id=..., window=window, computed_at=...,
trends=trends, any_regression=any(t.any_regression for t in trends)
)
CLI integration
driftbase trend
driftbase trend --window 20
driftbase trend --format json
driftbase trend --exit-on-regression # CI gate: exit 1 if any_regression
Output (text):
DRIFTBASE TREND · Last 20 runs
error_rate slope=+0.0041 WORSENING (5.1% → 12.3%)
latency_ms slope=+128 WORSENING (1.2s → 3.8s)
retry_rate slope=+0.001 STABLE
Status: REGRESSION DETECTED (2/3 metrics worsening)
Natural integration points
driftbase diagnose could call this internally and note when OLS slope predates the epoch breakpoint by N runs
driftbase diff could annotate whether the current version's metric slope is steeper than the baseline version's
- CI gating:
driftbase trend --exit-on-regression provides a continuous slope gate alongside the existing snapshot-comparison diff gate
Why complement epoch detection
| Detection type |
Catches |
Misses |
| JSD epoch detection |
Sudden distribution shifts |
Slow linear regressions |
| OLS slope |
Gradual per-metric drift |
Distribution shape changes |
| Both together |
Full behavioral slope picture |
— |
The data already exists in agent_runs_local. This is purely an analysis layer addition.
Related: PDR in Production v2.8 — §7.6.8 documents the same structural omission across 15 independent agent evaluation and observability frameworks. driftbase is distinctive because it is explicitly focused on behavioral drift — the proposed trend command fills the one complementary gap in an otherwise comprehensive tool.
Summary
driftbase historydetects behavioral epochs using Jensen-Shannon divergence on behavioral distributions — excellent for catching discrete shifts. The gap is the continuous slope layer: numeric metrics likeerror_count,latency_ms, andretry_countaccumulate inagent_runs_localon every run, but there is no command that computes OLS regression across the ordered run sequence.These are complementary, not competing:
A 5%→8%→12%→16% error rate drift across 20 runs may never produce a JSD spike large enough to become its own epoch. It shows up as an L-H-L-H-L epoch alternation, or gets absorbed into existing epoch noise. But the slope is telling you something the epoch framing misses.
Proposed Addition:
driftbase trendData model
Implementation sketch
CLI integration
driftbase trend driftbase trend --window 20 driftbase trend --format json driftbase trend --exit-on-regression # CI gate: exit 1 if any_regressionOutput (text):
Natural integration points
driftbase diagnosecould call this internally and note when OLS slope predates the epoch breakpoint by N runsdriftbase diffcould annotate whether the current version's metric slope is steeper than the baseline version'sdriftbase trend --exit-on-regressionprovides a continuous slope gate alongside the existing snapshot-comparisondiffgateWhy complement epoch detection
The data already exists in
agent_runs_local. This is purely an analysis layer addition.Related: PDR in Production v2.8 — §7.6.8 documents the same structural omission across 15 independent agent evaluation and observability frameworks. driftbase is distinctive because it is explicitly focused on behavioral drift — the proposed
trendcommand fills the one complementary gap in an otherwise comprehensive tool.