check-unexplained-choices.yml
Diff-scoped check that fails when a binning choice in code is never explained by the prose around it. The lab’s rule (Ezra, 2026-11-03, ai-config#4905) is that every arbitrary analysis choice, such as binning a variable, is explained in detail in the prose: what was chosen, what the alternatives were, and why this one.
The check reads code lines in a fenced chunk for a binning choice: cut(), cut_number(), cut_interval(), cut_width(), pd.cut(), pd.qcut(), breaks =, bins =, binwidth =, nbins = and n_bins =. Only binning is recognized, so that the check can fail by default without flagging choices that need no reason, such as a seed in a plain simulation.
A choice is explained when the prose of its unit holds a reason word such as “because”, “chose”, “choice”, “compromise”, “rather than”, “alternative” or “arbitrary”. The unit is the outermost div around the chunk (a figure, example or exercise), or, outside any div, the text from the previous heading to the next one.
The check does not read:
- a unit whose prose holds a reason word, outside code fences, display math and HTML comments;
- a code line that starts with
#, such as a comment or a#|chunk option; - a line carrying
<!-- check-unexplained-choices: allow -->.
Whether an explanation is good is a judgment the author makes; the check asks only that one exists. Set fail: false to get warnings instead of a failing check.
Scope
Only an added line is reported. The whole file is parsed, since the explaining prose may sit far from the changed line. With no base-ref, or when the diff cannot be computed, the check skips with a warning instead of scanning the whole tree. Set whole-tree: true to scan every tracked file on purpose, which measures how many existing choices go unexplained.
Usage
Copy examples/check-unexplained-choices.yml to .github/workflows/ in your repository.
Inputs
| Input | Default | Meaning |
|---|---|---|
globs |
*.qmd |
Space-separated git pathspecs of tracked files to check |
paths-ignore |
empty | Comma- or newline-separated glob patterns to skip |
fail |
true |
Fail the workflow on a finding; false warns instead |
whole-tree |
false |
Scan every choice, not only a pull request’s additions |
runs-on |
empty (CI_RUNNER variable, else ubuntu-latest) |
Runner label; self-hosted only for a private repository |
python-version |
3.x |
Python version to set up |
Permissions
The job needs contents: read only.
Example
name: Check for unexplained analysis choices
on:
pull_request:
jobs:
check:
uses: Morrison-Lab/gha/.github/workflows/check-unexplained-choices.yml@v3
with:
paths-ignore: 'chapters/outtakes/**'