perf(ci): gate the statusline bench lanes behind BENCH_LANES - #4178
Conversation
plugins/rate-limit-guard/bench/bench.test.sh spawned bench-idle.sh, bench-load.sh and trace-probe.sh on every contract-corpus run, which is a benchmark run whatever the parameters and the only part of that suite that spends real wall-clock seconds. BENCH_LANES=1 now runs them; an ordinary run stops after the lib assertions and reports the lanes as deferred, the same shape lib/hook-utils.test.sh uses for its clock comparisons. The clean-checkout runnability guard (#2582) moves from every pull request to the new weekly bench-harness workflow, which sets the variable, plus workflow_dispatch for a deliberate run. Advisory like hook-utils-timing: outside ci-status, blocking no merge. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01XwY46aTKXzw9wrLhVC1Azz
The first commit here added a weekly bench-harness workflow to run the gated lanes. #4173 deleted the two workflows of exactly that shape three commits ago, under the owner direction to delete stale and overengineered automation, and hook-utils-timing was deleted for having two runs nobody read. A new scheduled advisory lane would be the same thing again. So ci.yml gains a workflow_dispatch `bench_lanes` input instead, threaded into the contract-test step as BENCH_LANES. Nothing runs on a schedule, nothing goes unread, and the lanes still have a deliberate CI run. The deferral now prints a SKIP line rather than counting an ok, so the runner's aggregate names the coverage that did not run instead of reading as a full pass. bench/README.md describes the split, and the plugin takes a version bump with its changelog entry. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01M98vWnd3jQJ19Pe6Uj7bV9
Codex Review SummaryThis comment shows the latest Codex review activity on this pull request.
ℹ️ About Codex in GitHubYour team has set up Codex to review pull requests in this repo. Reviews are triggered when you
Codex reacts with 👀 while any review is running, comments if it has suggestions, and reacts with 👍 once all reviews finish with no findings. |
|
Claude finished @kyle-sexton's task in 4m 13s —— View job Code review complete
FindingsNo blocking or high-signal issues found. Traced the logic the PR body describes and confirmed it holds:
Not independently verified: I was unable to execute shell commands in this sandbox ( |
|
Claude finished @kyle-sexton's task in 47s —— View job Security review — PR #4178
Result: no security-relevant surface. Reviewed all 6 changed files (
This falls under the skip gate ("change has no security-relevant surface after reading the diff"), so no findings to report. GitHub Actions hardening concerns (if any) are zizmor's lane, not this one, and none of the above rise to needing that reasoning anyway. |
|
Last security-reviewed head: |
|
Claude has reviewed this PR 1 time. The lane skips further automatic reviews after 5; deleting this comment resets the count. |
…ment The reason stands on its own: a scheduled lane of their own would be unread advisory automation outside ci-status. Who deleted the last two, and when, is git history. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01M98vWnd3jQJ19Pe6Uj7bV9
|
After-number, from this pull request's own run (34976006943, head
0.019 s, against a 1.157 s median before (the three most recent successful One caveat on the comparison, because the two numbers come off different code paths. A pull request runs The job totals are not a comparison and are not offered as one. This run's step ran 46 selected suites in 227 s on that leg; the |
No related issue: acceptance criterion 2 of the CI performance program, tracked in melodic-software/github-iac#378; no issue in this repository owns it.
Summary
Acceptance criterion 2 requires this repository's
ci.ymlto keep benchmarks "gated behind an env var". Nothing gated them.plugins/rate-limit-guard/bench/bench.test.shis in the contract corpus, so both runner paths —scripts/run-plugin-tests.shon a push andscripts/affected-tests.sh --runon a pull request — spawned all three benchmark lanes (bench-idle.sh,bench-load.sh,trace-probe.sh) whenever the suite was selected.BENCH_FLOOR_Nis the spawn-count knob those lanes read, not a gate: the suite exports it itself and the lanes run either way.Fix
BENCH_LANESgates the lane runs inside the suite, atplugins/rate-limit-guard/bench/bench.test.sh:106, after thelib-bench.shassertions and before the first lane spawn. Unset, the suite runs its eight pure-function cases and stops. Set, it runs all thirteen.The gate is in the test script, not in the serial list or the job step, because the script is the only place both runner paths pass through.
run-plugin-tests.shdiscovers the suite by glob andaffected-tests.shselects it independently; both then runbash "$suite"with the environment inherited. The serial list chooses serial-versus-parallel, not whether a suite runs, and an entry there naming no discovered suite is an error. A gate in theci.ymlstep would have to carve one path out of a glob the runner owns, and would leave the pull-request selector path ungated.No new workflow. The first commit on this branch added a weekly
bench-harness.ymlto run the gated lanes. #4173 deleted two workflows of exactly that shape three commits ago, under the owner direction of 2026-09-14 to delete stale and overengineered automation, andhook-utils-timing.ymlwent specifically for having had two runs nobody read. Adding another scheduled advisory lane would be the same thing again, so the second commit removes it. The deliberate CI run is aworkflow_dispatchinput onci.ymlinstead:bench_lanes, threaded into the contract-test step asBENCH_LANES: ${{ inputs.bench_lanes && '1' || '' }}. Nothing runs on a schedule and nothing goes unread; the lanes run when someone asks for them, over the full corpus a dispatch already runs.The deferral is a
SKIP:line, not anok.run-plugin-tests.shreads^SKIP:and names the suite under "Suites with skipped coverage (exit 0 here is NOT evidence those cases ran)", which is exactly what this is: five cases that did not run. Counting it as a pass would make the aggregate read as full coverage.--strict-skipsconsequently fails on the suite, which is correct: a caller declaring a fully provisioned environment is asking for every case to run, andBENCH_LANES=1is how it gets them. No CI lane passes that flag.What this costs. That suite is the guard that the harness still runs from a clean checkout — the defect behind the unreproducible measurements in #2521. On an ordinary pull request that guard is now the lib-helper half plus repo-wide ShellCheck; the end-to-end half runs on a dispatch. The benchmark is not deleted and loses no capability.
scripts/run-plugin-tests-serial.txtkeeps its entry, with the reason rewritten: an ordinary run no longer needs a serial seat, but aBENCH_LANES=1run does, and that is when the lanes measure exactly what contention distorts.bench/README.mddescribes the split, and the plugin takes a version bump with its changelog entry.Verification
Local, in a clean worktree off
origin/main:bash plugins/rate-limit-guard/bench/bench.test.sh:PASS=8 FAIL=0withSKIP: bench lanes deferred, exit 0, 0.6 s.BENCH_LANES=1 bash plugins/rate-limit-guard/bench/bench.test.sh:PASS=13 FAIL=0, every lane case executed, 4.6 s.shellcheck -xandshfmt -dclean on the suite;actionlintandzizmor --persona=regularclean onci.yml;markdownlint-cli2clean on both changed markdown files, which are onscripts/em-dash-purged-paths.txtand gained no em dash.bash scripts/run-plugin-tests.test.sh:PASS=67 FAIL=0, including the case proving every serial-allowlist entry names an existing suite.bash scripts/check-lane-coverage.sh --checkandbash scripts/check-docs-only-gate.sh --check: clean.scripts/check-changelog-parity.shpasses--check,--check-bump origin/mainand--check-preserved origin/main.SKIP:line" paragraphs record. It re-verified the branch afterwards.Measured effect, from real runs rather than from the local numbers above. The suite always lands on
test-linux (1): it is index 217 of 347 discovered suites and 217 mod 4 = 1. Across the three most recent successfulpushruns ofci.ymlonmain(34939066292, 34930491268, 34925496845) its elapsed time inside the serial phase, measured from the preceding serial suite's terminalPASS:line to its own, was 1.170 s, 1.133 s and 1.157 s: median 1.157 s. The mediantest-linux (N)wall time across all twelve legs of those runs is 170 s.So the honest size of this change is about one second on one leg of a 170-second job, inside that job's run-to-run noise. It is worth having for the criterion and for what it stops — wall-clock lanes spawning on shared runners on every pull request that touches the plugin — and this body claims no throughput win. The after-number from this pull request's own run is posted as a comment once it lands, measured the same way.
Related
Refs: melodic-software/github-iac#378
Refs: #4173
Refs: #2582
Refs: #2521
🤖 Generated with Claude Code
https://claude.ai/code/session_01M98vWnd3jQJ19Pe6Uj7bV9