Skip to content

Make the benchmark CI guard robust against run-to-run noise#48

Merged
Korijn merged 1 commit into
masterfrom
claude/benchmark-guard
Jul 10, 2026
Merged

Make the benchmark CI guard robust against run-to-run noise#48
Korijn merged 1 commit into
masterfrom
claude/benchmark-guard

Conversation

@Korijn

@Korijn Korijn commented Jul 10, 2026

Copy link
Copy Markdown
Collaborator

Roadmap PR 2 (Track A) — port of observ #181 + #187. Rebased onto master after #47 merged.

Why

The benchmark job compared a single master run against a single PR run with --benchmark-compare-fail=mean:5%. That gate sits below the noise floor of GitHub-hosted runners: on observ, whole runs of identical code differed by 10–30%, producing fail → fail → pass across attempts of the same commit. A gate below the noise floor doesn't catch regressions — it breeds re-run-until-green rituals.

What this changes

  • GC disabled during timed rounds (--benchmark-disable-gc in addopts) and the median column added — the guard gates on medians.
  • PYTHONHASHSEED=0 pinned in CI so dict/set timings are comparable between processes.
  • Interleaved runs: master and PR code benchmarked A/B/A/B/A/B, three runs each, instead of once each.
  • benchmarks/compare_runs.py (taken from observ's bench/compare_runs.py) replaces --benchmark-compare-fail: a benchmark only fails when the fastest PR run is more than 25% slower than the slowest master run (per-benchmark medians), so a lucky or unlucky process on either side can't produce a false positive. Results are also appended to the GitHub job summary as a markdown table.

The 25% threshold is deliberately positioned as a tripwire for gross accidental regressions (an accidental copy in a hot path, an algorithmic slip), not a precision instrument — both the workflow and the script say so in comments. Changes too small to trip it should be measured with repeated local runs.

Verification

Ran the exact pipeline locally: two --benchmark-save runs of the pointer benchmarks with PYTHONHASHSEED=0, then compare_runs.py --baseline '.benchmarks/*/*_master?.json' --branch '.benchmarks/*/*_branch?.json' --threshold 0.25 — table renders, exit 0 on parity, and ruff check/format pass on the new script.

🤖 Generated with Claude Code

https://claude.ai/code/session_016Mu9vEBwU4fQLi8ZgkgdS2

@Korijn Korijn deleted the branch master July 10, 2026 21:06
@Korijn Korijn closed this Jul 10, 2026
@Korijn Korijn reopened this Jul 10, 2026
@Korijn Korijn force-pushed the claude/benchmark-guard branch from 00ac88f to d5dfadb Compare July 10, 2026 21:09
@Korijn Korijn changed the base branch from claude/ci-modernize to master July 10, 2026 21:10
The benchmark job compared a single master run against a single PR run
with --benchmark-compare-fail=mean:5%, a gate that sits below the noise
floor of GitHub-hosted runners (observ measured 10-30% swings between
runs of identical code). Replace it with the design observ landed in
fork-tongue/observ#181 and #187:

* Disable GC during timed rounds (--benchmark-disable-gc) and add the
  median column, which is what the guard gates on.
* Pin PYTHONHASHSEED=0 in CI so dict/set timings are comparable
  between processes.
* Run master and PR benchmarks interleaved, 3 runs each (A/B/A/B/A/B),
  instead of once each.
* Replace --benchmark-compare-fail with benchmarks/compare_runs.py,
  which only fails a benchmark when the fastest PR run is more than
  25% slower than the slowest master run (per-benchmark medians), so a
  lucky or unlucky process on either side can't produce a false
  positive. Results are also written to the GitHub job summary.

The 25% threshold is deliberately a tripwire for gross accidental
regressions, not a precision instrument; smaller deltas should be
measured with repeated local runs.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_016Mu9vEBwU4fQLi8ZgkgdS2
@Korijn Korijn force-pushed the claude/benchmark-guard branch from d5dfadb to ee50a23 Compare July 10, 2026 21:15
@Korijn Korijn merged commit 05bec17 into master Jul 10, 2026
10 checks passed
@Korijn Korijn deleted the claude/benchmark-guard branch July 10, 2026 21:17
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants