ADR-1230: The CI gcc moves forward with clang and meson, and the ratchet records it¶
- Status: Accepted
- Date: 2026-09-07
- Deciders: Lusoris
- Tags: ci, build, tooling, clang-tidy, fork-local
Context¶
The clang-tidy lanes in lint-and-format.yml install three toolchain components, and until now treated them inconsistently:
| Tool | ubuntu-24.04 ships | What CI did | Rationale in the workflow |
|---|---|---|---|
| clang | 18 — cannot parse the tree's C++26 std::expected | installs clang-22 from apt.llvm.org | yes, in a comment |
| meson | 1.3.2 — predates c23 in c_std | installs from PyPI | yes, in a comment |
| gcc | 14 | used gcc-14 | none |
Two of the three are deliberately pulled forward past the distro because the tree targets C23 / C++26 (ADR-0692). gcc was left at whatever the runner image happened to ship. No ADR pins it; the only mention of gcc-14 anywhere in docs/adr/ is an incidental line in a VVenC changelog summary.
That is not free, and it stopped being theoretical on PR #1392. The ratchet reported core/test/test_pooling_percentile.c: warnings 0 -> 1 (+1) while Tidy Changed — which fails on any warning and does not exclude that file — reported the same file clean, on the same runner and the same commit. The delta could not be reproduced on gcc-15 or gcc-16; on both, the only warning was a glibc system-header diagnostic the ratchet correctly discards.
The cause is structural. clang-tidy parses each translation unit against the system headers the C compiler provides, so a ratchet count depends on gcc's version as much as on clang-tidy's — and the baseline recorded only clang_tidy_version. Pinning gcc a major behind every developer's machine, while recording nothing about it, makes a count that disagrees with local measurement impossible to explain.
The report artifact made it worse: tidy-ratchet.py parses every diagnostic in parse_diagnostics() and then discards everything but the per-file count, so "which warning?" had no answer anywhere in CI's output.
Decision¶
1. gcc moves forward with the rest of the toolchain. The clang-tidy lanes install gcc-15 / g++-15 from ppa:ubuntu-toolchain-r/test, the same "pull the toolchain past the distro" treatment clang and meson already get, for the same reason.
2. The ratchet records the compiler it measured with. cc_version joins clang_tidy_version in the baseline and the report, read from the build directory's meson-info/intro-compilers.json rather than from $CC, so the recorded value is the compiler that actually produced compile_commands.json. A mismatch against the baseline annotates a warning, exactly as a clang-tidy mismatch already does.
3. The report artifact keeps the diagnostics. Every measured diagnostic is recorded as path:line:col: [check] in the --report JSON. The baseline deliberately does not carry them: it stays a reviewable count file that does not churn every time a line number shifts. The report is where you look when a delta needs explaining.
Alternatives considered¶
| Option | Pros | Cons | Why not chosen |
|---|---|---|---|
| Leave gcc at 14 | Zero churn; the baseline stays valid as-is | Keeps the tree's build compiler a major behind its own C23/C++26 target, and keeps every ratchet delta unreproducible off the CI image — the defect this ADR exists to fix | Rejected |
Move the lanes to an ubuntu-26.04 runner image | Newer gcc with no PPA | GitHub's hosted 26.04 image availability is not something this repo should depend on for a required check; the PPA is explicit and version-pinned | Rejected for now; revisit when 26.04 is the default ubuntu-latest |
Bump gcc across libvmaf-build-matrix.yml too | Consistency everywhere; the matrix is equally a major behind | A compiler bump across ten-plus matrix legs surfaces its own crop of new warnings and belongs in a PR whose CI failures are about exactly that, not mixed into a diagnostics fix | Deferred to a follow-up, deliberately |
| Record diagnostics in the baseline too | One file to look at | The baseline would churn on every line-number shift and stop being reviewable, and its whole value is being a stable, diffable count | Rejected |
| Keep counts only and reproduce locally when needed | No script change | That is precisely what failed on #1392: local reproduction is impossible when CI's compiler is pinned to a version developers do not have | Rejected |
Consequences¶
- Positive: the build compiler stops being the one component frozen at the distro's version; a future ratchet delta names the check and the line instead of only a count; a compiler change is announced rather than silently shifting every count.
- Negative: the cpu baseline must be regenerated. Warning counts under gcc-15's headers will not equal gcc-14's, so
scripts/ci/tidy-baseline-cpu.jsonis stale the moment this merges. It has to be rewritten from a CI run (tidy-ratchet.py --writeon the lane), never from a developer machine — a local run resolvesenable_dnn=autodifferently and would rebaseline unrelated files against the wrong build. - Neutral / follow-ups:
libvmaf-build-matrix.ymlstill pinsgcc-14across its legs; moving it is a separate PR. Thecc_versionfield is optional on read, so an existing baseline without it loads unchanged and simply does not trigger the mismatch warning until it is regenerated.
References¶
- req: the user asked why CI was going backwards on gcc when the project's direction is newer toolchains.
- PR #1392 — the unreproducible
+1that exposed both halves of this. - ADR-0692 — the C23 / C++26 target that justifies pulling clang and meson past the distro, and now gcc with them.
- ADR-1142 — the ratchet this makes diagnosable.