From 1f9df460792cffc89ec123a059995b0484cf6124 Mon Sep 17 00:00:00 2001 From: Transaction Science Date: Thu, 5 Nov 2026 10:21:43 -0500 Subject: [PATCH 1/6] jouleclaw-energy: clippy-clean under rapl and nvml on Linux - `--features rapl` alone: `liveness::probe` was never used. The RAPL probe reached the same code through `probe_packages_stepping(packages, || {})`, though rapl.rs documents its probe as `crate::liveness::probe`. `probe_packages` now calls `crate::liveness::probe` directly, which is the same call (probe = probe_stepping with a no-op step), and `probe_packages_stepping`, which only tests use, is `#[cfg(test)]`. - `--features nvml`: tests/nvml_hardware.rs spelled an `nvidia-smi` power triple out three times (type_complexity). It is now the oracle's `SmiPower` alias. Clippy -D warnings is clean on Linux (default, rapl, nvml, rapl+nvml) and macOS (default, ioreport, smc, ioreport+smc, rapl). Tests pass: Linux rapl (89) and rapl+nvml (96), macOS rapl lib (95). Co-Authored-By: Claude Opus 5.5 --- .../jouleclaw-rs/crates/jouleclaw-energy/src/rapl.rs | 4 ++-- .../crates/jouleclaw-energy/tests/nvml_hardware.rs | 10 +++++++--- 2 files changed, 9 insertions(+), 5 deletions(-) diff --git a/jouleclaw/jouleclaw-rs/crates/jouleclaw-energy/src/rapl.rs b/jouleclaw/jouleclaw-rs/crates/jouleclaw-energy/src/rapl.rs index 8b6591bf9..b3679d810 100644 --- a/jouleclaw/jouleclaw-rs/crates/jouleclaw-energy/src/rapl.rs +++ b/jouleclaw/jouleclaw-rs/crates/jouleclaw-energy/src/rapl.rs @@ -551,13 +551,13 @@ fn cached(set: &[PathBuf], probe: impl FnOnce() -> CounterLiveness) -> CounterLi /// caller is the cache in [`package_liveness`]. #[cfg_attr(not(target_os = "linux"), allow(dead_code))] fn probe_packages(packages: &[Package]) -> CounterLiveness { - probe_packages_stepping(packages, || {}) + crate::liveness::probe(|| open_sampler(packages), PROBE_TICK) } /// [`probe_packages`], with `before_burn` run at the start of every tick /// ([`crate::liveness::probe_stepping`]): how a test advances a fake tree in /// step with the probe. -#[cfg_attr(not(target_os = "linux"), allow(dead_code))] +#[cfg(test)] fn probe_packages_stepping(packages: &[Package], before_burn: impl FnMut()) -> CounterLiveness { crate::liveness::probe_stepping(|| open_sampler(packages), PROBE_TICK, before_burn) } diff --git a/jouleclaw/jouleclaw-rs/crates/jouleclaw-energy/tests/nvml_hardware.rs b/jouleclaw/jouleclaw-rs/crates/jouleclaw-energy/tests/nvml_hardware.rs index 411fdfbdb..685adab67 100644 --- a/jouleclaw/jouleclaw-rs/crates/jouleclaw-energy/tests/nvml_hardware.rs +++ b/jouleclaw/jouleclaw-rs/crates/jouleclaw-energy/tests/nvml_hardware.rs @@ -139,9 +139,13 @@ mod nvml_oracle { } } + /// One GPU as `nvidia-smi` gives it, in watts: (maximum power limit, + /// enforced limit, draw), each `None` where it gave none. + pub type SmiPower = (Option, Option, Option); + /// `nvidia-smi`'s view of every GPU: (maximum power limit, enforced limit, /// draw), in watts; `None` without `nvidia-smi`. - pub fn smi() -> Option, Option, Option)>> { + pub fn smi() -> Option> { let out = std::process::Command::new("nvidia-smi") .args(["--query-gpu=power.max_limit,enforced.power.limit,power.draw", "--format=csv,noheader,nounits"]) .output() @@ -159,7 +163,7 @@ mod nvml_oracle { /// GPU `i`'s ceiling in watts: `nvidia-smi`'s maximum power limit, else /// NVML's. - pub fn ceiling_w(nvml: &Nvml, smi: &Option, Option, Option)>>, i: usize) -> Option { + pub fn ceiling_w(nvml: &Nvml, smi: &Option>, i: usize) -> Option { smi.as_ref() .and_then(|s| s.get(i)) .and_then(|(max, _, _)| *max) @@ -320,7 +324,7 @@ mod nvml_oracle { let window = last_at; let rate_w: Vec = first.iter().zip(&prev).map(|(a, b)| b.saturating_sub(*a) as f64 / 1000.0 / window.as_secs_f64().max(1e-9)).collect(); - let draw = |s: &Option, Option, Option)>>, i: usize| s.as_ref().and_then(|s| s.get(i)).and_then(|t| t.2); + let draw = |s: &Option>, i: usize| s.as_ref().and_then(|s| s.get(i)).and_then(|t| t.2); let draws_w: Vec> = (0..n).map(|i| [draw(&before, i), draw(&after, i)].into_iter().flatten().collect()).collect(); let ceiling_w: Vec> = (0..n).map(|i| ceiling_w(&nvml, &after, i)).collect(); // The verdict that speaks for the run is the most severe of its GPUs', -- 2.54.0 (Apple Git-157) From fba729ce7b4b68668b7d65d6bee89960a99672a5 Mon Sep 17 00:00:00 2001 From: Transaction Science Date: Thu, 5 Nov 2026 10:21:43 -0500 Subject: [PATCH 2/6] jcp-energy: clippy-clean on Linux, with and without nvml - `FabricMeter::readable` and `FabricMeter::measure` built their vector `mut` on every platform and pushed to it only on macOS, so Linux reported two unused `mut`s. Each now has a macOS body that builds and returns the vector, and a body for everywhere else that returns it empty. The behaviour is the same on both. - `FabricSource::has_backend`: with `nvml` on, its match folded to a `matches!` (match_like_matches_macro). It is written as one, with the nvml arm still gated on the feature. - tests/nvml_hardware.rs: the `nvidia-smi` power triple is the oracle's `SmiPower` alias (type_complexity under `--features nvml`). Clippy -D warnings is clean on Linux (default, nvml) and in the macOS lint step (jcp-energy, jcp-gateway). Tests pass: Linux default (68) and nvml (70), macOS lib (128). Co-Authored-By: Claude Opus 5.5 --- jcp/jcp-rs/crates/jcp-energy/src/lib.rs | 28 +++++++++++-------- .../crates/jcp-energy/tests/nvml_hardware.rs | 10 +++++-- 2 files changed, 24 insertions(+), 14 deletions(-) diff --git a/jcp/jcp-rs/crates/jcp-energy/src/lib.rs b/jcp/jcp-rs/crates/jcp-energy/src/lib.rs index 629a2c36d..f040eef8e 100644 --- a/jcp/jcp-rs/crates/jcp-energy/src/lib.rs +++ b/jcp/jcp-rs/crates/jcp-energy/src/lib.rs @@ -6312,9 +6312,9 @@ impl FabricMeter { /// Which fabrics this meter can read, and whose work each figure counts. pub fn readable(&self) -> Vec<(Fabric, Attribution)> { - let mut out = Vec::new(); #[cfg(target_os = "macos")] { + let mut out = Vec::new(); if self.process.is_some() { out.push((Fabric::Cpu, Attribution::Process)); } @@ -6324,8 +6324,12 @@ impl FabricMeter { out.push((Fabric::Npu, Attribution::Machine)); } } + out + } + #[cfg(not(target_os = "macos"))] + { + Vec::new() } - out } /// Run `work`, and report each fabric's energy over it. @@ -6352,9 +6356,9 @@ impl FabricMeter { let out = work(); let span_ns = started.elapsed().as_nanos(); - let mut readings = Vec::new(); #[cfg(target_os = "macos")] - { + let readings = { + let mut readings = Vec::new(); let cpu_after = cpu_before.and_then(|_| self.process.as_ref()?.read_energy_nj()); if let (Some(b), Some(a)) = (cpu_before, cpu_after) { readings.push(FabricEnergy { @@ -6383,8 +6387,13 @@ impl FabricMeter { }); } } - } - let _ = span_ns; + readings + }; + #[cfg(not(target_os = "macos"))] + let readings = { + let _ = span_ns; + Vec::new() + }; (out, readings) } } @@ -6461,11 +6470,8 @@ impl FabricSource { /// cannot be measured" are different facts and a survey that blurs them is /// worthless. See [`FabricStatus::NotImplemented`]. pub fn has_backend(self) -> bool { - match self { - FabricSource::ProcRusage | FabricSource::IoReport | FabricSource::Rapl => true, - FabricSource::Nvml => cfg!(feature = "nvml"), - _ => false, - } + matches!(self, FabricSource::ProcRusage | FabricSource::IoReport | FabricSource::Rapl) + || (matches!(self, FabricSource::Nvml) && cfg!(feature = "nvml")) } } diff --git a/jcp/jcp-rs/crates/jcp-energy/tests/nvml_hardware.rs b/jcp/jcp-rs/crates/jcp-energy/tests/nvml_hardware.rs index 3ccbc92db..359c95e0f 100644 --- a/jcp/jcp-rs/crates/jcp-energy/tests/nvml_hardware.rs +++ b/jcp/jcp-rs/crates/jcp-energy/tests/nvml_hardware.rs @@ -137,9 +137,13 @@ mod nvml_oracle { } } + /// One GPU as `nvidia-smi` gives it, in watts: (maximum power limit, + /// enforced limit, draw), each `None` where it gave none. + pub type SmiPower = (Option, Option, Option); + /// `nvidia-smi`'s view of every GPU: (maximum power limit, enforced limit, /// draw), in watts; `None` without `nvidia-smi`. - pub fn smi() -> Option, Option, Option)>> { + pub fn smi() -> Option> { let out = std::process::Command::new("nvidia-smi") .args(["--query-gpu=power.max_limit,enforced.power.limit,power.draw", "--format=csv,noheader,nounits"]) .output() @@ -157,7 +161,7 @@ mod nvml_oracle { /// GPU `i`'s ceiling in watts: `nvidia-smi`'s maximum power limit, else /// NVML's. - pub fn ceiling_w(nvml: &Nvml, smi: &Option, Option, Option)>>, i: usize) -> Option { + pub fn ceiling_w(nvml: &Nvml, smi: &Option>, i: usize) -> Option { smi.as_ref() .and_then(|s| s.get(i)) .and_then(|(max, _, _)| *max) @@ -318,7 +322,7 @@ mod nvml_oracle { let window = last_at; let rate_w: Vec = first.iter().zip(&prev).map(|(a, b)| b.saturating_sub(*a) as f64 / 1000.0 / window.as_secs_f64().max(1e-9)).collect(); - let draw = |s: &Option, Option, Option)>>, i: usize| s.as_ref().and_then(|s| s.get(i)).and_then(|t| t.2); + let draw = |s: &Option>, i: usize| s.as_ref().and_then(|s| s.get(i)).and_then(|t| t.2); let draws_w: Vec> = (0..n).map(|i| [draw(&before, i), draw(&after, i)].into_iter().flatten().collect()).collect(); let ceiling_w: Vec> = (0..n).map(|i| ceiling_w(&nvml, &after, i)).collect(); // The verdict that speaks for the run is the most severe of its GPUs', -- 2.54.0 (Apple Git-157) From e8ac0fdfec542b6fe5344b2ec091864b93592e96 Mon Sep 17 00:00:00 2001 From: Transaction Science Date: Thu, 5 Nov 2026 10:21:44 -0500 Subject: [PATCH 3/6] eoc-meter: the NVML hardware test's nvidia-smi triple is a type alias tests/nvml_hardware.rs spelled `(Option, Option, Option)` out three times, which clippy flags as type_complexity under `--features cuda`. It is now the oracle's `SmiPower` alias. Clippy -D warnings is clean on Linux (default, cuda) and in the macOS lint step; Linux tests with cuda pass (77). Co-Authored-By: Claude Opus 5.5 --- eoc/eoc-rs/crates/eoc-meter/tests/nvml_hardware.rs | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/eoc/eoc-rs/crates/eoc-meter/tests/nvml_hardware.rs b/eoc/eoc-rs/crates/eoc-meter/tests/nvml_hardware.rs index bc1401c0a..0f328bfed 100644 --- a/eoc/eoc-rs/crates/eoc-meter/tests/nvml_hardware.rs +++ b/eoc/eoc-rs/crates/eoc-meter/tests/nvml_hardware.rs @@ -138,9 +138,13 @@ mod nvml_oracle { } } + /// One GPU as `nvidia-smi` gives it, in watts: (maximum power limit, + /// enforced limit, draw), each `None` where it gave none. + pub type SmiPower = (Option, Option, Option); + /// `nvidia-smi`'s view of every GPU: (maximum power limit, enforced limit, /// draw), in watts; `None` without `nvidia-smi`. - pub fn smi() -> Option, Option, Option)>> { + pub fn smi() -> Option> { let out = std::process::Command::new("nvidia-smi") .args(["--query-gpu=power.max_limit,enforced.power.limit,power.draw", "--format=csv,noheader,nounits"]) .output() @@ -158,7 +162,7 @@ mod nvml_oracle { /// GPU `i`'s ceiling in watts: `nvidia-smi`'s maximum power limit, else /// NVML's. - pub fn ceiling_w(nvml: &Nvml, smi: &Option, Option, Option)>>, i: usize) -> Option { + pub fn ceiling_w(nvml: &Nvml, smi: &Option>, i: usize) -> Option { smi.as_ref() .and_then(|s| s.get(i)) .and_then(|(max, _, _)| *max) @@ -319,7 +323,7 @@ mod nvml_oracle { let window = last_at; let rate_w: Vec = first.iter().zip(&prev).map(|(a, b)| b.saturating_sub(*a) as f64 / 1000.0 / window.as_secs_f64().max(1e-9)).collect(); - let draw = |s: &Option, Option, Option)>>, i: usize| s.as_ref().and_then(|s| s.get(i)).and_then(|t| t.2); + let draw = |s: &Option>, i: usize| s.as_ref().and_then(|s| s.get(i)).and_then(|t| t.2); let draws_w: Vec> = (0..n).map(|i| [draw(&before, i), draw(&after, i)].into_iter().flatten().collect()).collect(); let ceiling_w: Vec> = (0..n).map(|i| ceiling_w(&nvml, &after, i)).collect(); // The verdict that speaks for the run is the most severe of its GPUs', -- 2.54.0 (Apple Git-157) From c0bab664963c514f3ad24c07194db2cceb244e45 Mon Sep 17 00:00:00 2001 From: Transaction Science Date: Thu, 5 Nov 2026 10:21:44 -0500 Subject: [PATCH 4/6] sandbox-meter: the NVML hardware test's nvidia-smi triple is a type alias tests/nvml_hardware.rs spelled `(Option, Option, Option)` out three times, which clippy flags as type_complexity on Linux. It is now the oracle's `SmiPower` alias. Clippy -D warnings is clean on Linux and in the macOS lint step (sandbox-meter, sandbox-proof); Linux tests pass (166). Co-Authored-By: Claude Opus 5.5 --- .../crates/sandbox-meter/tests/nvml_hardware.rs | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/sandbox/sandbox-rs/crates/sandbox-meter/tests/nvml_hardware.rs b/sandbox/sandbox-rs/crates/sandbox-meter/tests/nvml_hardware.rs index bc5812ed0..fdd060c09 100644 --- a/sandbox/sandbox-rs/crates/sandbox-meter/tests/nvml_hardware.rs +++ b/sandbox/sandbox-rs/crates/sandbox-meter/tests/nvml_hardware.rs @@ -139,9 +139,13 @@ mod nvml_oracle { } } + /// One GPU as `nvidia-smi` gives it, in watts: (maximum power limit, + /// enforced limit, draw), each `None` where it gave none. + pub type SmiPower = (Option, Option, Option); + /// `nvidia-smi`'s view of every GPU: (maximum power limit, enforced limit, /// draw), in watts; `None` without `nvidia-smi`. - pub fn smi() -> Option, Option, Option)>> { + pub fn smi() -> Option> { let out = std::process::Command::new("nvidia-smi") .args(["--query-gpu=power.max_limit,enforced.power.limit,power.draw", "--format=csv,noheader,nounits"]) .output() @@ -159,7 +163,7 @@ mod nvml_oracle { /// GPU `i`'s ceiling in watts: `nvidia-smi`'s maximum power limit, else /// NVML's. - pub fn ceiling_w(nvml: &Nvml, smi: &Option, Option, Option)>>, i: usize) -> Option { + pub fn ceiling_w(nvml: &Nvml, smi: &Option>, i: usize) -> Option { smi.as_ref() .and_then(|s| s.get(i)) .and_then(|(max, _, _)| *max) @@ -320,7 +324,7 @@ mod nvml_oracle { let window = last_at; let rate_w: Vec = first.iter().zip(&prev).map(|(a, b)| b.saturating_sub(*a) as f64 / 1000.0 / window.as_secs_f64().max(1e-9)).collect(); - let draw = |s: &Option, Option, Option)>>, i: usize| s.as_ref().and_then(|s| s.get(i)).and_then(|t| t.2); + let draw = |s: &Option>, i: usize| s.as_ref().and_then(|s| s.get(i)).and_then(|t| t.2); let draws_w: Vec> = (0..n).map(|i| [draw(&before, i), draw(&after, i)].into_iter().flatten().collect()).collect(); let ceiling_w: Vec> = (0..n).map(|i| ceiling_w(&nvml, &after, i)).collect(); // The verdict that speaks for the run is the most severe of its GPUs', -- 2.54.0 (Apple Git-157) From 124b019b33083217cd00af0a4649f711aba7c563 Mon Sep 17 00:00:00 2001 From: Transaction Science Date: Thu, 5 Nov 2026 10:21:57 -0500 Subject: [PATCH 5/6] Joule Code L3 example: clippy-clean - src/llama_backend.rs: `rsplit(|c: char| c == '/' || c == ' ')` is now `rsplit(['/', ' '])` (manual_char_comparison); it splits the same way. - src/bin/run.rs: the host test's catch-all arm asserted `!cfg!(macOS on aarch64)`, a constant assertion (assertions_on_constants). It is now an `if cfg!(...)` that panics with the same message. - tests/common/mod.rs: each test binary compiles the shared module on its own, and the seeded test calls no `resolve_priced_at`. It gets the per-item `#[allow(dead_code)]` its sibling `resolve_seeded` already has, with the reason. `#[expect]` cannot work here: it would be unfulfilled in the binaries that do call it. `cargo clippy --all-targets --no-deps -- -D warnings` is clean on Linux and macOS, and the tests pass (16). The path dependencies' own rustc warnings (jouleclaw-backend-apple, jouleclaw-topology, jouleclaw-backend-reference on Linux) are not this crate's and are not denied by `--no-deps`. Co-Authored-By: Claude Opus 5.5 --- joule-code/examples/l3-jouleclaw/src/bin/run.rs | 4 +++- joule-code/examples/l3-jouleclaw/src/llama_backend.rs | 2 +- joule-code/examples/l3-jouleclaw/tests/common/mod.rs | 4 ++++ 3 files changed, 8 insertions(+), 2 deletions(-) diff --git a/joule-code/examples/l3-jouleclaw/src/bin/run.rs b/joule-code/examples/l3-jouleclaw/src/bin/run.rs index b026f9711..7bd2c5bc1 100644 --- a/joule-code/examples/l3-jouleclaw/src/bin/run.rs +++ b/joule-code/examples/l3-jouleclaw/src/bin/run.rs @@ -724,7 +724,9 @@ mod tests { assert_eq!(note, "estimated by apple-silicon from host load"); } _ => { - assert!(!cfg!(all(target_os = "macos", target_arch = "aarch64")), "a Mac with no host counter: {name}"); + if cfg!(all(target_os = "macos", target_arch = "aarch64")) { + panic!("a Mac with no host counter: {name}"); + } assert_eq!((name, from_counter), ("none", false)); assert_eq!(e, Energy::from_tokens(7, 9)); } diff --git a/joule-code/examples/l3-jouleclaw/src/llama_backend.rs b/joule-code/examples/l3-jouleclaw/src/llama_backend.rs index bb5a9b197..99dc2b40e 100644 --- a/joule-code/examples/l3-jouleclaw/src/llama_backend.rs +++ b/joule-code/examples/l3-jouleclaw/src/llama_backend.rs @@ -245,7 +245,7 @@ fn count_before(stderr: &str, unit: &str) -> Option { for line in stderr.lines() { if let Some(idx) = line.find(&needle) { let prefix = &line[..idx]; - let token = prefix.rsplit(|c: char| c == '/' || c == ' ').find(|s| !s.is_empty()); + let token = prefix.rsplit(['/', ' ']).find(|s| !s.is_empty()); if let Some(n) = token.and_then(|t| t.trim().parse::().ok()) { return Some(n); } diff --git a/joule-code/examples/l3-jouleclaw/tests/common/mod.rs b/joule-code/examples/l3-jouleclaw/tests/common/mod.rs index 4c36d3fec..3805dbd97 100644 --- a/joule-code/examples/l3-jouleclaw/tests/common/mod.rs +++ b/joule-code/examples/l3-jouleclaw/tests/common/mod.rs @@ -43,6 +43,10 @@ impl LlmBackend for OneMatmul { /// declaring none), switch the fabric on for this process, resolve one L3 /// request, and return its receipt energy with the ledger window it was priced /// from. Call once per test process: the fabric is discovered once. +// Each test binary compiles this module on its own, and the seeded test does +// not price a row, so there this helper is unused (as `resolve_seeded` is in +// the others). +#[allow(dead_code)] pub fn resolve_priced_at(tag: &str, grade: Option) -> (Energy, Vec) { let path = std::path::Path::new(env!("CARGO_TARGET_TMPDIR")).join(format!("l3-fabric-grade-{tag}.json")); let declared = grade.map(|g| format!(r#","provenance":"{g:?}""#)).unwrap_or_default(); -- 2.54.0 (Apple Git-157) From 48412b8df405e0e25b6184ef64f31ce4457d1550 Mon Sep 17 00:00:00 2001 From: Transaction Science Date: Thu, 5 Nov 2026 10:21:57 -0500 Subject: [PATCH 6/6] ci: lint the meter crates' Linux configurations, and the L3 example The macOS lint step lints jcp-energy, eoc-meter, sandbox-meter and jouleclaw-energy only as macOS builds them. The matrix's clippy gate is opt-in per workspace, and none of these workspaces has it. So their Linux code (RAPL through powercap and the MSRs, NVML, CUDA) was linted by no job. jouleclaw-energy's `rapl` build carried a dead function, and four crates' NVML hardware tests a clippy error, for as long as they existed. - standards-build.yml: a matrix key `meter_lint` lists configurations (`package` or `package:features`), and a step "clippy on the Linux meter code" lints each one with `--all-targets --no-deps -D warnings` on the workspace's own runner, beside the feature-gated energy tests. The entries: - jcp-rs: jcp-energy, jcp-energy:nvml - eoc-rs: eoc-meter, eoc-meter:cuda - sandbox-rs: sandbox-meter - jouleclaw-rs: jouleclaw-energy, and with rapl, nvml and rapl,nvml scripts/standards-touched.py reads the new key like the others. - joule-code-conformance.yml: "L3 JouleClaw binding example lints clean" (`--no-deps`), after its tests. The step's loop was run verbatim on Linux x86_64 for each entry: all clean. Both workflows parse, and the workflow-concurrency check passes. Co-Authored-By: Claude Opus 5.5 --- .github/workflows/joule-code-conformance.yml | 6 ++++ .github/workflows/standards-build.yml | 30 +++++++++++++++++--- 2 files changed, 32 insertions(+), 4 deletions(-) diff --git a/.github/workflows/joule-code-conformance.yml b/.github/workflows/joule-code-conformance.yml index e0b149410..f76ba2d89 100644 --- a/.github/workflows/joule-code-conformance.yml +++ b/.github/workflows/joule-code-conformance.yml @@ -223,6 +223,12 @@ jobs: working-directory: joule-code/examples/l3-jouleclaw run: cargo test + # Its own code only (`--no-deps`): the JouleClaw crates it builds through + # path dependencies are linted by their own workspace. + - name: L3 JouleClaw binding example lints clean + working-directory: joule-code/examples/l3-jouleclaw + run: cargo clippy --all-targets --no-deps -- -D warnings + # The MOQT relay, at draft-22 and, through its bridge, -18 and -16 (tests/drafts.rs, # tests/publish_done_streams.rs). Every test is on loopback: two publishers and three # subscribers over native QUIC, WebTransport over HTTP/3 and the WebSocket fallback; a diff --git a/.github/workflows/standards-build.yml b/.github/workflows/standards-build.yml index 46439dde2..b42184e4b 100644 --- a/.github/workflows/standards-build.yml +++ b/.github/workflows/standards-build.yml @@ -77,12 +77,12 @@ jobs: energy: ${{ steps.plan.outputs.energy }} env: WORKSPACES: | - - { name: jcp-rs, dir: jcp/jcp-rs, runner: linux, conformance: jcp-conformance, feature_tests: "-p jcp-energy --features nvml" } + - { name: jcp-rs, dir: jcp/jcp-rs, runner: linux, conformance: jcp-conformance, feature_tests: "-p jcp-energy --features nvml", meter_lint: "jcp-energy jcp-energy:nvml" } # sandbox-tee's certificate-chain verifiers sit behind features (their # X.509 and RSA dependencies are heavy), so a plain `cargo test` never # runs their tests: `amd-kds` (SEV-SNP's VCEK to AMD's root) and # `intel-pcs` (TDX's PCK to Intel's root). - - { name: sandbox-rs, dir: sandbox/sandbox-rs, runner: linux, conformance: sandbox-conformance, feature_tests: "-p sandbox-tee --features amd-kds,intel-pcs" } + - { name: sandbox-rs, dir: sandbox/sandbox-rs, runner: linux, conformance: sandbox-conformance, feature_tests: "-p sandbox-tee --features amd-kds,intel-pcs", meter_lint: "sandbox-meter" } - { name: smart-byte-rs, dir: smart-byte/smart-byte-rs, runner: linux } - { name: pool-rs, dir: pool/pool-rs, runner: linux } # `clippy: true` adds the zero-warning gate below. It is opt-in per @@ -139,7 +139,7 @@ jobs: # able to fail becomes a finding rather than staying green. - { name: proof-rs, dir: proof/proof-rs, runner: linux, z3: true, conformance: proof-conformance, applied: proof/conformance/v1/joulespec.toml } - { name: joulehook-rs, dir: joulehook/joulehook-rs, runner: linux } - - { name: eoc-rs, dir: eoc/eoc-rs, runner: linux, feature_tests: "-p eoc-meter --features cuda" } + - { name: eoc-rs, dir: eoc/eoc-rs, runner: linux, feature_tests: "-p eoc-meter --features cuda", meter_lint: "eoc-meter eoc-meter:cuda" } # mesh-openai's `serve_example` test (the reference server seals what # its meter read, never a fixture's figure) has required-features # `server`, so `cargo test --workspace` builds none of it; naming the @@ -163,7 +163,7 @@ jobs: # failing for no apparent reason, check `df -h /mnt/lima-colima-txarm` # on the txarm VM before suspecting the code: a full cache volume # fails whatever happens to be building, not whatever changed. - - { name: jouleclaw-rs, dir: jouleclaw/jouleclaw-rs, runner: linux-arm64, rustflags: "-C target-feature=+fp16", cache_suffix: "-nodebug", feature_tests: "-p jouleclaw-energy --features rapl,nvml" } + - { name: jouleclaw-rs, dir: jouleclaw/jouleclaw-rs, runner: linux-arm64, rustflags: "-C target-feature=+fp16", cache_suffix: "-nodebug", feature_tests: "-p jouleclaw-energy --features rapl,nvml", meter_lint: "jouleclaw-energy jouleclaw-energy:rapl jouleclaw-energy:nvml jouleclaw-energy:rapl,nvml" } steps: - uses: actions/checkout@v5 with: @@ -456,6 +456,28 @@ jobs: RUSTFLAGS: ${{ matrix.rustflags }} run: cargo test ${{ matrix.feature_tests }} + # The meter crates' Linux side: RAPL (powercap and the MSRs), NVML and + # CUDA are Linux code or sit behind features no workspace member enables, + # and the macOS lint step lints these crates only as macOS builds them. + # So no job linted them here, and jouleclaw-energy's `rapl` build carried + # a dead function, and four crates' NVML hardware tests a clippy error, + # for as long as they existed. Each `meter_lint` entry is a package, or + # `:`, linted on the workspace's own runner. + - name: clippy on the Linux meter code + if: matrix.meter_lint + working-directory: ${{ matrix.dir }} + shell: bash + env: + RUSTFLAGS: ${{ matrix.rustflags }} + run: | + set -eu + for config in ${{ matrix.meter_lint }}; do + package=${config%%:*} + features=() + [ "$config" = "$package" ] || features=(--features "${config#*:}") + cargo clippy -p "$package" "${features[@]}" --all-targets --no-deps -- -D warnings + done + # The page-set packages are not committed; their catalogue is, naming # each package by its content. Any change to what they are built from — # the sources, the app's translations and gloss audits, the symbol -- 2.54.0 (Apple Git-157)