energy meters: a GPU counter reading low is refuted in sandbox-meter, eoc-meter and jcp-energy too #354

Merged
dcharlot merged 1 commit from fix/nvml-low-counter-not-a-reading into main 2026-10-20 08:27:53 -04:00
Owner

What was open

#341 bounded an NVML cumulative-energy counter from below in jouleclaw-energy. Three more meter crates carry the same plausibility check, and each still judged a counter in one direction only:

  • sandbox-meter (its NVML probe)
  • eoc-meter (its cuda GPU telemetry)
  • jcp-energy (feature nvml)

A counter that accrued a fraction of what its board drew still advanced, so the liveness rule called it live. It was then graded HwShunt and spent an energy ceiling it was not measuring. Under-reporting is the unsafe direction at a ceiling (jcp SPEC §5). A counter running fast fails safe.

What this changes

  • CounterUnderRate in all three crates. It is judged against the same board telemetry with the same constants as #341: floor = (mean_usable_draw − 5 W) / 4. A counter one meter declines, another therefore does not admit. The slack comes off before the division, so an idle board makes no finding. The verdict carries the floor and the draw it was taken from.
  • sandbox-meter ranking. sandbox-meter judges several GPUs per run. An under-report outranks an over-report there, and between two under-reports the larger shortfall speaks.
  • The verdict mapping is now tested on every platform. sandbox-meter's NVML probe builds only on Linux. A mutation of its verdict-to-status mapping therefore survived every test on the macOS build host and would have been caught only by CI's Linux legs. The mapping now lives in the shared liveness module (gpu_counter_status), which builds everywhere.
  • jcp SPEC §5.1. The plausibility rule is now two-sided. The floor allows for the draw reading's imprecision and never fires near idle, and either bound refutes, never verifies.
  • jouleclaw SPEC §1.3. It said the reference implementation "already falls back" to the power integral on an unvalidated GPU. It does not tell a validated part from an unvalidated one. It falls back only where it can refute the counter, and the bound is deliberately wide: a counter 13.3 % low passes it and is graded HwShunt until something it shares no error with, such as an external meter, validates it. The text now says so.

Not changed

The meter name is "nvml" in both modes, but each reading's provenance already separates them: HwShunt for the counter, ModelBased for the power integral.

Verification (build host)

  • Tests pass.
    • sandbox-meter: 171 lib tests.
    • eoc-meter: 82 lib tests.
    • jcp-energy: 117 lib tests.
    • 7 of these are new.
    • The feature builds (jcp-energy nvml, eoc-meter cuda) compile.
  • Mutations. All 12 mutations of the new logic are killed:
    • for each crate: the floor removed, an under-report mapped to Live, the slack not subtracted;
    • sandbox-meter only: the under-report ranked low, ordering by rate instead of shortfall, and the moved mapping.
  • Clippy.
    • The macOS clippy gate is clean on every crate it lints.
    • sandbox-meter's library and unit tests are clippy-clean for x86_64-unknown-linux-gnu.
    • Its Linux-only tests/nvml_hardware.rs fails clippy::type_complexity three times. That file predates this PR and is not in any gate.
  • Repo checks. tests-in-ci, spec-refs, orphan-sources, vanity-metrics and comparative-prose all pass.

🤖 Generated with Claude Code

## What was open #341 bounded an NVML cumulative-energy counter from below in jouleclaw-energy. Three more meter crates carry the same plausibility check, and each still judged a counter in one direction only: - `sandbox-meter` (its NVML probe) - `eoc-meter` (its `cuda` GPU telemetry) - `jcp-energy` (feature `nvml`) A counter that accrued a fraction of what its board drew still advanced, so the liveness rule called it live. It was then graded `HwShunt` and spent an energy ceiling it was not measuring. Under-reporting is the unsafe direction at a ceiling (jcp SPEC §5). A counter running fast fails safe. ## What this changes - **`CounterUnderRate` in all three crates.** It is judged against the same board telemetry with the same constants as #341: `floor = (mean_usable_draw − 5 W) / 4`. A counter one meter declines, another therefore does not admit. The slack comes off before the division, so an idle board makes no finding. The verdict carries the floor and the draw it was taken from. - **sandbox-meter ranking.** sandbox-meter judges several GPUs per run. An under-report outranks an over-report there, and between two under-reports the larger shortfall speaks. - **The verdict mapping is now tested on every platform.** sandbox-meter's NVML probe builds only on Linux. A mutation of its verdict-to-status mapping therefore survived every test on the macOS build host and would have been caught only by CI's Linux legs. The mapping now lives in the shared `liveness` module (`gpu_counter_status`), which builds everywhere. - **jcp SPEC §5.1.** The plausibility rule is now two-sided. The floor allows for the draw reading's imprecision and never fires near idle, and either bound refutes, never verifies. - **jouleclaw SPEC §1.3.** It said the reference implementation "already falls back" to the power integral on an unvalidated GPU. It does not tell a validated part from an unvalidated one. It falls back only where it can refute the counter, and the bound is deliberately wide: a counter 13.3 % low passes it and is graded `HwShunt` until something it shares no error with, such as an external meter, validates it. The text now says so. ## Not changed The meter name is `"nvml"` in both modes, but each reading's provenance already separates them: `HwShunt` for the counter, `ModelBased` for the power integral. ## Verification (build host) - **Tests pass.** - sandbox-meter: 171 lib tests. - eoc-meter: 82 lib tests. - jcp-energy: 117 lib tests. - 7 of these are new. - The feature builds (jcp-energy `nvml`, eoc-meter `cuda`) compile. - **Mutations.** All 12 mutations of the new logic are killed: - for each crate: the floor removed, an under-report mapped to `Live`, the slack not subtracted; - sandbox-meter only: the under-report ranked low, ordering by rate instead of shortfall, and the moved mapping. - **Clippy.** - The macOS clippy gate is clean on every crate it lints. - sandbox-meter's library and unit tests are clippy-clean for `x86_64-unknown-linux-gnu`. - Its Linux-only `tests/nvml_hardware.rs` fails `clippy::type_complexity` three times. That file predates this PR and is not in any gate. - **Repo checks.** tests-in-ci, spec-refs, orphan-sources, vanity-metrics and comparative-prose all pass. 🤖 Generated with [Claude Code](https://claude.com/claude-code)
energy meters: a GPU counter reading low is refuted in sandbox-meter, eoc-meter and jcp-energy too
All checks were successful
energy meters on real hardware / RAPL and NVML on jetson-hub (pull_request) Successful in 47s
standards workspaces build + test / which workspaces this change touches (pull_request) Successful in 6s
repository checks / lockfiles, tests in CI, workflow hygiene, spec and section references, public text (pull_request) Successful in 1m11s
standards workspaces build + test / joulecontract-rs (joulecontract/joulecontract-rs, joulecontract-rs, linux-arm64, true) (pull_request) Successful in 1m49s
standards workspaces build + test / jouleclaw-rs (-nodebug, jouleclaw/jouleclaw-rs, -p jouleclaw-energy --features rapl,nvml, jouleclaw-rs, linux-arm64, -C target-feature=+fp16) (pull_request) Successful in 3m49s
standards workspaces build + test / mesh-rs (mesh/mesh-rs, -p mesh-engine-gguf -p mesh-openai --features mesh-engine-gguf/gguf,mesh-openai/server, mesh-rs, linux-arm64) (pull_request) Successful in 1m8s
standards workspaces build + test / joule-code-rs (joule-code/joule-code-rs, joule-code-rs, linux-arm64, true) (pull_request) Successful in 4m2s
standards workspaces build + test / jcp-rs (jcp-conformance, jcp/jcp-rs, -p jcp-energy --features nvml, jcp-rs, linux) (pull_request) Successful in 1m53s
standards workspaces build + test / eoc-rs (eoc/eoc-rs, -p eoc-meter --features cuda, eoc-rs, linux) (pull_request) Successful in 2m8s
standards workspaces build + test / joule-ui-rs (joule-ui/joule-ui-rs, joule-ui-rs, linux) (pull_request) Successful in 1m9s
standards workspaces build + test / joulehook-rs (joulehook/joulehook-rs, joulehook-rs, linux) (pull_request) Successful in 1m12s
standards workspaces build + test / proof-rs (proof-conformance, proof/proof-rs, proof-rs, linux, true) (pull_request) Successful in 1m31s
standards workspaces build + test / sandbox-rs (sandbox-conformance, sandbox/sandbox-rs, sandbox-rs, linux) (pull_request) Successful in 2m24s
standards workspaces build + test / macOS energy backends (pull_request) Successful in 7m14s
standards workspaces build + test / jouledesk-rs (jouledesk/jouledesk-rs, jouledesk-rs, macos) (pull_request) Successful in 2m37s
f18337dc81
#341 bounded an NVML cumulative-energy counter from below in
jouleclaw-energy. The same plausibility check exists in three more meter
crates, and each still judged the counter in one direction only. A counter
that accrued a fraction of what its board drew still advanced, so the
liveness rule called it live. It was then graded `HwShunt` and spent an
energy ceiling it was not measuring. Under-reporting is the unsafe direction
at a ceiling (jcp SPEC §5): it admits work the budget cannot cover. A counter
running fast fails safe.

sandbox-meter, eoc-meter and jcp-energy now carry `CounterUnderRate`, judged
against the same board telemetry and with the same constants as #341:

    floor = (mean_usable_draw - 5 W) / 4

So a counter one meter declines, another does not admit. The slack comes
off the draw before the division, so an idle board makes no finding. The
verdict carries the floor and the draw it was taken from. In sandbox-meter,
which judges several GPUs per run, an under-report outranks an over-report,
and the larger shortfall speaks.

sandbox-meter's NVML probe only builds on Linux, so its verdict-to-status
mapping was tested only by CI's Linux legs. The mapping now lives in the
shared `liveness` module (`gpu_counter_status`), which builds and is tested on
every platform.

SPEC changes:
- jcp §5.1: the plausibility rule is now two-sided, with the floor allowing
  for the draw's imprecision and never firing near idle.
- jouleclaw §1.3: no longer claims the reference implementation already falls
  back to the power integral on an unvalidated GPU. It falls back only where
  it can refute the counter, and the bound is wide: a counter 13.3 % low
  passes it and is graded `HwShunt` until something it shares no error with
  validates it.

Tests: 7 new across the three crates. All 12 mutations of the new logic are
killed.

Co-Authored-By: Claude Opus 5.5 <[email protected]>
Sign in to join this conversation.
No reviewers
No labels
No milestone
No project
No assignees
1 participant
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set

Reference
Transaction-Science/open-standards!354
No description provided.