jcp §5: a GPU counter's plausibility verdict was a bool, and conflated two findings #185
Loading…
Reference in a new issue
No description provided.
Delete branch "fix/gpu-plausibility-magnitude"
Deleting a branch is permanent. Although the deleted branch may continue to exist for a short time before it actually gets removed, it CANNOT be undone in most cases. Continue?
plausible_gpu_countercompares a counter's implied rate against two bounds —1.5× the board's maximum power limit, and 2× the board's mean draw plus 5 W —
and returned
bool.What the bool threw away
Everything that made the comparison useful was discarded at the return: which
bound broke, by how much, and the rate it broke it at. A counter a tenth
over a bound and one twenty times over were the same answer.
That also made the judgement irreproducible. The margins are constants in this
crate; re-grading a past refusal against a revised margin needs the rate, and the
rate did not survive the check.
It conflated two findings
One branch fired when the board's own draw reading exceeded the board's own
limit — an RTX 4050 Laptop GPU reports about 590 W for a second after it wakes.
That says the yardstick is broken, not that the counter is overstating. Yet
CounterStatus::Implausible's doc asserted:…for a case whose evidence does not support it. A broken yardstick is an
indeterminate.
The verdict now carries its figures
CounterStatusgainsUnjudgeablefor the last. Both still decline the rung— unjudgeable is not admissible and declining is the safe direction — so
selection behaviour is unchanged. What changes is the diagnosis, which is the
difference between replacing a counter and waiting for a board to settle.
The hardware job corrected my first shape of this
I had the broken-reading check void the whole judgement. The real RTX 4050 on
jetson-hub refused it: one 590 W post-wake spike among otherwise sane 14.8 W
samples turned a counter running persistently at four to thirty times the board's
draw into "cannot judge" — a worse diagnosis than the overrun it actually is,
and a disagreement with the test's own independent oracle.
A reading past the board's own limit is now discarded individually, and only
that reading. One broken sample is not a broken bracket.
Unjudgeableisreserved for a bracket with no usable reading left at all.
That also fixes something the old code hid: the mean summed every reading, so
a 590 W spike inflated it and made the mean-draw bound more permissive. It was
invisible before only because any such reading short-circuited the check first. A
test pins it, asserting the spike-inflated mean would have admitted a counter the
sane reading alone refuses.
And when both bounds break, the power limit is reported: a board cannot draw
past its own limit by construction, while the mean-draw bound is soft (telemetry
lags a load step). Being a static spec value rather than a reading, the limit is
never discarded either — so a broken draw sample cannot excuse a counter that
overran it outright.
Spec
§5 gains Plausibility (REQUIRED where a bound is readable) beside the
existing Liveness requirement — the spec said nothing about this, and liveness
alone would admit the RTX 4050's counter, which advances in every sample
interval while running at four to thirty times the board's draw. Perfectly live,
and no count of that board's energy.
The new text requires the rate be checked against an independently-read bound
where one exists, SHOULD-records the rate and the bound rather than only the
refusal, and requires an unusable bound reading be reported as unjudgeable
rather than as a counter that overran. Where no bound is readable the requirement
does not apply and liveness stands alone.
A test of mine that was wrong
I first asserted the mean-draw bound binds on the jetson-hub figures. It does
not: 119.5 W is over the 97.5 W power cap, so that bound binds. The code was
right and the test was wrong. Both cases are now pinned separately, plus a case
where the mean-draw bound binds alone (44 W inside a 97.5 W cap, past 2 × 10.4 W
Verification
jcp-rsworkspace 403 passed, clippy clean onjcp-energy.Implausiblea_live_gpu_counter_past_its_board_is_implausiblePowerLimitthe_verdict_says_which_bound_broke_and_by_how_muchUnjudgeableadmitted as selectable🤖 Generated with Claude Code
`plausible_gpu_counter` compares a counter's implied rate against two bounds — 1.5x the board's maximum power limit, and 2x the board's mean draw plus 5 W — and returned `bool`. Everything that made the comparison useful was discarded at the return: which bound broke, by how much, and the rate it broke it at. A counter a tenth over a bound and one twenty times over were the same answer. That also made the judgement irreproducible: the margins are constants in this crate, and re-grading a past refusal against a revised margin needs the rate, which did not survive. It conflated two findings, too. One branch fired when the **board's own draw reading** exceeded the board's own limit — an RTX 4050 Laptop GPU reports about 590 W for a second after it wakes. That tells you the yardstick is broken, not that the counter is overstating, and `CounterStatus::Implausible`'s doc then asserted "it is not counting the board's energy" for a case whose evidence does not support it. A broken yardstick is an indeterminate. `GpuPlausibility` now carries the verdict with its figures: `Plausible { rate_mw }`, `CounterOverRate { rate_mw, bound_mw, bound }` with `GpuBound ∈ { PowerLimit, MeanDraw }`, and `BoardTelemetryUnusable { draw_mw, limit_mw }`. `CounterStatus` gains `Unjudgeable` for the last. Both still decline the rung — unjudgeable is not admissible and declining is the safe direction — so selection behaviour is unchanged; what changes is the diagnosis, which is the difference between replacing a counter and waiting for a board to settle. Two ordering choices, both written down where they are made. The board's reading is checked **first**: a counter measured against a yardstick known to be wrong would be reported with a magnitude that means nothing, so a broken reading yields no magnitude at all. And when both bounds break, the power limit is reported, because a board cannot draw past its own limit by construction while the mean-draw bound is soft (telemetry lags a load step) — naming the harder bound is the more informative diagnosis. SPEC §5 gains **Plausibility (REQUIRED where a bound is readable)** beside the existing Liveness requirement. Liveness is necessary and not sufficient, and the spec said nothing about this: the RTX 4050's counter advances in every sample interval while running at four to thirty times the board's draw — perfectly live, and no count of that board's energy. The new text requires the rate be checked against an independently-read bound where one exists, SHOULD-records the rate and the bound rather than only the refusal, and requires that an unusable bound reading be reported as unjudgeable rather than as a counter that overran. Where no bound is readable the requirement does not apply and liveness stands alone. One of my own tests was wrong first time and the code was right: I asserted the mean-draw bound bound first on the jetson-hub figures, but 119.5 W is over the 97.5 W power cap, so that bound binds. Both cases are now pinned separately, with a case where the mean-draw bound binds alone. jcp-rs workspace: 403 passed, clippy clean on jcp-energy. Co-Authored-By: Claude Opus 5 <[email protected]>4e9a6d6adfaa551552a2