ci(gate): compile and lint feature-gated code, which nothing did (#1380) - #1423
Merged
Merged
Conversation
`#[cfg(feature = "x")]` code must still PARSE when the feature is off, so a syntax error was caught — but nothing after parsing was: type errors, borrow errors, wrong arity, a renamed method. Both lint passes in gate.sh and the hook build --no-default-features, so nine feature families gating code (cpal, serial/gpio, gpu, keychain, tokio, serde, gui/serve, hardware-tests, instruments) were compiled by no automated check. ci.yml's gpu-feature-gates guarded one of them and, being release/**-scoped (#1120), never ran on an ordinary PR. ONE RULE, not the issue's named --features cpal-backend: a hand-maintained list of crate+feature pairs is the same rotting mirror the guard exists to catch. Safe because every feature here is additive (generic-serial = ["serial"]). A per-feature matrix was considered and rejected on measurement — no cfg(all(feature = A, not(feature = B))) exists anywhere, so a 2^17 powerset would find zero defects. IT FOUND TWO LIVE DEFECTS, neither in cpal: a `serve`-gated test left behind when LinkParams gained cessb_enabled (b883b5f) and notch (26696f9) in 2026-06 — uncompilable, therefore never RUN, for ~3 months — and a float-literal-f32-fallback in the gui binary that rustc says becomes a hard error. Both fixed; the serve tests now run: 2 passed, 0 failed. THE PREFLIGHT IS NOT CEREMONY. --all-features pulls alsa-sys, libudev-sys and libdbus-sys, whose build scripts call pkg_config and PANIC when a .pc file is absent. The ubuntu runner ships none of the three -dev packages and neither gate-running job installed anything, so this was red-on-arrival for post-merge-gate.yml (#1074's archetype). My clean local run described this host only AFTER a root update stamped those .pc files on 2026-09-19; the ledger records libdbus-sys failing here four days before. Both gate and hook now fail with the Debian package names rather than skipping, and both CI jobs apt-get them (not `|| true`). A LATENT DEFECT THE DESIGN EXPOSED: gpiocdev is declared under [target.'cfg(target_os = "linux")'] while gpio.rs was gated on feature = "gpio" alone. Cargo enables a feature whose optional dep is target-filtered out, so --all-features on macOS compiles that code with no crate. Retargeted to all(target_os = "linux", feature = "gpio") at all five sites; unverified on darwin here. gpu-feature-gates REMOVED, subsumed: the new pass covers gpu and hardware-tests across every crate rather than five named plugins, on every local gate run and in post-merge-gate, where that job never ran at all. TWO STATED LIMITS. Not closed over targets (see gpio). Not closed over the shipped recipe: --all-features turns `instruments` on, so an instruments-only item called from a cpal-gated production path passes all three passes and fails only `cargo build --release -p openpulse-cli --features cpal-backend`. Zero instances today. Sabotage — #1380's own probe, a planted type error in the cpal-gated run_drive: pass1 --no-default-features --all-targets -> rc=0 pass2 --no-default-features -> rc=0 pass3 --all-features --all-targets -> rc=101 The two rc=0 rows are what make the failure attributable to the new pass. Evidence honesty: both defects found are in openpulse-linksim, a crate slated for replacement, and the yield on shipped cpal/gpu/serial paths was zero. The justification is the class (3 months undetected, PR #424 precedent), not today's haul. Verification-objective: feature-gated code must be compiled and linted by an automated check, not only parsed Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_0188ATCj6DZ9aRVQ2vSirua6
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Closes #1380.
#[cfg(feature = "x")]code must still parse when the feature is off, so a syntax error wascaught — but nothing after parsing was: type errors, borrow errors, wrong arity, a renamed method.
Both lint passes in
gate.shand the hook build--no-default-features, so nine feature familiesgating code (cpal, serial/gpio, gpu, keychain, tokio, serde, gui/serve, hardware-tests, instruments)
were compiled by no automated check.
ci.yml'sgpu-feature-gatesguarded one of them and, beingrelease/**-scoped (#1120), never ran on an ordinary PR.It found two live defects, neither in cpal
apps/openpulse-linksim/tests/serve_integration.rs—E0063.LinkParamsgainedcessb_enabled(
b883b5f8) andnotch(26696f98) in 2026-06; the test was last touched 2026-06-21. Theservefeature's only tests had been uncompilable, and therefore never run, for ~3 months. They now
run: 2 passed, 0 failed.
apps/openpulse-linksim/src/gui.rs:509—float-literal-f32-fallback, which rustc says "willbecome a hard error in a future release". The
guibinary would have stopped compiling on afuture toolchain with no warning to anyone.
One rule, not a list
cargo clippy --workspace --all-features --all-targets -- -D warnings, rather than the issue's named--features cpal-backend: a hand-maintained list of crate+feature pairs is the same rotting mirrorthe guard exists to catch. Safe because every feature here is additive (
generic-serial = ["serial"]). A per-feature matrix was considered and rejected on measurement — nocfg(all(feature = A, not(feature = B)))exists anywhere, so a 2¹⁷ powerset would find zero defects.The preflight is not ceremony
--all-featurespullsalsa-sys,libudev-sysandlibdbus-sys, whose build scripts callpkg_configand panic when a.pcfile is absent. The ubuntu runner ships none of the three-devpackages and neither gate-running job installed anything, so as first written this wasred-on-arrival for
post-merge-gate.yml— #1074's archetype. My clean local run described thishost only after a root update stamped those
.pcfiles on 2026-09-19; the ledger recordslibdbus-sysfailing on this same machine four days earlier.So: a
pkg-configpreflight in both gate and hook that fails with the Debian package namesrather than skipping, and an
apt-getstep (deliberately not|| true) in both CI jobs that rungate.sh.A latent defect the design exposed
gpiocdevis declared under[target.'cfg(target_os = "linux")']whilegpio.rswas gated onfeature = "gpio"alone. Cargo enables a feature whose optional dep is target-filtered out, so--all-featureson macOS compiles that code with no crate. Retargeted toall(target_os = "linux", feature = "gpio")at all five sites. Unverified on darwin — no darwin std on this host.gpu-feature-gatesremovedSubsumed: the new pass covers
gpuandhardware-testsacross every crate rather than five namedplugins, on every local gate run and in
post-merge-gate, where that job never ran at all. Itsreasoning and the PR #424 precedent survive in the new step's comment.
Two stated limits
Not closed over targets (see gpio). Not closed over the shipped recipe:
--all-featuresturnsinstrumentson, so an instruments-only item called from a cpal-gated production path passes allthree passes and fails only
cargo build --release -p openpulse-cli --features cpal-backend. Zeroinstances today — a residual, not a claim of completeness. My earlier "2×2 grid" framing was wrong:
the axes are not independent.
Sabotage — #1380's own probe
A planted type error in the cpal-gated
run_drive(calibrate.rs:320):The two
rc=0rows are what make the failure attributable to the new pass. The preflight wasseparately sabotaged with a nonexistent library and correctly printed
SKIPPED (missing pkg-config: zz-nonexistent-lib)with the install line, and failed.Evidence honesty
Both defects found are in
openpulse-linksim, a crate under a 2026-09-10 direction to be replaced,and the yield on shipped cpal/gpu/serial paths was zero. The justification is the class — three
months undetected, PR #424 precedent — not today's haul.
Test results
scripts/gate.shon the branch tip, clean tree:All 13 steps
ok, including the new one.cargo test -p openpulse-linksim --features serve --test serve_integration→ 2 passed, 0 failed.Reviewer note
The CI evidence that matters here is
post-merge-gate.yml, not this PR's checks — the gate doesnot run pre-merge (#1144), and the apt step is the thing at risk. I will confirm that run after merge
and report it.
Verification-objective: feature-gated code must be compiled and linted by an automated check, not
only parsed
Review: docs/dev/reviews/review-1380-feature-rot-guard.md
🤖 Generated with Claude Code
https://claude.ai/code/session_0188ATCj6DZ9aRVQ2vSirua6