mirror of
https://github.com/hanzoai/tasks.git
synced 2026-10-04 02:04:03 +00:00
## What changed? Added a Bayesian commit bisect analysis to the `flakereport` tool that automatically identifies which commits most likely introduced test flakiness. Inspired by this Python tool: https://github.com/hauntsaninja/git_bayesect Sample run of the report can be found [here](https://github.com/temporalio/temporal/actions/runs/23914956307). This change uses the set of test runs which are mapped to commit history to infer with Bayesian statistics the probability that a commit introduced a flaky test or tests. There is a fuller explanation in `doc.go`. A tl;dr: The algorithm ranks each commit (as a transition) in the history by assigning equal p_before and p_after and using a Beta-Binomial marginal likelihood to determine the posterior probability. There is a heuristic to lower the prior probability for commits that only touch documentation or ci configuration. ## Why? This can help us identify the actual commit that introduced a problem and also help us get commit authors to validate their work instead of engineers without all of the context for a change. ## How did you test it? - [ ] built - [X] run locally and tested manually - [ ] covered by existing tests - [ ] added new unit test(s) - [ ] added new functional test(s) ## Potential risks Minimal, reporting only
77 lines
3.8 KiB
Go
77 lines
3.8 KiB
Go
// Package flakereport implements Bayesian commit bisection for identifying which commit
|
||
// most likely introduced a flaky test in a CI system.
|
||
//
|
||
// # Problem
|
||
//
|
||
// A flaky test is one whose failure probability changes at some point in the commit
|
||
// history — typically because a code change introduced a race condition, timing
|
||
// sensitivity, or environmental dependency. Given a rolling window of CI runs (each
|
||
// associated with the HEAD commit at the time), we want to rank candidate commits by
|
||
// their posterior probability of being the "transition commit" that caused the flakiness.
|
||
//
|
||
// # Data
|
||
//
|
||
// The raw input is a set of test runs downloaded from GitHub Actions artifacts. Each run
|
||
// records whether a specific test passed or failed, and is tagged with the workflow RunID.
|
||
// RunIDs are mapped to commit SHAs via the GitHub Actions API (WorkflowRun.HeadSHA).
|
||
// Runs are then grouped into CommitObservation records: for each (test, commit SHA) pair
|
||
// we count the number of passing and failing runs.
|
||
//
|
||
// # Model
|
||
//
|
||
// The inference model assumes exactly one transition commit c in the history:
|
||
//
|
||
// - Before commit c: the test has a background failure probability p_before.
|
||
// - At commit c and all later commits: the test has an elevated failure probability p_after.
|
||
//
|
||
// Neither p_before nor p_after is known, so both are assigned independent uniform (Beta(1,1))
|
||
// priors. The model treats them as nuisance parameters and marginalizes them out, yielding
|
||
// the Beta-Binomial marginal likelihood:
|
||
//
|
||
// P(data | transition at c) = BetaBinomial(n_before, k_before; 1, 1)
|
||
// × BetaBinomial(n_after, k_after; 1, 1)
|
||
//
|
||
// where n_before / k_before are the total runs / failures before commit c, and n_after /
|
||
// k_after are the total runs / failures at and after commit c. The closed form is:
|
||
//
|
||
// BetaBinomial(n, k; α, β) = Beta(k+α, n-k+β) / Beta(α, β)
|
||
//
|
||
// All arithmetic is performed in log-space to avoid floating-point underflow, with the
|
||
// log-sum-exp trick applied during normalization.
|
||
//
|
||
// # Commit Priors
|
||
//
|
||
// The prior probability that a given commit is the transition commit is not uniform across
|
||
// all commits. Commits that only touch documentation, CI configuration, or test files
|
||
// cannot plausibly affect production code behaviour, so they receive a reduced prior weight
|
||
// (down to 0.05×). Commits that touch source code receive the default weight of 1.0.
|
||
// These heuristic weights are fetched from the GitHub API in parallel and applied before
|
||
// running the inference.
|
||
//
|
||
// # Inference Algorithm
|
||
//
|
||
// For N commits with observations, the algorithm runs in O(N) time using prefix sums:
|
||
//
|
||
// 1. Compute prefix sums of failures and passes across the commit sequence.
|
||
// 2. For each candidate transition commit i, use the prefix sums to split the data into
|
||
// "before" and "after" segments and evaluate the log marginal likelihood.
|
||
// 3. Add the log prior weight to each log-likelihood.
|
||
// 4. Normalize via log-sum-exp to obtain posterior probabilities that sum to 1.
|
||
//
|
||
// # Output
|
||
//
|
||
// Commits are ranked by posterior probability. Only commits above a configurable minimum
|
||
// probability threshold (default 0.50) are reported. Results are surfaced in the GitHub
|
||
// Actions step summary, a markdown report artifact, and optionally a Slack message
|
||
// listing the "hottest" commits (those with the highest aggregate posterior probability
|
||
// across all analyzed tests).
|
||
//
|
||
// # Limitations
|
||
//
|
||
// The model assumes a single transition in the observed window. If multiple commits each
|
||
// contributed independently to flakiness, or if the failure rate oscillates, the model
|
||
// may identify the wrong commit or produce a diffuse posterior with no strong suspect.
|
||
// The model also requires a minimum of 5 failures and 30 total runs before it will
|
||
// attempt bisection on a test, to avoid over-fitting noisy data.
|
||
package flakereport
|