Onboarding OpenHands.
Running sm refit on a production platform of ~322k lines. The result was mostly a baseline rather than a clean-up.
OpenHands is a massive developer assistant platform. Onboarding its primary repository (300k+ lines of Python) to slop-mop required running sm refit to review all quality gates, establish baseline configurations, and execute step-by-step code remediation.
| Repository | OpenHands/OpenHands |
|---|---|
| Codebase Size | ~322,000 lines |
| Language | Python, TypeScript |
| Initial State | Unvalidated (Onboarding) |
| Final State | scour_clean (Maintenance Mode Active) |
| Remediation PR | PR #14719 |
| Barnacles filed (against ourselves) | #263, #264 |
Onboarding Findings & Remediation
Running sm refit --start analyzed the project across all active checks, identifying findings in 7 different quality gates. The remediation path involved target refactoring alongside precise scoping configuration to lock down the codebase.
-
Gate 1 ยท Deceptiveness: Bogus Tests
“Python test files starting with
test_contained mock fixtures namedtest_clientwith no assertions. They were flagged as false-positive passing tests since they asserted no behavior.”Remediation: Renamed helper fixtures from
test_clienttoclientacross all unit test suites, and added explicit assertions to helper validation routines. -
Gate 2 ยท Overconfidence: Missing Annotations
“Strict type checking flagged thousands of missing parameter and return annotations across legacy abstract factory classes.”
Remediation: Added targeted
# type: ignoreannotations for dynamic abstract imports and configuredstrict_typing: falsescoped to core directories in.sb_config.jsonto prevent noise while preserving main type safety. -
Gate 3 ยท Myopia: Action Hygiene
“A manifest builder job in
_build-image.ymlcalledactions/checkoutwithout explicitcontents: readpermissions.”Remediation: Patched the GitHub Actions workflow permission blocks to explicitly grant read-only token permissions, securing the action checkout loop.
-
Gate 4 ยท Overconfidence: Type Blindness
“Strict pyright checking identified optional member access warnings (potential
Noneattribute access) on serialization models and Litellm imports.”Remediation: Added targeted
# type: ignore[reportOptionalMemberAccess]comments on optional fields, simplified import blocks, and resolved import-untyped risks. -
Gates 5 & 6 ยท Myopia: String Duplication and Code Sprawl
“FastAPI query docstrings, large mock databases, and massive legacy service modules (some up to 1,700 lines) tripped length thresholds.”
Remediation: Configured
.sb_config.jsonto exclude test suites, scripts, and frontend directories from sprawl checks, and raised thresholds to lock in the legacy baseline length parameters. -
Gate 7 ยท Overconfidence: Coverage Gaps
“Baseline project coverage check failed because the legacy codebase is at 49% coverage, falling short of the default 80% limit. Two sandbox port mapping tests were also failing.”
Remediation: Set
threshold: 49in the configuration to freeze the baseline and prevent future regressions. Corrected the sandbox unit tests to assert string mappings for Docker ports rather than integer ports.
What was actually fixed โ versus baselined
The findings above use the word “remediation” loosely. The split for a 400+-file PR whose bulk was reformatting: a small amount of fixing, and a large amount of accepting the existing state and guarding against regressions from there.
| Genuinely fixed | GitHub Actions least-privilege (contents: read); a Docker sandbox test corrected (port-map keys int → str, and a hardcoded /tmp path swapped for tempfile.gettempdir()); and duplicate pagination Query() titles extracted to shared constants across 11 routers (see the second pass below). A small, real set of changes โ not a 322k-line clean. |
|---|---|
| Suppressed | 61 # type: ignore / # noqa markers added โ the type and lint gates were silenced, not satisfied. |
| Baselined (Python) | Coverage frozen at the existing 49%; strict_typing: false and strict: false downgrade the strict-typing and type-blindness gates. |
| Scoped out | The TypeScript front-end gate suite (formatting, dead-code, type-checking, bogus-tests) and three meta-gates โ including gate-dodging and silenced-gates, the gates that flag suppression โ are disabled in the committed config. The green board below is the Python core, not the whole repo. |
Read the green board that follows with that in mind: it is real, but it is the score for a deliberately scoped, baselined Python surface โ not a claim that 322k lines got cleaned.
$ sm status ๐ชฃ sm status โ Project Status Check ๐ Project: OpenHands ๐ง State: scour_clean โจ MAINTENANCE MODE ACTIVE ยท 20/20 checks passed โ myopia:dependency-risk.py (passed) โ myopia:github-actions-hygiene (passed) โ myopia:ambiguity-mines.py (passed) โ deceptiveness:bogus-tests.py (passed) โ laziness:complexity-creep.py (passed) โ laziness:dead-code.py (passed) โ laziness:debugger-artifacts (passed) โ overconfidence:coverage-gaps.py (passed) โ overconfidence:missing-annotations.py (passed) โ overconfidence:type-blindness.py (passed) โ deceptiveness:gate-dodging (passed) โ laziness:silenced-gates (passed)
Executing sm status on OpenHands reports a clean slop-mop board (a dozen of the twenty shown) โ slop-mop's own gate suite, now with the gate-dodging and silenced-gates meta-gates re-enabled in the second pass. That is a separate scoreboard from OpenHands' native CI; getting that green took the reconciliation in the ledger below โ and as of this writing it is, with the PR passing every check and blocked only on a maintainer's review.
A second pass, looking for missed slop
We went back and looked for slop hiding behind the baseline. Little turned up. That is weak evidence either way: it is consistent with the code being in good shape, and also with our not having looked in the right places.
- The Python core is clean. Zero committed debugger artifacts; the lightweight, host-independent gates find essentially nothing to fix.
- Two meta-gates went back on.
gate-dodgingandsilenced-gatesboth pass on this repo, so the baseline config isn't gaming the gates and no Python gate is muted. They are enabled again, asserting exactly that on every run. - One genuine finding, fixed and verified. Tightening
string-duplicationsurfaced the same FastAPI paginationQuery()titles copy-pasted ~13× each across 11 routers โ real duplication. We installed OpenHands’ toolchain, extracted them to shared constants in the existingpaging_utils.py, and confirmed no behavior change (1,172 app-server and OpenAPI-schema tests still pass). With the duplication gone, the gate’s threshold drops from the baselined20back to4โ a real tightening, earned by a real fix, not a config dial.
OpenHands runs its own eslint, tsc, ruff and mypy, all green, so much of what slop-mop downgraded overlapped with checks the host already ran, or was stricter than them. That is the strongest statement the evidence supports; it does not establish that nothing was missed. Raising the 49% coverage floor is left to the OpenHands team.
What went wrong
The board above is slop-mop's own gates. Getting OpenHands' native CI to pass โ its ruff lint and its migration checks โ took real work, and slop-mop made genuine mistakes getting there. We hold ourselves to the same standard we ask of our users: when the tool creates friction, file a barnacle. Here are the ones this case study produced, against our own repo.
-
Misstep ยท It rewrote immutable migrations
refit ran its formatters over 94 applied database migrations in
enterprise/migrations/versions/. Applied migrations are historical records โ they must never be reformatted. The change was simply wrong, and it tripped OpenHands' migration-check CI on top of it.Cost & fix: all 94 files were reverted to upstream. Filed as barnacle #263 โ refit must exclude
migrations/and other immutable or generated trees from formatting. Still open at the time of writing. -
Wasted work ยท It double-formatted a repo that already had a formatter
OpenHands already pins
ruff(v0.12.5 / v0.4.1). refit reformatted 417 files with its own formatters anyway โ and ruff promptly disagreed, demanding 139 fixes and 32 reformats. The work had to be redone with the host's ruff, partially undoing slop-mop's. Net result: churn, spent tokens, and a red lint board until it was reconciled by hand.Cost & fix: OpenHands' own ruff hooks were run and committed. Filed as barnacle #264 โ when a repo pins a formatter, refit should defer to it, not fight it.
-
Framing ยท "Maintenance Mode" is not "your CI is green"
A 20/20 slop-mop board means slop-mop's gates pass. It does not mean OpenHands' native pipeline passed โ that needed the two fixes above, plus keeping the branch synced with a fast-moving
main. Onboarding earns you a baseline; it does not hand you a green host pipeline for free.Takeaway: the slop-mop board and the host's CI are two separate scoreboards. PR #14719 shows both.