Coverage
CodeStax ingests test-coverage reports and turns them into:
- A Coverage A–E rating on every scan
- Coverage-gap findings for low-covered files
- The
new_coverage_minquality gate input - Per-file coverage view on the scan dashboard
See Coverage Ingestion for the upload flow + CI recipes. This page is the scanner reference.
Supported Formats
| Format | Filename patterns | Common sources |
|---|---|---|
| LCOV | lcov.info, coverage.lcov, lcov-report.info, *.lcov | Jest, Vitest, Python coverage.py --lcov, Go gocov, C gcov |
| Cobertura XML | coverage.xml, cobertura.xml, cobertura-coverage.xml, coverage-cobertura.xml | Python coverage.py, PHPUnit, Ruby SimpleCov, .NET |
| JaCoCo XML | jacoco.xml, jacocoTestReport.xml | Java (Maven, Gradle), Kotlin, Scala |
| Clover XML | clover.xml | PHPUnit, Karma, legacy Jest |
Format detection is automatic by filename + root-element sniff. You can also force via report_format query/form param.
Two Ingestion Paths
Auto-detect
Scanner walks the cloned repo (bounded 6 directories deep) looking for files matching known patterns. Skipped: node_modules, .git, __pycache__, .venv, venv, env, dist, .next, .nuxt, .cache.
Works when coverage artifacts are committed to git.
Upload (preferred for most teams)
curl -X POST "https://codestax.co/api/quality/coverage/upload" \
-H "Authorization: Bearer $JWT" \
-F "scan_id=12345" \
-F "file=@coverage/lcov.info"Max file size: 25 MB.
Output
Per-file records (CoverageReport table)
{
"file_path": "src/auth/handler.py",
"lines_total": 420,
"lines_covered": 412,
"lines_missed": 8,
"branches_total": 84,
"branches_covered": 72,
"coverage_pct": 98.1,
"report_format": "lcov"
}Aggregate (returned from GET /quality/coverage/:scan_id)
{
"scan_id": 12345,
"file_count": 847,
"lines_total": 42100,
"lines_covered": 38700,
"coverage_pct": 91.92,
"files": [ ... ]
}Coverage-gap findings
Files below threshold emit type: "coverage_gap" findings:
< 60%(configurable viaquality_coverage_low_threshold) →medium< 30%(configurable viaquality_coverage_critical_threshold) →high
Files < 20 lines total are skipped (noise reduction).
Parser Notes
LCOV
Line records (DA:, LF:, LH:) → total/covered/missed per file. Branch records (BRF:, BRH:) → branch coverage.
Cobertura
<class filename="..."><lines><line number="X" hits="Y"/> — counts lines + branches (condition-coverage="X% (A/B)").
JaCoCo
<report><package><sourcefile><counter type="LINE|BRANCH" missed="X" covered="Y"/> — standard JaCoCo XML.
Clover
<project><package><file><metrics statements="X" coveredstatements="Y"/> — statement-level coverage treated as line coverage.
Thresholds (Configurable)
Per-org scanner config:
{
"quality_coverage_autodetect": true, // enable auto-scan of repo
"quality_coverage_low_threshold": 60, // medium severity threshold
"quality_coverage_critical_threshold": 30 // high severity threshold
}Dependencies
Parser is stdlib-only — no PyYAML or lxml dependency. XML parsing uses xml.etree.ElementTree. LCOV is line-oriented text.
Limits
- 25 MB file cap (hard, backend)
- 2000 file records per scan (soft — excess rows dropped with a warning log)
- Absolute paths in reports are kept as-is (we don’t path-normalize; use relative paths in your CI config for cleanest results)
Known Gaps
- Function-level coverage — parsers capture line + branch; function-level
FN:/FNDA:records in LCOV are currently ignored - Diff-based coverage — “coverage on lines changed in this PR” not yet computed; roadmap Q2
- Coverage trends — per-repo coverage over time is stored but no trend UI yet; use the API
Related
- Coverage Ingestion — CI upload recipes
- Quality Ratings — how coverage feeds the A–E rating
- Set Up Quality Gates —
new_coverage_minthreshold enforcement