jcp: an energy figure must say how much of the work it covers (re-land) #67
Loading…
Reference in a new issue
No description provided.
Delete branch "jcp/energy-coverage-relanded"
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?
Energy { measured_uj, estimated_uj, provenance }.provenanceanswers how the number was acquired. Nothing answered how much of the task it accounts for — two different questions, routinely conflated to the figure's advantage.The concrete case: on a host where the accelerator exposes an energy counter but the CPU does not, a caller reads the accelerator and
Energy::measured()stampsHwShunton a figure presented as the task's energy. The CPU's share is not zero — it is unmeasured and silently missing. The reading is honest about its sensor and dishonest about its scope, and neither the type nor the receipt could tell the difference.The design
Coverage { Whole, Partial }sits beside provenance rather than inside it, because the axes really are independent: a partial reading is still a genuine sensor reading, andcheck_provenanceis untouched.Energy::measured_partialexists so the honest case is as easy to express as the flattering one. Without it, a caller holding a partial reading reaches formeasured()and the figure claims the whole task by default.The distinction is carried into the sealed receipt, not just the type. Had it stopped at the type, a partial reading would reach a verifier looking exactly like a whole one — the very failure the field was added to prevent.
Wholeis the default and is omitted from the wire, so every receipt sealed before this field canonicalizes to the same bytes, and a legacy payload with nocoveragekey parses asWhole. Both are pinned by tests; published vectors are unchanged on disk.On blast radius — I was wrong, twice
I first declined this change on a measurement of "85 literal sites across 8 workspaces". That was wrong: a grep for
Energy {had swept upmesh::Energy,proof::Energy,DeviceEnergyandAttestedEnergy— different types entirely. A second, import-filtered grep then said 2, which was also wrong in the other direction.The compiler put the real figure at one site: a test inside
jcp-schemaitself.Checked before and again after the receipt change, since cross-workspace breakage is the entire risk of editing this crate — and this is the crate whose last field addition broke four workspaces, three unnoticed for weeks.
Verification
240 jcp-rs tests pass · conformance passes all classes · published vectors unchanged on disk · all seven dependent workspaces check clean.
`Energy { measured_uj, estimated_uj, provenance }`. `provenance` answers *how* the number was acquired and nothing answers *how much of the task it accounts for* — two different questions, routinely conflated to the figure's advantage. The concrete case: on a host where the accelerator exposes an energy counter but the CPU does not, a caller reads the accelerator and `Energy::measured()` stamps `HwShunt` on a figure presented as the task's energy. The CPU's share is not zero; it is unmeasured and silently missing. The reading is honest about its sensor and dishonest about its scope, and nothing in the type or the receipt could tell the difference. `Coverage { Whole, Partial }` sits beside provenance rather than inside it, because the axes really are independent: a partial reading is still a genuine sensor reading, and `check_provenance` is untouched. `Energy::measured_partial` exists so the honest case is as easy to express as the flattering one — without it, a caller holding a partial reading reaches for `measured()` and the figure claims the whole task by default. The distinction is carried into the sealed receipt, not just the type. Had it stopped at the type, a partial reading would reach a verifier looking exactly like a whole one, which is the failure the field was added to prevent. `Whole` is the default and is omitted from the wire, so every receipt sealed before this field canonicalizes to the same bytes, and a legacy payload with no `coverage` key parses as `Whole` — both pinned by tests, and the published vectors are unchanged on disk. On blast radius: I first declined this change on a measurement of "85 literal sites across 8 workspaces", which was wrong — a grep for `Energy {` had swept up `mesh::Energy`, `proof::Energy`, `DeviceEnergy` and `AttestedEnergy`, which are different types. The compiler put the real figure at **one** site, a test inside `jcp-schema` itself. Every one of the eight path-depending workspaces compiles untouched, checked before and again after the receipt change, since that is the whole risk of editing this crate. Verified: 240 jcp-rs tests pass, conformance passes all classes, published vectors unchanged, and joule-code / joule-ui / jouleclaw / joulehook / jouledesk / sandbox / mesh all check clean with zero errors.