ADR-1290: The tidy ratchet owns its per-lane compilation database¶
- Status: Accepted
- Date: 2026-09-22
- Deciders: Lusoris
- Tags:
ci,sycl,cuda,hip,lint,agents
Context¶
ADR-1142 puts every file under the same standards and measures the debt per lane in scripts/ci/tidy-baseline-<lane>.json. The measurement is only as wide as the compilation database it is handed, and for the sycl lane that database was silently short: meson emits the SYCL feature translation units as CUSTOM_COMMAND rules (icpx -fsycl), and scripts/ci/write-compile-commands.py deliberately exports only the native c_COMPILER / cpp_COMPILER rules. scripts/ci/gen-sycl-compile-commands.py exists to synthesise the missing entries and core/src/feature/sycl/AGENTS.md already instructs contributors to run it, but make tidy-ratchet never did — so the lane measured 0 SYCL feature TUs against the 18 the generator produces, and the committed tidy-baseline-sycl.json recorded an empty backend.
The consequence was not confined to the baseline. Because a lane only counts NOLINT markers in files it measures, 15 uncited markers — 14 under core/src/feature/sycl/ and core/src/sycl/, 1 under core/src/feature/metal/ — were invisible to every lane, and the GPU NOLINT backlog was reported as 6 when the tree-wide figure was 21. A gate that cannot see a file reports it as clean, which is the failure mode ADR-1142 §1 exists to prevent.
Two further preconditions were undocumented and cost sibling agents whole sessions: the GPU build dir must be configured -Db_lto=false, because b_lto_threads=4 (ADR-1172) renders as GCC's -flto=4 and clang-tidy rejects it on every TU (T-TIDY-CHANGED-LTO-FLAG-2026-09-05 already fixed this for the cpu lane); and the build dir must live outside the repository, or meson's generated <build>/src/*.json.c enter the measurement under build-dir-specific keys.
Decision¶
The ratchet targets own the database they measure. make tidy-ratchet and make tidy-ratchet-write expand a per-lane hook, TIDY_RATCHET_COMPDB_<lane>, between the native export and the measurement; for sycl that hook runs gen-sycl-compile-commands.py, and for the lanes whose database meson writes natively it is empty. The two build-dir preconditions are documented at the variable block in the Makefile and in docs/development/ci.md, and scripts/ci/tests/test_tidy_ratchet_sycl_compdb.py pins the wiring.
Alternatives considered¶
| Option | Pros | Cons | Why not chosen |
|---|---|---|---|
Per-lane TIDY_RATCHET_COMPDB_<lane> hook in the Makefile (chosen) | Mirrors the existing TIDY_RATCHET_EXTRA_<lane> shape, so a future lane adds one line; keeps tidy-ratchet.py free of backend knowledge; testable without a toolchain | A caller who invokes tidy-ratchet.py directly still has to run the generator | — |
Call the generator from inside tidy-ratchet.py when --lane sycl | Covers direct script callers too | Puts meson/icpx build-graph knowledge inside the measurement tool and makes it mutate its own input; the script deliberately takes a database it does not own | Rejected: wrong layer |
Teach write-compile-commands.py to emit CUSTOM_COMMAND rules | One database, one tool | That script's contract is "native compiler rules only", and widening it would pull icpx flag translation (-fsycl, -fp-model=) into a generic exporter | Rejected: conflates two contracts |
| Document the extra step and leave the Makefile alone | No code change | This was already the state — AGENTS.md documented it and the baseline was still recorded without it. A rule only a human can apply is the thing that failed | Rejected: it is the status quo that broke |
Consequences¶
- Positive: the
sycllane measures the SYCL backend it is named for; the GPU baselines are reproducible from a documented recipe; the tree-wide uncited-NOLINT count and the sum of the lane baselines can no longer diverge silently. - Negative: the re-measured
syclbaseline is substantially larger than the one it replaces, because 18 previously unmeasured TUs enter it. That is newly-visible pre-existing debt, not a regression, and it is now bounded by the ratchet. - Neutral / follow-ups: none of the GPU lanes runs in CI yet — they remain local-only, so the baselines are recorded and unenforced until a hosted toolchain exists. Metal has no Linux toolchain and stays covered by the tree-wide NOLINT scan rather than by a lane measurement.
References¶
- ADR-1142 — whole-tree standards and the ratchet.
- ADR-0141 §2 — the NOLINT carve-out and its citation requirement.
- ADR-0278 — the CPU-lane cite-only sweep this completes for the GPU lanes.
- ADR-1172 — the
b_lto_threads=4default behind the-flto=obstacle. - ADR-1243 — scoped baseline tightening.
docs/state.mdrowsT-GPU-TIDY-LANE-BLIND-SPOT-2026-09-22,T-SYCL-LINT-SWEEP-2026-09-16,T-TIDY-CHANGED-LTO-FLAG-2026-09-05.- Ledger:
.workingdir/BUGS.mdBUG-029,BUG-041.