Streaming Latency Percentiles

stats.percentile is exact but needs the full sorted sample list in memory; for a long-running or sharded load / soak run you want an O(1)-per-record, bounded-memory, mergeable structure instead. This adds a HdrHistogram-style LatencyDigest (records into significant-figure buckets, merges across shards) plus exact_percentiles() for small sample sets.

Pure standard library (math); imports no PySide6.

Headless API

from je_auto_control import LatencyDigest, exact_percentiles

digest = LatencyDigest(sig_figs=3)
for latency_ms in stream:
    digest.record(latency_ms)        # O(1), bounded memory
print(digest.summary())              # min/mean/max/p50/p90/p95/p99

# merge per-shard digests into one
total = shard_a.merge(shard_b)

# exact percentiles for a small in-memory set
exact_percentiles([12.0, 9.5, 14.2], qs=(50, 95))

LatencyDigest.record buckets each value to sig_figs significant figures (so memory is bounded by the number of distinct rounded values, not the sample count); percentile / quantiles / summary read it back, and merge folds another digest in for cross-shard aggregation — the property you need to compute a correct aggregate p99 from per-worker results. exact_percentiles delegates to stats.percentile for the small-set case.

Executor command

AC_percentiles takes samples (a list or JSON string) and optional qs quantiles (default 50/90/95/99) and returns {percentiles}. The same operation is exposed as the MCP tool ac_percentiles and as a Script Builder command under Report.