Measure everything that ships, and notice the 300-line cap filling up - #406
Merged
Conversation
Two gates whose SCOPE was wrong rather than whose logic was. [tool.coverage.run].source was ["backend", "graphlink_plugins"], while [tool.setuptools] ships four packages and 23 loose root modules. Two shipped packages - provider_runtime and settings_store - and every root module, api_provider.py among them, sat outside the 85% floor entirely. A file nothing measures can regress to zero with the gate still green. Widening it takes the measured set from 18,763 statements to 21,606 and lands at 85.53%, so the floor holds unchanged. provider_runtime is the weak spot now inside it (ollama_scan 8%, llama_cpp_scan 10%, gemini_transport 29%) and that is the point: those numbers were invisible before, and a regression in them now counts. The root modules are listed WITHOUT a .py suffix. coverage's `source` takes packages and directories and silently ignores anything else - the first version of this change wrote "api_provider.py" and measured exactly nothing new, the statement count sitting at 18,763 while the config looked correct. Caught by comparing the count, not by reading the file. Both lists are hand-maintained in the same file, which is the shape this repo keeps getting bitten by, so tests/test_coverage_scope.py compares them in both directions: every shipped thing is measured, nothing measured is unshipped or nonexistent. Separately, the 300-line register* cap: four functions sit within 17 lines of it (294, 290, 285, 283). A cap everything sits just under binds on whoever next touches one of those functions, for a reason unrelated to their change - the same erosion check-bundle-size.mjs kept suffering. The gate now fails on a FIFTH function entering that band rather than on the four already there, since splitting a 294-line registration function is work to schedule, not to force. Lower the recorded count as they are split; never raise it. Test plan: - CI coverage command, with the widened source: 21,606 statements, 86%, "Required test coverage of 85.0% reached. Total coverage: 85.53%", 3202 passed. - 4 new coverage-scope tests, 1 new cap-headroom test. - ruff and mypy both clean. Worth stating why that mattered here: the first pass at this replaced ".py" suffixes globally in pyproject and silently corrupted three unrelated sections - mutmut's source_paths, mypy's files list, and ruff's api_provider.py per-file-ignore, which is what surfaced it. All three are back to file paths; only the coverage list uses bare names. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Problem
Two gates whose scope was wrong rather than whose logic was.
The coverage floor measured half the product
[tool.coverage.run].sourcewas["backend", "graphlink_plugins"], while[tool.setuptools]ships four packages and 23 loose root modules. Two shipped packages —provider_runtimeandsettings_store— and every root module,api_provider.py(954 statements) among them, sat outside the 85% floor entirely.A file nothing measures can regress to zero with the gate still green.
The 300-line register* cap has four functions crowding it
A cap everything sits just under binds on whoever next touches one of those functions, for a reason unrelated to their change — the same erosion
check-bundle-size.mjskept suffering.Change
Coverage widens to every shipped package plus every shipped module. Measured set goes from 18,763 → 21,606 statements, landing at 85.53%, so the floor holds unchanged:
provider_runtimeis the weak spot now inside it (ollama_scan8%,llama_cpp_scan10%,gemini_transport29%) and that is precisely the point — those numbers were invisible before, and a regression in them now counts.The root modules are listed without a
.pysuffix.coverage'ssourcetakes packages and directories and silently ignores anything else; the first version of this change wrote"api_provider.py"and measured exactly nothing new, the statement count sitting at 18,763 while the config looked correct. That was caught by comparing the count, not by reading the file.Both lists are hand-maintained in the same file, so
tests/test_coverage_scope.pycompares them in both directions: every shipped thing is measured, and nothing measured is unshipped or nonexistent.The cap gate now fails on a fifth function entering the 30-line band rather than on the four already there — splitting a 294-line registration function is work to schedule, not to force on an unrelated change. Lower the recorded count as they are split; never raise it.
Test plan
ruffandmypyboth clean — and worth stating why that mattered here. The first pass at this replaced.pysuffixes globally inpyproject.tomland silently corrupted three unrelated sections: mutmut'ssource_paths, mypy'sfileslist, and ruff'sapi_provider.pyper-file-ignore. The ruff failure is what surfaced it. All three are back to file paths; only the coverage list uses bare names.🤖 Generated with Claude Code