467acb38 made a stream's energy measured only when its counter advanced. It
left this as not done: `StreamAccount` had no way to say "not metered". So a
stream metered by the stub, by a counter whose read failed, or by one that did
not move reported `0 µJ (estimated)`. That is work that ran, presented as a
figure of zero. Saying so honestly needed a change to a public type. Nothing
outside this file uses `StreamAccount` or `StreamMeter`, in this workspace or
any other in the monorepo, so the change is contained.
The fix is the honest one, not a duration-based estimate: the account does not
invent a figure. Any per-second or per-token coefficient would be a number
nobody measured, and callers already hold their own estimates.
- `StreamAccount.microjoules` is now `Option<u64>`: `Some` only when the
counter read at the start and at the latest checkpoint and advanced between
them, and `None` otherwise. The separate `measured: bool` is gone, since the
`Option` says it.
- `joule_cost()` returns `Option<JouleCost>`: `Some(JouleCost::measured(..))`
for a metered stream and `None` for one nothing metered. There is no
estimated zero; a caller with no reading supplies its own estimate and tags
it as one.
- Token counts are kept, metered or not. A failed later read still keeps the
last reading, and a failed start still never turns a later read into the
counter's since-boot total.
Tests: a counter that holds gives `{ tokens: 3, microjoules: None }` and no
cost. A counter that advances 450 µJ gives `Some(measured(450))`. A failed
start gives `None`. A stream that advanced 200 µJ keeps that figure when a
later read fails. The stub gives five tokens and no figure, and so does
`StreamAccount::default()`.
Falsified, each mutant restored byte-for-byte:
- recording a zero delta as the stream's figure fails three tests
(`left: Some(0)`, `right: None`);
- returning HEAD's `0 µJ (estimated)` for an unmetered stream fails three
(`left: Some(JouleCost { microjoules: 0, source: Estimated })`).
Co-Authored-By: Claude Opus 5.5 <[email protected]>