Machine-learning bugs don't crash. If slices of the same patient end up in both the training and the test set, the model can learn to recognize the patient instead of the disease. The code runs, the tests pass, and the reported score is wrong. Teams find out weeks later, after a failed reproduction, and must rerun experiments. Code review reads the diff; this bug only appears when the split runs on real data. Invariant is a code reviewer for ML correctness, built with and around IBM Bob. On a pull request, Bob (in our custom ML Reviewer mode) reads the project's study protocol, then calls Invariant's tools over MCP. Static analysis flags a risky split; Invariant then executes the project's own split function on the project's own metadata and counts patients in both sets. A deterministic report builder runs every check itself, hashes the committed protocol, data and configuration, and derives the status: blocked, review_required or no_findings. Bob explains the finding and writes the fix, but it cannot set the count, the hashes or the status. A required GitHub check runs the same builder on every pull request and blocks the merge unless there are no findings. What we demonstrated, end to end, on a public demo repository (a fully synthetic, NSCLC-inspired imaging benchmark with no patient data): 1. A normal-looking pull request: existing tests green. 2. Invariant measured 166 patients in both train and test: every test patient. 3. Report A recorded "blocked" before any code changed. 4. Bob traced the leak with two parallel subagents, wrote a patient-grouped split and four regression tests, including a Hypothesis property test. 5. On the fixed commit: 0 overlapping patients, tests passing, CI green. 6. Report B recorded "no findings" and kept the 11 previously affected training runs as history. 7. We reintroduced the bug in a new pull request: ordinary tests stayed green, Invariant failed, and the merge was blocked. Measured impact: patient-level AUC was a perfect 1.00 with the leaky split and 0.66 (seed 0), 0.62 (mean of five seeds) with a patient-independent split. Who uses it and how ML engineers and researchers whose decisions rest on an evaluation number: medical imaging teams before they publish a benchmark or submit a model, and product teams before a release. They install Invariant with one command, review pull requests with Bob as usual, and get a blocking check plus a commit-by-commit record of what was checked, what failed and what fixed it. What makes it different Measured, not guessed: the finding is a count from the real split, not a model's opinion. The evidence is deterministic and commit-bound: identical locally and in CI. The review ends in a fix and a regression test, not a comment. And it is honest about scope: every report lists what was not checked (train-only preprocessing, inference consistency), and every Bob task was verified by us with expected results fixed in advance.
Category tags: