#3941·tinyusb

pre-PR gate skips build-contract coverage: validate builds named boards, check_build.py only checks coverage for a resolved scope

Author: hathachCreated Sep 21, 2026Updated Sep 21, 2026
LabelsPrio 📌followup

Problem

The pre-PR gate can report green on a change whose driver no built board compiled.

  • .claude/skills/build/scripts/check_build.py:839-842 runs coverage() only when the scope was resolved (--scope/--base); under --board it is skipped.
  • .claude/workflows/validate.js:168-170 always dispatches builder with named boards, so every pre-PR build runs in --board mode.

Result: a change to src/portable/<vendor>/<driver>.c plus the core file that registers it selects boards, the boards build green, and the uncovered verdict the build contract defines (a class no example enables, a driver the preprocessor removes on every built board, a -T target that writes no elf) is never produced. pre-pr then says ship.

Fix

  • Add a selection-only mode to check_build.py (over select()/boards_for(), --base preferred), output marked as a selection, not a build. pre-pr uses it instead of its own board-sampling rules.
  • validate carries the original scope and ci_select reasons through the builds and evaluates coverage() afterwards, or reports coverage as unverified in its verdict.
  • Regression cases: changed board file, portable driver, uncovered class, preprocessed-away driver (dcd_nrf5x.c on NRF54, hcd_rp2040.c under MAX3421), tooling-only change, non-default -T target.

Why deferred

It changes the gate's behaviour, not its plumbing; the workflow cleanup that removes full-check, fanout-dev and check.sh and makes pre-pr software-only lands first and does not touch this.