Repository navigation
ADR 0015 Gate pull requests on test coverage
Generated from
docs/adr/0015-gate-pull-requests-on-test-coverage.md. Edit that file in the repository: changes made in the wiki are overwritten.
- Status: Proposed
- Date: 2026-09-30
- Deciders: Gihed Annabi
Every test project references coverlet.collector, but CI never collected coverage, so nobody could see which code
the tests exercise. Measured on main, product code has 81% line coverage once tests, migrations and generated code
are excluded. The domain project is the weakest, at 74%. A gate on the total alone would let a pull request add
untested code as long as the total stays above the bar, and a high total bar would block unrelated work on old gaps.
CI measures line coverage on every run and enforces two rules on pull requests:
-
Changed lines: at least 80% of the executable source lines a pull request adds or changes under
src/are covered. Declarations, blank lines and comments don't count. A pull request that changes no executable line passes this rule. - Total: line coverage of all product code stays at or above 60%.
coverage.runsettings excludes test projects, EF Core migrations, files under obj/ and code marked
[GeneratedCode] or [ExcludeFromCodeCoverage], and skips auto-implemented properties. scripts/coverage_gate.py
merges the reports, computes both numbers from the pull request's diff, and writes a summary. That summary lists the
uncovered changed lines and any project that no test loads. CI writes it to the run page, keeps it as one comment on
the pull request, and uploads the reports. [ExcludeFromCodeCoverage] needs a comment explaining why the code can't
be tested.
Positive
- New code arrives with tests, and reviewers see exactly which changed lines aren't covered.
- The gate needs no external service or token: the built-in
GITHUB_TOKENposts the comment.
Negative
- Line coverage says a line ran, not that a test checked its result. Reviewers still judge the assertions.
- A project that no test loads has no coverage data. The summary names it, but the total leaves it out.
- Total minimum only: simpler, but a pull request can add untested code while the total stays above the bar.
- Report only: gives visibility, but nothing stops untested code from merging.
- A hosted service (Codecov, SonarCloud): adds an account, a token and a third party for what the build can compute itself.
- Product scope
- Architecture
- Visual guide
- Diagram maintenance
- Review a pull request
- Design a screen
- Test the addon
- Set up Discord
- Provision the server
- Glossary
- API contracts
- Addon snapshot contract
- Project automation
- Work management specification
- Warmane lockout evidence
- Planning
-
Decisions
- Index
- Foundation and authentication
- Character synchronization
- Documentation publication
- Protected automatic squash merges
- Viewed files before approval
- Operator review before a peer
- Auto-merge when ready
- Merge with the workflow token
- Meaningful review comments
- Read queries from the write database
- Website session and API trust
- Interactive Server rendering with Radzen
- Scalar API reference
- GitHub Wiki mirror
- Coverage gate
- Work item hierarchy
- Penpot mockups
- Generated Penpot mockups
- Dark design system
- SonarCloud findings
- Addon roster import
- Discord role checks
- Discord servers at sign-in
- Community roles
- Work item classification
- Work management specification adoption
- OVH test environment
- Environment secrets
- PostgreSQL
- Companion pairing
- WoW addon in Lua
- Windows companion in Avalonia
- Companion in the Microsoft Store
- Workflows on a self-hosted runner