open-standards/jouleclaw/scales/README.md
David Charlot 4d9236fe1c
Some checks failed
jouleclaw public surface must stay documented / Public-surface audit (jouleclaw-rs) (pull_request) Successful in 1m3s
no-vanity-metrics / Scan committed Markdown for vanity metrics (pull_request) Successful in 4s
standards workspaces build + test / aac-rs (pull_request) Successful in 1m37s
standards workspaces build + test / eoc-rs (pull_request) Successful in 1m47s
standards workspaces build + test / joule-code-rs (pull_request) Successful in 2m1s
standards workspaces build + test / jcp-rs (pull_request) Successful in 1m14s
standards workspaces build + test / proof-rs (pull_request) Successful in 1m10s
standards workspaces build + test / sandbox-rs (pull_request) Successful in 2m1s
standards workspaces build + test / smart-byte-rs (pull_request) Successful in 2m32s
WAI conformance / cargo-class corpora · linux (pull_request) Successful in 33s
WAI conformance / cross-arch byte-equality · linux (pull_request) Successful in 18s
standards workspaces build + test / jouleclaw-rs (pull_request) Successful in 7m19s
standards workspaces build + test / joulecontract-rs (pull_request) Successful in 1m18s
standards workspaces build + test / map-rs (pull_request) Successful in 1m11s
standards workspaces build + test / mesh-rs (pull_request) Successful in 53s
standards workspaces build + test / openpay (pull_request) Successful in 3m43s
WAI conformance / cargo-class corpora · linux-arm64 (pull_request) Successful in 1m7s
WAI conformance / cross-arch byte-equality · linux-arm64 (pull_request) Successful in 33s
standards workspaces build + test / arl-rs (pull_request) Successful in 26m42s
standards workspaces build + test / joule-ui-rs (pull_request) Successful in 14m25s
standards workspaces build + test / jouledesk-rs (pull_request) Successful in 11m21s
standards workspaces build + test / joulehook-rs (pull_request) Successful in 9m52s
standards workspaces build + test / sense-rs (pull_request) Successful in 8m13s
WAI conformance / cargo-class corpora · macos (pull_request) Successful in 1m21s
WAI conformance / cross-arch byte-equality · macos (pull_request) Successful in 21s
WAI conformance / cargo-class corpora · windows (pull_request) Has been cancelled
WAI conformance / cross-arch byte-equality · windows (pull_request) Has been cancelled
compliance: publish the EU draft PUE bands as a sourced data pack, not as code
`BandingScale` deliberately ships no canonical scale: which thresholds are
correct for a metric is a policy question a library has no standing to settle,
and baking one in would repeat the mistake the type was written to retire —
`is_compliant`'s `pue < 1.5 && renewable_pct >= 50.0`, two magic floats with no
provenance, no version, and no way to say which instrument they encoded.

So the EU draft's PUE bands are published as **data**, in `jouleclaw/scales/v1/`,
with their sources beside them. `BandingScale` already derives `Deserialize`, so
a pack loads with `serde_json::from_str` and this adds no crate code at all —
which is the point.

Each pack is exactly a `BandingScale`, accompanied by a provenance file
recording where the numbers came from, the status of that source, what the pack
omits, and the reuse terms. A pack with no provenance file is not publishable
here; a threshold whose origin is unstated is the thing the directory exists to
replace.

Three things the provenance says plainly:

- **The instrument is a DRAFT** — registered 2026-03-26, revised 2026-07-02, not
  adopted and not in the Official Journal, with first labels expected
  2027-08-15. A grade produced from it is not a regulatory determination.
- **WUE is deliberately absent.** The instrument sets the grade from PUE *and*
  WUE, and only the PUE bands were read from it. Inventing WUE boundaries to
  complete the set would be exactly the failure this design prevents: a
  threshold with no provenance, presented as though it had one. A test asserts
  that a composite built from this pack reports `covers(&["pue","wue"]) ==
  false`, so a half-graded facility cannot read as graded.
- **The instrument permits calculation and estimates**, not only measurement, so
  a PUE fed to this scale may be self-declared. The scale bands whatever number
  it is given and says nothing about how that number was acquired.

The scale id is a version and is never edited in place. Ratings cite their
`scale_id` and `comparable_with` refuses to rank across scales, which only works
if an id means one fixed set of boundaries forever — so a changed instrument is
a new id, never an edit that would silently re-band grades already issued.

The pack is tested, not merely committed: it is `include_str!`-ed, deserialized,
validated and banded, and the test pins that its last boundary is **1900** —
this file's own example fixture uses 2000, and only one of the two is sourced.

Verified: 52 jouleclaw-compliance tests pass (2 new).

Co-Authored-By: Claude Opus 5 <[email protected]>
2026-09-06 06:24:25 -04:00

50 lines
2.2 KiB
Markdown
Raw Permalink Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

# Banding scales
Published threshold sets for [`BandingScale`](../jouleclaw-rs/crates/jouleclaw-compliance/src/banding.rs).
## Why scales live here and not in the crate
`BandingScale::rate` turns a measurement into an A–G band. The crate ships the
**shape** of a scale and no scale at all, deliberately: which thresholds are
correct for a given metric is a policy question a library has no standing to
settle. Baking one in would repeat the mistake the type was written to retire —
`EedReport::is_compliant`'s `pue < 1.5 && renewable_pct >= 50.0`, two magic
floats with no provenance, no version, and no way to say which instrument they
encoded — only with more ceremony.
So a scale is **data**, published here with its sources beside it. `BandingScale`
derives `Deserialize`, so a pack loads with `serde_json::from_str` and needs no
crate code:
```rust
let scale: BandingScale = serde_json::from_str(include_str!("…/eu.eed.dr2026.pue.json"))?;
let rating = scale.rate(report.pue_milli())?;
```
## What a pack must carry
Each `<scale_id>.json` is exactly a `BandingScale`. Each is accompanied by
`<scale_id>.provenance.json` recording where the numbers came from, the status
of that source, what the pack deliberately omits, and the reuse terms.
A pack with no provenance file is not publishable here. A threshold whose origin
is unstated is the thing this directory exists to replace.
## The scale id is a version, and never edited in place
Ratings cite their `scale_id`, and `Rating::comparable_with` refuses to rank two
ratings from different scales. That only works if an id means one fixed set of
boundaries forever. When a source instrument changes, the result is a **new
id** — never an edit to an existing file, which would silently re-band every
grade already issued under it.
## Current packs
| scale | metric | source status |
|---|---|---|
| `eu.eed.dr2026.pue/1` | PUE, milli-units | **Draft** delegated regulation (revised 2026-07-02, not adopted) |
A grade produced from a draft instrument is not a regulatory determination, and
the provenance file says so in those words. These packs exist so that a figure
can be banded *against a stated source*; they do not make the source binding,
and they do not make a self-declared input measured.