open-standards/jcp/jcp-rs/crates/jcp-efficiency/tests/energy_trace_pack.rs
David Charlot f9dac4e14b
Some checks failed
standards workspaces build + test / jouleclaw-rs (pull_request) Successful in 2m45s
standards workspaces build + test / aac-rs (pull_request) Successful in 1m32s
no-vanity-metrics / Scan committed Markdown for vanity metrics (pull_request) Has been cancelled
no-vanity-metrics / WAI public text names no comparison (pull_request) Has been cancelled
no-vanity-metrics / WAI public text names no company or product (pull_request) Has been cancelled
standards workspaces build + test / arl-rs (pull_request) Has been cancelled
standards workspaces build + test / eoc-rs (pull_request) Has been cancelled
standards workspaces build + test / jcp-rs (pull_request) Has been cancelled
standards workspaces build + test / joule-ui-rs (pull_request) Has been cancelled
standards workspaces build + test / joulecontract-rs (pull_request) Has been cancelled
standards workspaces build + test / jouledesk-rs (pull_request) Has been cancelled
standards workspaces build + test / joulehook-rs (pull_request) Has been cancelled
standards workspaces build + test / map-rs (pull_request) Has been cancelled
standards workspaces build + test / mesh-rs (pull_request) Has been cancelled
standards workspaces build + test / openpay (pull_request) Has been cancelled
standards workspaces build + test / proof-rs (pull_request) Has been cancelled
standards workspaces build + test / sandbox-rs (pull_request) Has been cancelled
standards workspaces build + test / sense-rs (pull_request) Has been cancelled
standards workspaces build + test / smart-byte-rs (pull_request) Has been cancelled
standards workspaces build + test / macOS energy backend (jcp-energy) (pull_request) Has been cancelled
standards workspaces build + test / joule-code-rs (pull_request) Has been cancelled
jcp: publish the energy_trace/1 conformance pack, and replay it
§5.3–5.6 stated rules and nothing emitted them. The types did not even derive
`Serialize`, so the profile could not cross a wire, let alone be checked by
anyone else — a shape nothing emits is a proposal, which is the same gap the
C2PA emitter closed for `wai` and the negative-vector replay closed for
`joulecontract`.

So: serde on the trace and dynamics types, a `gen_trace_vectors` binary writing
`jcp/conformance/v1/energy_trace.json`, and a test that reads those bytes back
from disk — the same bytes a third party would — and checks the reference
implementation reproduces every recorded verdict.

The pack carries the refusals, not just the acceptances, because the refusals
are the load-bearing half. An implementation that admits an unbound outcome, a
double-counted activity, an over-accounted total or a frozen counter has failed
in the direction that flatters, which is the direction nobody notices:

- conservation: the named residual, the provenance/coverage floor, and all three
  refusals (`Unbound`, `DuplicateActivity`, `OverAccounted`)
- budget: 0.5 % over a one-joule grant is 5000 ppm against a 1 ppm floor; the
  same floor over `Estimator` windows is exact and physically meaningless; a
  ratio against a zero grant is not a figure
- physical: refuted above the burst envelope, refuted **below** the idle floor
  (the frozen-counter shape), `NotRefuted` which is not verification, and a
  zero-duration window as unboundable rather than clean
- shape: a total balanced by padding does not read as sustained; character is
  scale-invariant at 37× the magnitude; under three windows it is unresolvable
- dynamism: an undeclared baseline makes no comparison, a coarser baseline does
  not apply to finer windows, and a cause explains only with evidence attached

Falsified rather than assumed: flipping one recorded residual by a single
microjoule — 250000 to 250001 — fails the replay naming the case and the field.
The pack was then regenerated and the value confirmed back at 250000.

Two anti-vacuity guards, because this file has been written three times this
session and twice the first version could not fail: the pack path is asserted
rather than skipped, and a test requires every declared section plus at least 20
replayed cases, so a wrong path or a renamed key fails instead of passing having
checked nothing.

Verified: 49 tests in `jcp-efficiency` — 43 unit, 6 pack.

Co-Authored-By: Claude Opus 5 <[email protected]>
2026-10-02 00:06:10 -04:00

184 lines
8 KiB
Rust
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.

//! Replay the published `energy_trace/1` pack from disk.
//!
//! SPEC §5.3–5.6 states rules, and `gen_trace_vectors` emits the vectors. This
//! reads those bytes back — the same bytes a third party would — and checks the
//! reference implementation reproduces every recorded verdict. A pack only its
//! own generator can read is not a conformance pack.
//!
//! The refusals matter more than the acceptances. An implementation that admits
//! an unbound outcome, a double-counted activity or a frozen counter has failed
//! in the direction that flatters, which is the direction nobody notices.
use jcp_efficiency::dynamics::{
DrawShape, EnergyWindow, PhysicalVerdict, PowerEnvelope,
};
use jcp_efficiency::trace::{OutcomeTrace, TraceError};
use serde_json::Value;
fn pack() -> Value {
let p = std::path::Path::new(env!("CARGO_MANIFEST_DIR"))
.join("../../../conformance/v1/energy_trace.json");
// Assert, not skip. A `return` here would make this test pass green in the
// one case it exists to catch — the pack going missing or moving.
assert!(
p.exists(),
"conformance pack missing at {} — it is what this test replays",
p.display()
);
let bytes = std::fs::read(&p).unwrap_or_else(|e| panic!("read {}: {e}", p.display()));
serde_json::from_slice(&bytes).expect("pack parses")
}
#[test]
fn the_pack_declares_its_profile_and_spec() {
let v = pack();
assert_eq!(v["profile"], "energy_trace/1");
assert!(v["spec"].as_str().unwrap().contains("5.3-5.6"));
}
/// Every positive conservation vector reproduces its recorded reconciliation.
#[test]
fn conservation_positives_reproduce_their_recorded_verdicts() {
let v = pack();
let cases = v["conservation"]["positive"].as_array().expect("positives");
assert!(cases.len() >= 2, "expected the published positive cases");
for c in cases {
let note = c["note"].as_str().unwrap_or("?");
let t: OutcomeTrace =
serde_json::from_value(c["input"].clone()).unwrap_or_else(|e| panic!("{note}: {e}"));
let r = t.reconcile().unwrap_or_else(|e| panic!("{note}: must reconcile: {e}"));
let exp = &c["expected"];
assert_eq!(
serde_json::to_value(r.accounted_uj).unwrap(), exp["accounted_uj"],
"{note}: accounted"
);
assert_eq!(
serde_json::to_value(r.residual_uj).unwrap(), exp["residual_uj"],
"{note}: the residual is the whole point"
);
assert_eq!(
serde_json::to_value(r.provenance_floor).unwrap(), exp["provenance_floor"],
"{note}: provenance takes the floor"
);
assert_eq!(
serde_json::to_value(r.coverage_floor).unwrap(), exp["coverage_floor"],
"{note}: coverage takes the floor"
);
}
}
/// Every refusal is actually refused, and for the recorded reason. An
/// implementation that accepted these would be wrong in the flattering
/// direction.
#[test]
fn conservation_negatives_are_refused_for_the_recorded_reason() {
let v = pack();
let cases = v["conservation"]["negative"].as_array().expect("negatives");
assert!(cases.len() >= 3, "expected the three published refusals");
for c in cases {
let note = c["note"].as_str().unwrap_or("?");
let t: OutcomeTrace =
serde_json::from_value(c["input"].clone()).unwrap_or_else(|e| panic!("{note}: {e}"));
let err = t.reconcile().expect_err(&format!("{note}: must be refused"));
let want = c["expected"]["error"].as_str().unwrap();
let got = match err {
TraceError::Unbound => "Unbound",
TraceError::DuplicateActivity { .. } => "DuplicateActivity",
TraceError::OverAccounted { .. } => "OverAccounted",
};
assert_eq!(got, want, "{note}: refused, but for the wrong reason");
}
}
/// The physical bound refutes above the envelope and below the floor — the
/// second being the shape a frozen counter takes.
#[test]
fn physical_bounds_reproduce_their_recorded_verdicts() {
let v = pack();
let env: PowerEnvelope =
serde_json::from_value(v["physical"]["envelope"].clone()).expect("envelope");
let cases = v["physical"]["cases"].as_array().expect("cases");
assert!(cases.len() >= 4);
let mut saw_below = false;
for c in cases {
let note = c["note"].as_str().unwrap_or("?");
let w: EnergyWindow =
serde_json::from_value(c["input"].clone()).unwrap_or_else(|e| panic!("{note}: {e}"));
let got = match env.check(&w) {
PhysicalVerdict::NotRefuted { .. } => "NotRefuted",
PhysicalVerdict::RefutedAbove { .. } => "RefutedAbove",
PhysicalVerdict::RefutedBelow { claimed_uj, floor_uj } => {
saw_below = true;
if let Some(f) = c["expected"]["floor_uj"].as_u64() {
assert_eq!(floor_uj, f, "{note}: floor");
assert_eq!(claimed_uj, 0, "{note}: a frozen counter claims nothing");
}
"RefutedBelow"
}
PhysicalVerdict::Unboundable => "Unboundable",
};
assert_eq!(got, c["expected"]["verdict"].as_str().unwrap(), "{note}");
}
assert!(saw_below, "the frozen-counter refutation must be in the pack");
}
/// Character survives a change of scale, and a padded total does not read as
/// sustained. These two together are what the shape check is for.
#[test]
fn draw_character_reproduces_its_recorded_verdicts() {
let v = pack();
let floor = v["shape"]["idle_floor_uj"].as_u64().expect("idle floor");
let cases = v["shape"]["cases"].as_array().expect("cases");
assert!(cases.len() >= 6);
let mut saw_inconsistent = false;
for c in cases {
let note = c["note"].as_str().unwrap_or("?");
let declared: DrawShape =
serde_json::from_value(c["input"]["declared"].clone()).expect("declared");
let windows: Vec<EnergyWindow> =
serde_json::from_value(c["input"]["windows"].clone()).expect("windows");
let got = jcp_efficiency::dynamics::check_shape(declared, &windows, floor);
let want = c["expected"]["verdict"].as_str().unwrap();
let name = match &got {
jcp_efficiency::dynamics::ShapeVerdict::Consistent { shape } => {
if let Some(s) = c["expected"]["shape"].as_str() {
assert_eq!(
serde_json::to_value(shape).unwrap().as_str().unwrap(), s,
"{note}: shape"
);
}
"Consistent"
}
jcp_efficiency::dynamics::ShapeVerdict::Inconsistent { .. } => {
saw_inconsistent = true;
"Inconsistent"
}
jcp_efficiency::dynamics::ShapeVerdict::Unresolvable { windows } => {
if let Some(n) = c["expected"]["windows"].as_u64() {
assert_eq!(*windows as u64, n, "{note}: window count");
}
"Unresolvable"
}
};
assert_eq!(name, want, "{note}");
}
assert!(saw_inconsistent, "the padding refutation must be in the pack");
}
/// Anti-vacuity across the whole pack: a wrong path, a renamed key or an empty
/// array would otherwise let every test above pass having checked nothing.
#[test]
fn the_pack_carries_every_section_it_claims() {
let v = pack();
for section in ["conservation", "budget", "physical", "shape", "dynamism"] {
assert!(!v[section].is_null(), "section {section} missing from the pack");
}
let total: usize = v["conservation"]["positive"].as_array().map_or(0, Vec::len)
+ v["conservation"]["negative"].as_array().map_or(0, Vec::len)
+ v["physical"]["cases"].as_array().map_or(0, Vec::len)
+ v["shape"]["cases"].as_array().map_or(0, Vec::len)
+ v["dynamism"]["cases"].as_array().map_or(0, Vec::len)
+ v["budget"]["positive"].as_array().map_or(0, Vec::len)
+ v["budget"]["negative"].as_array().map_or(0, Vec::len);
assert!(total >= 20, "expected the full published pack, replayed {total} cases");
}