Code coverage
The coverage the build already measured, read from whichever report format it left behind and normalized into one shape: the line and branch totals across every report, and a summary per file. The covered and missed line numbers themselves are left out unless lineDetail asks for them, because a large repository's line map is bigger than the facts document is allowed to be. Reports that name the same file are merged line by line, so a per module report and a merged one agree, but a report carrying only totals adds to them.
| Facts key | coverage |
| Version | v1 |
| Script | coverage.py |
| Timeout | 60 seconds |
Inputs
| Input | Description | Default | Environment |
|---|---|---|---|
reports | Comma separated globs matched against every file in the working directory and against bare file names, naming the coverage reports to read. | jacoco*.xml,jacocoTestReport.xml,cobertura*.xml,coverage*.xml,lcov.info,coverage-final.json | GUARDRAIL_INPUT_REPORTS |
maxFiles | Most files to carry in byFile, the ones with the most uncovered lines first. The totals stay whole when files are dropped. | 500 | GUARDRAIL_INPUT_MAXFILES |
lineDetail | true to carry the covered and missed line numbers of every file in byFile, which a guardrail over the lines a change touched needs and everything else pays for in size. | false | GUARDRAIL_INPUT_LINEDETAIL |
A guardrail that declares an input of the same name passes it through, so the guardrail's configuration in buildnote.json is what decides these values.
A guardrail asks for these facts by name, and reads them back the same way:
{
"collect": ["coverage"]
}coverage = guardrail.facts("coverage")Facts
The document coverage collects. A path carrying [] is an entry of the list before it, and one carrying [path] is a key of the object before it.
| Fact | Meaning |
|---|---|
source | report when a coverage report was read, none when there was none. |
reason | Why nothing was read, present only when source is none. |
reports | Every report that was read, in path order. |
reports[].path | Path of the report, relative to the directory the CLI runs in. |
reports[].modified | When the report was last written, ISO 8601, so a stale report is recognisable. |
reports[].format | Format it was read as: jacoco, cobertura, istanbul or lcov. |
lines.covered | Lines at least one report saw executed, counted once across every report that names the file. |
lines.missed | Lines every report saw unexecuted. |
lines.percent | Covered lines as a percentage of the lines the reports measured, to two decimal places, 0.0 when they measured none. |
branches | The branch totals, or null when no report that was read carries branch coverage. |
branches.covered | Branches taken. |
branches.missed | Branches never taken. |
branches.percent | Taken branches as a percentage of the branches the reports measured, to two decimal places. |
files | How many files the reports measured, before maxFiles was applied. |
byFile | A summary per file, the ones with the most uncovered lines first, up to maxFiles. |
byFile[path].covered | Lines of that file at least one report saw executed. |
byFile[path].missed | Lines of that file every report saw unexecuted. |
byFile[path].percent | Covered lines of that file as a percentage, to two decimal places. |
byFile[path].coveredLines | The covered line numbers, ascending, present only when lineDetail is true. |
byFile[path].missedLines | The missed line numbers, ascending, present only when lineDetail is true. |
dropped | Files left out of byFile because maxFiles was reached. |
A collector that cannot finish prints what it had along with an incomplete key saying why, so the facts below the point it stopped are absent. A check that cares reads incomplete before the rest.
Example facts
The example facts collected by coverage collector:
{
"source": "report",
"reports": [
{
"path": "jacocoTestReport.xml",
"modified": "2026-03-04T10:15:00Z",
"format": "jacoco"
}
],
"lines": {
"covered": 4,
"missed": 3,
"percent": 57.14
},
"branches": {
"covered": 1,
"missed": 3,
"percent": 25.0
},
"files": 2,
"byFile": {
"com/acme/widget/Broker.kt": {
"covered": 1,
"missed": 2,
"percent": 33.33
},
"com/acme/widget/Queue.kt": {
"covered": 3,
"missed": 1,
"percent": 75.0
}
},
"dropped": 0
}Collected for
| Guardrail | Category | Inputs |
|---|---|---|
tests/coverage-floor | tests | none |