Conversation
redisbench-admin judges each `kpis` floor on a single sample, and the harness's own run-to-run spread is 22-49% above ~100k rps against floors set 5% low. Four consecutive nightlies on the identical commit a3b2edb recorded 20 breaches between them, so the gate currently fails quiet nights and would pass a real slowdown. Move the verdict into the repo: run-remote keeps measuring but no longer decides (continue-on-error), and check_kpis.py compares each result against its floor and fails only when the previous run saw the same benchmark breach. The verdict is carried between runs in the Actions cache, keyed by ref, shard and run id, so a PR run cannot inherit master's breaches and each of the three shards judges its own subset. Replaying the four nights through the new gate reproduces the 8 and 12 breaches on 09-19 and 09-21 and exits 0 on all four, per shard and merged; a 30% slowdown injected into two consecutive nights is reported on the first and fails the job on the second. json_nummultby_num_2 (MOD-18654, Won't Do) has no floor, so it is listed as ungated rather than failed -- otherwise the job stays red every night and its status still means nothing. A run where no benchmark produced a result does fail, so continue-on-error cannot hide a broken harness. This is a stopgap for the gate, not for the measurement: a regression smaller than the harness's spread stays invisible. Narrowing that spread is MOD-18823; per-benchmark margins should follow from its findings.
Codecov Report✅ All modified and coverable lines are covered by tests. Additional details and impacted files@@ Coverage Diff @@
## master #1642 +/- ##
=======================================
Coverage 85.97% 85.97%
=======================================
Files 15 15
Lines 5306 5306
=======================================
Hits 4562 4562
Misses 744 744 ☔ View full report in Codecov by Harness. 🚀 New features to boost your workflow:
|
A benchmark under its floor is under a baseline already set 5% below a measured value, so any breach is worth a ticket -- whether or not it repeats the next night. The previous commit reported a first-time breach only as a log line, which is too easy to lose. Findings now leave the run in a form the nightly analysis can triage from: kpi-state/findings.json, uploaded as an artifact, and a table in the run summary listing every breach worst-shortfall-first. Nothing files a ticket automatically; that decision stays with the nightly analysis. Job status is unchanged and still fails only on a breach the previous run saw too. Failing on a single one would put the job back to red on roughly half the nights -- 20 breaches in four nights of identical code -- which is what MOD-18822 is about.
A result under its floor is a result more than 5% below the baseline, and the policy for one is red job, ticket filed, floor left alone -- first occurrence, not on the second. So the two-consecutive-runs rule and all the state it needed are gone: no Actions cache, no previous verdict to restore or save, and the check's exit code now follows directly from this run's results. What stays is the part that makes a breach actionable. redisbench-admin fails the step for a floor breach and for a benchmark that never ran with the same exit code, so telling them apart meant grepping the log; the check names each one, writes the breaches to kpi-state/findings.json with their shortfall for the nightly analysis to file from, and puts the same table in the run summary. A run where nothing measured at all still fails, so handing it the verdict cannot hide a broken harness, and json_nummultby_num_2 (MOD-18654, Won't Do, no floor) is reported as ungated rather than deciding the job. Replaying the four nights of 09-18..09-21: 09-19 and 09-21 fail with 8 and 12 breaches, 09-18 and 09-20 pass, per shard and merged. Those two nights ran the same commit as the two that passed, so the tickets filed from them are about the harness's own 22-49% spread -- MOD-18823 -- which is the thing that has to shrink for this gate to be quiet.
Since run-remote continues on error, an errored benchmark left no trace: its result file is simply absent, and absent is indistinguishable from "this shard was never given that benchmark", so a timeout or a single test error after some successes left the job green. Before this PR run-remote's own exit code covered that case. The run log is the only place that records a benchmark was meant to run and did not, so capture it (tee) and read the "Failed to run remote benchmark for test '<name>'" lines from it. Each one is a finding and fails the job, except the names passed as --known-broken -- json_nummultby_num_2 (MOD-18654, Won't Do) and nothing else. Reported by Cursor Bugbot on the PR.
Two more holes of the same shape as the last one: with run-remote under continue-on-error, anything that leaves a benchmark merely absent read as "this shard was never given it" and passed. measured() discarded the reason result_metric returns when a result file exists but cannot be used -- ambiguous duplicates, or no known throughput metric in it. That benchmark looked unmeasured and its floor was never applied; it is now reported unreadable and fails the job. A step timeout or a crash partway through leaves no log line at all for the benchmarks that never started, so the log cannot catch it. The gate now also takes run-remote's step outcome: a non-success that nothing in the log accounts for -- no breach, no failed-to-run line, not even a known-broken one -- fails the job as an incomplete run. A timeout on a night when a known-broken benchmark also errored still reads as accounted-for; closing that needs each shard's expected benchmark list, which redisbench-admin does not expose (neither i % 3 nor contiguous thirds of the sorted yml list reproduces the real 14/13/15 split). Both reported by Cursor Bugbot. Four-night replay unchanged.
The benchmark gate writes its table on each of the three shard jobs, which is not where anyone looks. The nightly summary is, and it carried only the job name: "benchmark - job failed", with no indication of which benchmark or by how much. So the summary job now restates the breaches, in the same table the benchmark job renders, and sends them to Slack as one section of their own -- a floor breach is a performance finding, not a failed test, so it does not belong folded into the failed-OS list. No new download: the existing step already pulls every artifact of the run, kpi findings included. The three shards each report the same ungated benchmark, hence unique_by. Rendered against last night's run (35780480546), the Slack section reads: *Benchmark KPI floors:* • *json_set_key_empty* - 134217 vs floor 163624 (-18%) • *json_vs_hashes_hset_key_simple* - 136977 vs floor 165889 (-17.4%) • *json_set_sclr_pass_100_json* - 116244 vs floor 129489 (-10.2%) • *json_vs_hashes_json.set_key_simple* - 133769 vs floor 135841 (-1.5%) The block is built with jq rather than interpolated into the payload format string, so a benchmark name or a percentage cannot break it, and the step output is passed in as an env var rather than expanded inside the script.
A bare `run:` gets `bash -e {0}`, without pipefail -- confirmed in the
job log of run 35780480546, `shell: /usr/bin/bash -e {0}`. So piping
run-remote into tee reported tee's exit code instead: the step would
have been `success` after any failure, and the --run-outcome guard added
in the previous commit could never fire.
`shell: bash` gives `bash --noprofile --norc -eo pipefail {0}`, so the
non-zero survives the pipe, the step outcome is truthful again, and an
incomplete run is still caught.
Reported by Cursor Bugbot.
Brings in #1643 (MOD-18654), which bounds json_nummultby_num_2 so the benchmark runs again -- the premise this branch was written against.
#1643 bounds that benchmark's multiplier, and it produced a result for the first time since at least 2026-08-09: 102,553 rps on the push-to-integ run of e1c8194. So --known-broken json_nummultby_num_2 is no longer a safety valve, it is a hole -- if that benchmark stops running again the gate would wave it through. The workflow passes no --known-broken at all now; the flag stays, unused, for the next benchmark that breaks for good. It still has no `kpis` floor, since update_kpis.py seeds one only from a run that returned a result and none had. So it is still reported as ungated, and the wording follows the reason: "no floor seeded yet" rather than MOD-18654. Seeding one is a update_kpis.py run and a PR, which it now qualifies for. Four-night replay unchanged with no exemption passed (8 and 12 breaches on 09-19 and 09-21). On the 09-23 integ run the gate reports it as "UNGATED: json_nummultby_num_2 (no floor)" -- measured, unfloored -- alongside 7 breaches, which are the sustained step-change from 09-21 (MOD-18823).
The summary only branched on the breach count, so a run whose findings held an errored or unreadable benchmark and no breach announced that every gated benchmark met its floor and sent Slack a green check -- while the shard job that produced it was red. The rows were emitted after that line without a table header, so they did not render either. Same bug for a night with only an ungated row, which is the common case. The table header now depends on there being any row at all, the rows go out in severity order, and the verdict line and the Slack bullets depend on breach *or* errored/unreadable, so a green check means all three are clear. Checked against three inputs: last night's real findings (4 breaches + 1 ungated), an ungated-only night, and a synthetic errored + unreadable run with no breach. Reported by Cursor Bugbot.
Two findings on the previous commit, both about the same blind spot: an ungated benchmark is reported by every shard, but only the shard that was given it has a number. The summary merged those copies with unique_by, which keeps whichever came first, so the nightly table and the Slack block could say "no result" for a benchmark another shard had timed. It now dedupes on (benchmark, status) preferring the copy with a measured value. This only became visible with #1643: before it, json_nummultby_num_2 had no result on any shard. And verdict() classified an unusable result before checking for a floor, so a floor-less benchmark with an unreadable result produced an UNREADABLE row with floor=None, which the summary table formats as a number -- TypeError, after findings.json was already written. Ungated is now decided first: with no floor there is nothing for an unusable result to be measured against. Covered in --self-test, which also renders the step summary for that row rather than only checking the verdict. Four-night replay unchanged. Reported by Cursor Bugbot.
Both of these are the asymmetry the previous commit fixed in the nightly summary and left in the gate's own table. An ungated benchmark is listed but is not a finding, and step_summary appended the file-a-ticket footer whenever the list was non-empty -- and with a floor-less benchmark in the set it is never empty. So a clean run told the reader to file a ticket, which on push-to-integ is the only KPI report they see. The footer now follows the rows that need a ticket, and an otherwise clean run says its floors were met. And a benchmark that failed to run was reported twice when it also had no floor: once as errored from the run log, once as ungated from the verdict, both asking for a ticket, and the nightly merge groups by (benchmark, status) so both survived. The errored row is the actionable one and now the only one. Rendered for both cases: the 09-18 artifacts produce the ungated row plus "Every gated benchmark met its floor", 09-21 produces the 12 breaches plus the footer. Reported by Cursor Bugbot.
There was a problem hiding this comment.
Cursor Bugbot has reviewed your changes using high effort and found 1 potential issue.
❌ Bugbot Autofix is OFF. To automatically fix reported issues with cloud agents, have a team admin enable autofix in the Cursor dashboard.
Reviewed by Cursor Bugbot for commit 9677bbf. Configure here.
| jq -s 'add | ||
| | group_by([.benchmark, .status]) | ||
| | map(sort_by(.measured == null)[0]) | ||
| | sort_by(-(.shortfall_pct // 0))' $FINDINGS > kpi-findings.json |
There was a problem hiding this comment.
Merge duplicates errored ungated benchmarks
Medium Severity
The nightly KPI merge dedupes on (benchmark, status), so a floor-less benchmark that failed to run still appears twice: errored from the shard that ran it, and ungated / no result from the other shards. The summary table and the “each row is worth a ticket” footer then treat both as separate findings, which is the report nightly triage files from.
Additional Locations (1)
Reviewed by Cursor Bugbot for commit 9677bbf. Configure here.


Policy this implements
A benchmark result under its
kpisfloor is a result more than 5% below itsbaseline (
update_kpis.pysets floors atmeasured × 0.95). For one of those:the job goes red, a ticket is filed, and the floor is not moved — on the
first occurrence, not on a repeat.
What was wrong
redisbench-admin checks the floors at the end of
run-remoteand exits non-zero,but one exit code carries two different findings: a benchmark came in under its
floor, or a benchmark never ran at all.
json_nummultby_num_2had errored onevery run since at least 2026-08-09, so the step was red every night regardless,
and separating a real breach from that meant grepping the log:
Nothing carried the breaches out of the run either, so filing tickets from them
meant re-reading logs per shard.
What changes
run-remotekeeps measuring but no longer owns the verdict(
continue-on-error: true); a newtests/benchmarks/check_kpis.pydoes:kpi-state/findings.json, uploaded as an artifact(30 days), and rendered as a table in the run summary — worst shortfall first,
so the nightly analysis can file from it without opening a log. Nothing is
filed automatically.
a benchmark with no floor is listed as
ungatedand does not decide the job.hide a broken harness.
No baseline is touched: the 42
kpisvalues are exactly as #1641 left them, andupdate_kpis.pycan still only raise a floor, never lower one.Updated after merging
master: #1643 fixed MOD-18654, andjson_nummultby_num_2produced a result for the first time since 2026-08-09 —102,553 rps on the push-to-integ run of
e1c81941. The gate therefore passes no--known-brokenat all: with that benchmark running, an exemption for it wouldbe a hole rather than a safety valve. It still has no floor (
update_kpis.pyseeds one only from a run that returned a result), so it is reported as
ungatedwith the reason it now has — no floor seeded yet — and it qualifies for one.
check_kpis.pyreusesupdate_kpis.py's result-file matching and floor parsingrather than repeating either, and
--self-testcovers the verdicts, thefindings output and the boundary at exactly-the-floor.
Validation
Replayed against the uploaded result artifacts of the four nightlies of 09-18 →
09-21, per shard and merged:
Findings counts match the failures (8 and 12), worst shortfalls -10.9% on 09-19
and -20.4% on 09-21.
Worth knowing what those two nights are: all four ran the identical commit
a3b2edb63, and the harness's own run-to-run spread is 22-49% for thebenchmarks above ~100k rps — wider than the 5% margin the floors sit at. On
09-21 every breached benchmark hit its own four-night minimum, and 24 of the 42
benchmarks did, which is a slow host rather than 12 slow commands. So the
tickets filed off these two nights are the record of that spread, which is
MOD-18823 — the gate cannot get quieter than the measurement it reads.
Jira: MOD-18822 (blocks MOD-18184)
🤖 Generated with Claude Code
Note
Low Risk
Changes are limited to CI workflows and a new benchmark gate script; no runtime RedisJSON or auth/data-path changes.
Overview
Benchmark CI no longer treats
redisbench-admin run-remote’s exit code as the gate: that step runs withcontinue-on-error, logs torun-remote.log(bash + pipefail), and a newCheck KPI floorsstep runstests/benchmarks/check_kpis.py, which fails the job on floor breaches, benchmarks that did not run (from the log), unreadable results, or an unexplained non-success run outcome. Findings go tokpi-state/findings.json, a job summary table, and abenchmark-kpi-findings-*artifact for triage.test-summary.ymlmerges shard findings into the workflow summary and adds a Benchmark KPI floors section to nightly Slack messages.json_nummultby_num_2is no longer exempt (MOD-18654 fixed); benchmarks without a seeded floor are reported as ungated and do not fail the job.Reviewed by Cursor Bugbot for commit 9677bbf. Bugbot is set up for automated code reviews on this repo. Configure here.