open-standards/eoc/eoc-rs/crates/eoc-carbon/tests/account_per_request.rs
Transaction Science 6c37e29980 eoc-carbon: an account and an SCI score are measured only where every part was, and a run with no correct answer has no score
0db9b8be listed three things here as not done. `CarbonAccount` dropped
provenance, and `account_request` is a public way in. A report with zero
correct answers carries `joules_per_correct == u64::MAX` as a sentinel, which
`sci_from_eval_report` multiplied by `correct.max(1)` into a u64::MAX µJ
energy term (18.4 TJ). And the test that pins the bridge's provenance sat
behind the `eval-bridge` feature, which nothing in the workspace enables, so
`cargo test --workspace` never compiled it, nor any mutation it catches.

What holds now:

- `CarbonAccount` gains `it_energy_source`, the input `JouleCost`'s provenance
  unchanged, and `facility_energy_source`. The facility joules are `it_joules`
  × PUE, so they are measured only when every part of them was: the IT joules
  were measured, and the PUE added no overhead. A PUE above 1 is a published
  or assumed facility ratio applied to the reading, energy no counter on the
  host read; a figure containing any of it is an estimate. A PUE of 1 adds
  nothing, so measured IT joules stay measured, as an estimated zero adds
  nothing to a live span in eoc-cascade. Grid intensity has its own provenance
  (the reading's provider and kind) and does not enter the tag. Both fields
  read back as `Estimated` when absent. Nothing outside this crate builds a
  `CarbonAccount`.
- `SciScore::energy_source` is now the account's facility provenance, because
  the score's energy term is facility energy. Before, it was the input's
  provenance, so measured IT joules at the default PUE of 1.58 gave a
  "measured" term of which 37% no counter read. This changes what 0db9b8be
  set: an SCI score at PUE > 1 is now estimated even from measured joules.
  The SCI numbers do not change.
- The bridge's pure part is compiled in every build. `EvalEnergy`
  (micro-joules per correct answer, correct answers, provenance) and
  `sci_per_correct_answer` hold all the scoring, including the `JouleCost`
  construction 0db9b8be's mutation targeted. `sci_from_eval_report`, still
  behind `eval-bridge`, only copies the report's three fields across.
- A run with no correct answer has no score per correct answer:
  `sci_per_correct_answer` and `sci_from_eval_report` return `None` for
  `correct == 0` and for the `u64::MAX` sentinel, whatever `correct` says
  beside it. The sentinel is never read as energy. `sci_from_eval_report` now
  returns `Option<SciScore>`; its only callers are this crate's tests.

Tests in the default build: an account's (IT, facility) tags are (Measured,
Measured) at PUE 1, (Measured, Estimated) at 1.2, (Estimated, Estimated) from
an estimate at either, and (Measured, Measured) at a PUE of 0.5, which is
clamped to 1; the figures are the same whichever tag. An account round-trips
and an old one reads back estimated. A score is measured at PUE 1, estimated
at 1.2 from measured joules, with the same SCI. An eval run's score keeps the
run's provenance (2 × 1 J × 1.2 = 2.4 J over R = 2), and a run with 0
correct, or the sentinel with 3 correct, has none. `account_per_request` now
asserts its tags. Under `eval-bridge`, a report's score equals its run's score
for both provenances and both PUEs, and a 0-correct report has none.

Falsified, each mutant restored byte-for-byte (sha256 checked); every one but
the last runs in the default build:

- 0db9b8be's mutant, `JouleCost::measured(total)` in the bridge, now fails
  `an_eval_runs_score_keeps_the_runs_provenance` in a plain `cargo test`;
- an account dropping the IT provenance fails 1 test;
- the facility tag ignoring the PUE fails 3, ignoring the IT provenance 3;
- the score taking the input's provenance (0db9b8be's rule) fails 2;
- removing the no-correct-answer guard fails 1, and so does checking
  `correct == 0` without the sentinel;
- the `eval-bridge` wrapper tagging every report measured fails
  `an_eval_reports_score_is_its_runs_score` under `--features eval-bridge`.
That wrapper's three-field copy is the only part a default build cannot see.

`cargo test -p eoc-carbon` passes (42 + 8), and with `--features eval-bridge`
(43 + 8). No clippy warning in this crate, before or after.

Not done: `joules_per_correct` is an integer quotient, so the total
reconstructed from it can fall short of the run's by less than one µJ per
correct answer.

Co-Authored-By: Claude Opus 5.5 <[email protected]>
2026-09-30 21:07:25 -04:00

36 lines
1.1 KiB
Rust

//! Spec example: 1000 J at 400 gCO2e/kWh, PUE 1.2 → 0.1333... gCO2e.
use chrono::Utc;
use eoc_carbon::account::account_request;
use eoc_carbon::intensity::{CarbonIntensity, IntensityKind, ProviderKind};
use eoc_carbon::pue::Pue;
use eoc_core::{JouleCost, JouleSource};
#[test]
fn one_kilojoule_400g_pue_1_2() {
let cost = JouleCost {
microjoules: 1_000_000_000, // 1000 J
source: JouleSource::Measured,
};
let intensity = CarbonIntensity::new(
"EXAMPLE",
400.0,
IntensityKind::Average,
ProviderKind::Mock,
Utc::now(),
);
let pue = Pue::new(1.2);
let acc = account_request(&cost, &intensity, &pue);
// 1000 / 3.6e6 * 400 * 1.2 = 0.13333...
assert!(
(acc.g_co2e - 0.13333333).abs() < 1e-5,
"got {} gCO2e",
acc.g_co2e
);
assert!((acc.facility_joules - 1200.0).abs() < 1e-9);
assert_eq!(acc.pue, 1.2);
assert_eq!(acc.g_co2e_per_kwh, 400.0);
// The IT joules were read; the PUE's overhead was not.
assert_eq!(acc.it_energy_source, JouleSource::Measured);
assert_eq!(acc.facility_energy_source, JouleSource::Estimated);
}