check-split-solutions.yml
Diff-scoped check that fails a pull request which touches a split exercise whose solution was not split with it. The lab’s rule (Ezra, 2026-10-28) is that a solution is split the way its exercise is: one #sol- per #exr-, each with the slug of its exercise. It complements check-multipart-exercises, which reads only the exercise side. This implements gha#1290.
A group is the set of #exr- divs that share a slug once a trailing -partK is removed. A group with two or more exercises is split. The ids may sit in different subfiles, so the check indexes every file the globs match. In a split group it reports:
- an exercise with no
#sol-of the same slug; - a
#sol-with no exercise of that slug; - a solution that labels parts: two lettered list items in one marker style (
(a)/(b),a./b.), or a line opening “Part 2:”. A numbered list is not flagged, because it can be the answer itself; - a solution that holds a figure chunk (
#| label: fig-...or#| fig-cap) when its own exercise does not ask for a plot but a sibling exercise does. This is the case of#sol-lab-boston-simple, whose figure answered the plot exercises two parts later; - a solution whose code reports a statistic that only a sibling exercise asks for. This one is a heuristic and never blocks: it always prints a warning, even with
fail: true. It looks for a short list of terms (correlation, R-squared, residual, variance inflation, F-test, p-value, standard error, a listing of indicator columns) in the exercise text of the siblings but not of the solution’s own exercise, then looks for a call that reports the term in the solution’s code. Assignments, function definitions, imports, hidden chunks (include: false) and comments inside a function count as setup and are not read. An exercise that says “repeat ?@exr-x” is read as asking for what@exr-xasks. This is the case of the old#sol-lab-multiple, which printed the correlation that-part3asks for. Known gap: it cannot see a second model fit in the first solution (the old#sol-sign-flipfitted the model withhorsepoweradded, which-part4asks for), because that has no term to look for.
Code, display math and HTML comments are not read for part labels. A solution that holds <!-- split-solutions-ok: reason --> is exempt.
A group is reported when the pull request adds a line inside any of its divs. With no base to diff against, the check skips instead of scanning the whole tree. It fails by default; fail: false gives warning annotations only.
Inputs
| Input | Default | Meaning |
|---|---|---|
globs |
*.qmd |
Git pathspecs of tracked files to check (recursive) |
paths-ignore |
none | Comma or newline separated globs to skip |
fail |
true |
Fail on a finding; false warns |
whole-tree |
false |
Report every split group, to measure a corpus |
python-version |
3.x |
Python version |
Usage
Copy examples/check-split-solutions.yml to .github/workflows/check-split-solutions.yml.