feat(ci): nightly flake detection — N-run failure rates + serial/parallel divergence - #271
Open
raphaelvigee wants to merge 3 commits into
Open
feat(ci): nightly flake detection — N-run failure rates + serial/parallel divergence#271raphaelvigee wants to merge 3 commits into
raphaelvigee wants to merge 3 commits into
Conversation
raphaelvigee
force-pushed
the
raphaelvigee/w6-flake-detection
branch
2 times, most recently
from
July 30, 2026 08:39
5acd637 to
5f0ebf2
Compare
…llel divergence Four separate agents each burned time proving someone else's flake wasn't theirs, and master itself went red on one, because flakiness was folklore with no numbers behind it. `heph tool flake-report` parses repeated `cargo test` runs and reports per-test failure rates; the nightly workflow runs the suite 20x on Linux+macOS, aggregates, and also diffs one parallel run against a serial (`--test-threads=1`) run to flag tests coupled to process-wide global state — the root cause behind two of the five flakes. Mutation testing (item 3) is skipped: cargo-mutants reruns the suite per mutant, and this workspace's compile times (18min cold, ~40s warm, observed here) make even PR-scoped mutation testing expensive enough to risk shipping the other two pieces badly rather than well.
code-quality + feature-quality review of the initial commit surfaced three real bugs and confirmed the tool's own test coverage had gaps identical in kind to the problem it exists to solve: - The nightly workflow's --fail-on-flake never actually failed the job: `heph tool ... | tee -a "$GITHUB_STEP_SUMMARY"` under `set -e` (no pipefail) reports the pipeline's exit status as tee's, not heph's. Added `set -o pipefail`; reproduced the swallow and the fix live before committing. - Doctest results (`Doc-tests <crate>`, no `Running ` line of its own) were silently misattributed to whichever integration-test binary ran last — the exact class of misattribution bug this tool was built to prevent. parse_run now recognizes the `Doc-tests` header. - "Consistently failing" only checked failed == seen, not seen == total runs — a test only reached in 2 of 20 runs (because an earlier test aborted the process) could be labelled "broken every run" on 2 samples. Added has_reduced_visibility/is_consistently_failing and a markdown section surfacing partial-visibility tests instead of overstating them. - The serial-vs-parallel divergence check compared a single parallel log against the serial run, so an intermittent-under-parallel test had a good chance of passing in the one sampled run and never showing up as divergent. It now diffs against the already-computed 20-run aggregate. Also: execute()'s CLI entrypoint had zero test coverage (empty dir, --json-out, --fail-on-flake gating, subdirectory skip), and the <binary>::<name> collision key had no test proving two same-named tests in different binaries don't collide — both added. Plus workflow hygiene: r2-secret for warm sccache, retention-days on scratch/report artifacts, an honest "Build test binaries" step that actually builds them, zero-padded run-log filenames, and a stated (not silent) linux/arm64 exclusion from the matrix.
…rate heph tool flake-report shipped in every user's install of the heph binary for something that has nothing to do with building or running targets — it exists solely for this repo's own nightly CI. Moved the tool to a standalone crate (crates/flake-report) with its own tiny binary, dropped the heph-tool-subcommand wiring, and pointed the nightly workflow at the new binary directly (cargo build -p flake-report; ./flake-report --logs-dir ... instead of heph tool flake-report --logs-dir ...). No behavior change: same parsing/aggregation logic, same 14 tests (moved as-is), same CLI flags. Added the crate to the workspace member list and to devenv.nix's qualityCrates so lint/fmt still cover it.
raphaelvigee
force-pushed
the
raphaelvigee/w6-flake-detection
branch
from
July 30, 2026 09:40
5f0ebf2 to
bcd4e08
Compare
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Five distinct flakes surfaced in one day, and the real cost was misattribution: four separate agents each spent significant time proving someone else's flake wasn't theirs, and master itself went red on one. This builds the detection that would have prevented that, in priority order:
heph tool flake-report+.github/workflows/flake-detect.yml). Parses the defaultcargo testtext output (no nightly-only--format json— this workspace pins stable Rust) across N repeated runs and reports, per test, how many runs it failed — a flake is now a number, not folklore. Runs on Linux + macOS nightly (schedule +workflow_dispatch), reporting via step summary + JSON artifact.--test-threads=1and diffs it against the 20-run parallel aggregate: a test that fails under parallel execution but never serially is coupled to process-wide global state — the root cause behind two of the five flakes.Advisory by default — it reports, it doesn't gate
master.fail_on_flake: trueon a manual dispatch makes it fail instead.Review
Ran independent code-quality and feature-quality passes against the first commit. Both surfaced real, non-cosmetic bugs, all fixed in the second commit:
--fail-on-flakenever actually failed the job (set -ewithoutpipefailswallows a piped command's exit code) — reproduced live, fixed.execute()'s CLI entrypoint (empty dir,--json-out,--fail-on-flakegating, subdirectory skip), and the<binary>::<name>collision key.Test plan
cargo test -p heph --lib flake_report— 14 tests, all greencargo clippy --all-targets --locked -- -D warningsand--all-featuresvariant, both clean (workspace root, not-p)cargo fmt --checkcleancargo test --workspace --exclude bin-e2e --no-runcleanflake-detect.ymlon CI (can't run a GitHub Actions schedule locally)🤖 Generated with Claude Code
https://claude.ai/code/session_01UbF42bJh9F15S9BmeEfcTY