Skip to content

Measure everything that ships, and notice the 300-line cap filling up - #406

Merged
dovvnloading merged 1 commit into
mainfrom
fix/coverage-scope-and-cap-headroom
Sep 4, 2026
Merged

Measure everything that ships, and notice the 300-line cap filling up#406
dovvnloading merged 1 commit into
mainfrom
fix/coverage-scope-and-cap-headroom

Conversation

@dovvnloading

Copy link
Copy Markdown
Owner

Problem

Two gates whose scope was wrong rather than whose logic was.

The coverage floor measured half the product

[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 (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

294 lines ( 6 left)  backend/api/intents_chat.py::register_chat_intents
290 lines (10 left)  backend/chat_library.py::register_chat_library
285 lines (15 left)  backend/api/intents_settings_api_provider.py::register_settings_api_provider_intents
283 lines (17 left)  backend/api/intents_branches.py::register_branches_intents

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.

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:

TOTAL                                   21606   3126    86%
Required test coverage of 85.0% reached. Total coverage: 85.53%

provider_runtime is the weak spot now inside it (ollama_scan 8%, llama_cpp_scan 10%, gemini_transport 29%) 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 .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. 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.py compares 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

  • CI coverage command with the widened source: 21,606 statements, 85.53%, 3202 passed.
  • 4 new coverage-scope tests, 1 new cap-headroom test.
  • ruff and mypy both clean — and worth stating why that mattered here. The first pass at this replaced .py suffixes globally in pyproject.toml and silently corrupted three unrelated sections: mutmut's source_paths, mypy's files list, and ruff's api_provider.py per-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

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>
@dovvnloading
dovvnloading merged commit 4ba4d29 into main Sep 4, 2026
5 checks passed
@dovvnloading
dovvnloading deleted the fix/coverage-scope-and-cap-headroom branch September 4, 2026 15:13
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant