compliance: derive the A-G band instead of accepting one #64
Loading…
Reference in a new issue
No description provided.
Delete branch "compliance/banding-function"
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?
EnergyLabelis an A–G enum with an ordering and a description, and nothing in this workspace ever derived one. Every use supplies a letter the caller had already decided:The label was a container for someone else's judgement — the one shape a rating must not have. And the only threshold rule that did exist is:
Two magic floats, no provenance, no version, and no way to band anything.
BandingScale::rateis the missing function. What matters is less the arithmetic than what it refuses to let a caller do.A letter is not a rating
Two facilities both rated "B" under different threshold sets are not comparable, and nothing about the letter says so. A
Ratingtherefore cannot be constructed without its scale — it carriesscale_id, metric, unit, and the measured value, so a reader re-derives the letter rather than trusting it.comparable_withis an explicit check.better_thanreturnsNonefor incomparable ratings rather thanOrdering::Equal— refusing to rank is a different answer from ranking equal, and collapsing the two is exactly how a bare enum invites the mistake.A revision is a different scale
Because
scale_idtravels inside every rating, re-tuning thresholds cannot silently re-band history. The test pins a value that is C under v1 and D under v2, and shows the two ratings do not compare.The rest
milli_puerather than1.5. A float boundary makes the band depend on how the value was parsed, and band edges are precisely where that bites.validaterejects them andraterefuses rather than emitting a band from a scale that cannot rank. A scale must also carry an id and a unit — a rating that cannot cite its scale is back to being a bare letter.No canonical scale is shipped
The examples in the tests are named
example.*on purpose. Which thresholds are correct for a given metric is a policy question this crate has no standing to settle, and baking one in would repeat thepue < 1.5mistake with more ceremony.Verification
43 crate tests pass (7 new), no clippy warnings in the new file.
`EnergyLabel` is an A–G enum with an ordering and a description, and nothing in this workspace ever *derived* one — every use supplies a letter the caller had already decided (`build_sample("svc-1", 0.35, EnergyLabel::A)`). The label was a container for someone else's judgement, which is the one shape a rating must not have. The only threshold rule that did exist, `EuComplianceReport::is_compliant`, is a hardcoded `pue < 1.5 && renewable_pct >= 50.0`: two magic floats with no provenance, no version, and no way to band anything. `BandingScale::rate` is the missing function. What matters is less the arithmetic than what it refuses to let a caller do. **A letter is not a rating.** Two facilities both rated "B" under different threshold sets are not comparable, and nothing about the letter says so. A `Rating` therefore cannot be constructed without its scale: it carries the `scale_id`, the metric, the unit, and the measured value, so a reader re-derives the letter rather than trusting it. `comparable_with` is an explicit check, and `better_than` returns `None` for incomparable ratings rather than `Ordering::Equal` — refusing to rank is a different answer from ranking equal, and collapsing them is exactly how a bare enum invites the mistake. **A revision is a different scale.** Because the `scale_id` travels inside every rating, re-tuning thresholds cannot silently re-band history — the test pins a value that is C under v1 and D under v2, and shows the two ratings do not compare. **Scales are data, not match arms.** A new scale is a value, not a recompile. **Integers, in a declared unit.** Thresholds are `u64` in a unit the scale names (milli-PUE rather than `1.5`), matching the receipt family's discipline: a float boundary makes the band depend on how the value was parsed, and band edges are precisely where that bites. **Boundaries earn the better band**, stated once and tested at every edge, so "on the line" is not left to the reader. **A non-monotonic scale cannot rate at all.** Overlapping boundaries would assign different letters to one value depending on evaluation order, so `validate` rejects them and `rate` refuses rather than emitting a band from a scale that cannot rank. A scale must also carry an id and a unit, since a rating that cannot cite its scale is back to being a bare letter. No scale is shipped as canonical. The examples in the tests are named `example.*` on purpose: which thresholds are correct for a given metric is a policy question this crate has no standing to settle, and baking one in would repeat the `pue < 1.5` mistake with more ceremony. Verified: 43 crate tests pass (7 new), no clippy warnings in the new file.