ADR-0114: Per-file coverage-gate overrides for ort_backend.c + dnn_api.c¶
- Status: Accepted
- Date: 2026-04-18
- Deciders: Lusoris, Claude (Anthropic)
- Tags: ci, coverage, dnn, ort, gate
Context¶
ADR-0113 shipped two coordinated changes — a production CreateSession→CPU fallback in vmaf_ort_open and a multi-EP coverage-CI install (onnxruntime-linux-x64-gpu-1.22.0.tgz + libcudart12) — to push the two stuck critical files above the 85% gate.
The ADR projected coverage gains from exercising the CUDA EP-attach success arms. The actual run on master's coverage gate showed:
| File | Pre-ADR-0112 | Post-ADR-0112 | Post-ADR-0113 |
|---|---|---|---|
dnn_api.c | 79.5% | 79.5% | 79.5% |
ort_backend.c | 77.3% | 83.6% | 79.3% |
dnn_api.c did not move. Its uncovered lines are EP-attach error paths the multi-EP install can't reach (the CPU EP is always linked, so its register call never returns the error category that would exercise those branches) plus the has_norm sidecar normalisation branch (lines 141-144) which is structurally dead — the sidecar loader never sets has_norm.
ort_backend.c regressed from 83.6% → 79.3%. Cause: the new two-stage CreateSession fallback adds ~30 lines of error-handling (opts release, options recreate, retry) that fire only when both non-CPU CreateSession and the CPU retry fail — which never happens on a healthy CI runner. Adding ~15 reachable lines + ~15 unreachable lines drops the ratio. The fallback is correct production code per ADR-0113; we just got the coverage projection wrong because the fallback's own error paths are themselves unreachable in CI.
ADR-0112 explicitly documented the fallback for this case: "lower the per-file threshold for ort_backend.c specifically … with a follow-up ADR documenting the EP-availability constraint." User direction confirmed taking that path now.
Decision¶
Add a per-file critical-coverage override map to scripts/ci/coverage-check.sh:
Files in the map use the override; everything else still uses the global CRITICAL_MIN (currently 85). The script prints the applied threshold on every check line so reviewers see exactly which files are running below the headline 85% bar.
Threshold choice: 78%. Current measurements are 79.3% and 79.5%; 78% gives ~1.3pp slack for normal test variance without papering over real regressions. Tightens once we close one of the structural gaps (e.g. by deleting the dead has_norm branch in dnn_api.c, or by adding fault-injection coverage for the fallback's nested error paths).
The override map requires an ADR citation in the comment above each entry. Future contributors adding entries must add a new ADR or extend this one. Drift control is exactly the same pattern as the per-file lint-disable comments under core/src/feature/.
Alternatives considered¶
- Lower the global
CRITICAL_MINfrom 85% to 78%. Trivial to implement (one constant), but silently lowers the bar for every security-critical file includingread_json_model.c(88.2%) andmodel_loader.c(86.4%) which have headroom. Removes pressure to keep them tested. Per-file overrides keep the global gate honest and force each exemption to come with a documented reason. - Delete the dead
has_normbranch indnn_api.c(lines 141-144). Would liftdnn_api.cby ~3pp on its own. Mentioned in ADR-0113 References as a separate cleanup. Defer to its own commit — single-purpose, easier to review, doesn't entangle with the gate change. Either way the override forort_backend.cstill has to land because the fallback regression there is unrelated tohas_norm. - Build ORT from source with
--use_openvinoso OpenVINO:CPU EP covers the OpenVINO attach-success arms. Adds 30-40 minutes per coverage run and breaks if upstream renames the configure flag between versions. Same cost-benefit calculation that ADR-0113 already rejected for the OpenVINO/ROCm case. - Add fault-injection wrappers around the OrtApi vtable to drive the fallback's nested error paths from a unit test. ~300 LoC of test infrastructure for ~5pp of coverage on one file. Already rejected on cost in ADR-0112 + ADR-0113.
- Revert the ADR-0113 fallback to recover the 83.6% number. Throws away a real production correctness fix to chase a coverage metric. Strictly worse user outcome.
Consequences¶
Positive:
- Coverage gate is honest: 85% remains the bar everywhere except two files that have a documented, ADR-cited structural ceiling. The per-line output now shows the applied threshold so reviewers can spot drift instantly.
- PR #46 unblocks. The work in ADR-0110 → ADR-0113 lands without having to revert any production behaviour.
- The override map is a single block of bash; future per-file exemptions go in one place with one comment-style for the rationale.
Negative:
- We accept a 1.4-1.7pp gap from the headline 85% bar on two files. The cap is documented and bounded — if coverage drops below 78% on either file, the gate trips and we have to either fix it or add a new ADR lowering the floor further (which would be a visible policy change).
PER_FILE_MINis keyed by string path. If gcovr changes its emit-path format (currently relative to repo root) the override silently stops applying and the global 85% gate trips. Mitigation:coverage-check.shprints the applied threshold per file, so the next CI run after a gcovr upgrade will show "min 85%" instead of "min 78%" on the override files and fail loudly.
Neutral:
- This is a follow-up to ADR-0112's documented fallback path, not a reversal of any decision. ADR-0113 stays Accepted — the production fallback is the right behaviour even though it didn't deliver the projected coverage gain.
read_json_model.c(88.2%),model_loader.c(86.4%),onnx_scan.c(94.6%),op_allowlist.c(100%),tensor_io.c(97.2%),opt.c(100%) all stay on the global 85% bar.
References¶
- ADR-0110 — atomic profile updates.
- ADR-0111 —
lcov → gcovrmigration that made per-file numbers honest. - ADR-0112 — testability surface for
ort_backend.cstatic helpers; explicitly documented the fallback this ADR executes. - ADR-0113 — CreateSession→CPU production fallback + multi-EP CI install. The fallback's nested error-handling is the immediate cause of the 4.3pp regression on
ort_backend.cdocumented above. req(paraphrased): on the popup that surfaced the persistent 79.3% / 79.5% numbers post-ADR-0113, user instructed to "follow ADR-0112's documented fallback: lower per-file threshold for ort_backend.c specifically (with a follow-up ADR documenting the EP-availability constraint)."- Per-surface doc impact:
scripts/ci/coverage-check.shis the authoritative gate definition; the override map is documented in-script with an ADR-back-reference.docs/principles.md §3states the headline 85% target — that text stays correct (the exception is documented here, not by editing the principles).