๐Ÿชฃ slop-mop

← All case studies

rulebook-ai, cold.

Running sm refit on a repo that had never heard of us, and publishing whatever fell out.

The first run covered a 322k-line codebase and produced mostly baselining. So we ran the opposite experiment: a small repo, picked from the wild, that had never heard of us โ€” botingw/rulebook-ai, ~8.5k lines of Python. No coordination with the maintainer, no cherry-picking, nothing pre-cleaned. Run sm refit and publish whatever falls out.

Repository botingw/rulebook-ai โ€” a CLI for composable AI rule packs
Scanned scope 63 files ยท 8,473 lines (plus 201 Markdown files of distributed rule packs)
Language Python
Starting grade 8 gates failing ยท 155 raw findings ยท 6 passing
Final grade A+ โ€” shipshape ยท 0 findings ยท 21 gates passing
Their test suite 56 passing at the merge-base ยท 81 passing at the end (25 added). Three were failing in between, from a regression of ours; see the ledger.
Remediation 22 commits ยท 69 files ยท +3,431/−1,871, on a branch we control. Not offered upstream, so none of it has been reviewed by the maintainer.
Barnacles filed (against ourselves) 4 more, all fixed in PR #332 โ€” plus 6 in #331 from the same run

Two latent crashes

The type gates surfaced two latent crashes. Both raise at runtime given the right input, rather than being style complaints.

A retired CI action, and two setup blockers

github-actions-hygiene opened with 23 findings, and one of them was not hygiene at all: the workflows still called actions/upload-artifact@v3, which GitHub retired. Their pipeline had been failing on that since September 2025. We pinned the actions to SHAs and moved to v4 on our branch, which fixes it there. Their CI is still failing, because we have not offered the branch upstream — the fix exists only in our copy.

The same pass found grpcio==1.71.0 pinned exactly, which has no wheel for Python 3.14 and fails to compile from source, and a [tool.pytest] block whose addopts was a string where current pytest requires a list — the suite would not start until that was fixed. Both block a fresh checkout.

What was actually fixed โ€” versus baselined

The equivalent table for OpenHands records mostly baselining. This run's split is different.

Genuinely fixed Two latent crashes; 13 mypy errors; 18 pyright unknown-type errors resolved by giving yaml.safe_load a typed boundary rather than silencing it; 12 broken documentation links; a 111-line create_parser() split along the seams its own comments already marked; the retired CI action; the uninstallable pin; the config that stopped pytest booting; stubs declared for a dependency that was already required at runtime; and 25 new tests.
Suppressed 9 markers total. Seven are pragma: allowlist secret on the literal string "not-needed" โ€” a placeholder API key in distributed template files, copied verbatim into seven packs. One # nosec, attached to a URL-scheme check that actually validates. One # noqa for reaching at a private argparse type. For contrast, case study #1 added 61.
Baselined Coverage, and only coverage. sm init wrote an 80% threshold; the repo measures 40%. Rather than gate on a bar it has never met, the threshold records where it actually stands and just-this-once requires ≥80% coverage on changed lines โ€” so every future PR has to move the number up rather than sideways.
Scoped out The tool_starters and vscode-extension trees, excluded from six gates. These are template packs copied byte-for-byte into user projects, so the same file gets analysed once per copy โ€” pyright reported 555 errors that were really 18, repeated. This is a judgement call: the excluded code is real code that ships to users, and it is no longer checked.
Not compromised strict_typing and pyright strict are both still true and both pass, so the typing gates were satisfied rather than downgraded. gate-dodging and silenced-gates are enabled and passing.
rulebook-ai โ€” sm scour
$ sm scour --no-cache

   โœ… myopia:dependency-risk.py         (passed)
   โœ… myopia:github-actions-hygiene     (passed)
   โœ… myopia:ambiguity-mines.py         (passed)
   โœ… myopia:string-duplication.py      (passed)
   โœ… myopia:code-sprawl                (passed)
   โœ… myopia:just-this-once.py          (passed)
   โœ… myopia:interactive-assumptions    (passed)
   โœ… overconfidence:missing-annotations.py  (passed)
   โœ… overconfidence:type-blindness.py  (passed)
   โœ… overconfidence:untested-code.py   (passed)
   โœ… overconfidence:coverage-gaps.py   (passed)
   โœ… overconfidence:dangling-references (passed)
   โœ… laziness:sloppy-formatting.py     (passed)
   โœ… laziness:repeated-code            (passed)
   โœ… laziness:dead-code.py             (passed)
   โœ… laziness:complexity-creep.py      (passed)
   โœ… laziness:debugger-artifacts       (passed)
   โœ… laziness:broken-templates.py      (passed)
   โœ… laziness:silenced-gates           (passed)
   โœ… deceptiveness:bogus-tests.py      (passed)
   โœ… deceptiveness:gate-dodging        (passed)

โœจ NO SLOP DETECTED ยท 21 checks passed
   โš“ hull rating: A+ โ€” shipshape ยท 0 findings

The finishing board, run uncached. Twenty-one gates, including gate-dodging and silenced-gates.

Friction that was not a bug

Things that made the run slower without being defects in either codebase. They are listed because they are what the process actually cost, and none of them appear in a grade.

What went wrong

Four of the items below are defects in slop-mop. Two are mistakes we made in their code.