Skip to Content
ScanningCoverage

Coverage

CodeStax ingests test-coverage reports and turns them into:

  1. A Coverage A–E rating on every scan
  2. Coverage-gap findings for low-covered files
  3. The new_coverage_min quality gate input
  4. 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

FormatFilename patternsCommon sources
LCOVlcov.info, coverage.lcov, lcov-report.info, *.lcovJest, Vitest, Python coverage.py --lcov, Go gocov, C gcov
Cobertura XMLcoverage.xml, cobertura.xml, cobertura-coverage.xml, coverage-cobertura.xmlPython coverage.py, PHPUnit, Ruby SimpleCov, .NET
JaCoCo XMLjacoco.xml, jacocoTestReport.xmlJava (Maven, Gradle), Kotlin, Scala
Clover XMLclover.xmlPHPUnit, 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 via quality_coverage_low_threshold) → medium
  • < 30% (configurable via quality_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