DATA-01: thirty days of the real meter, and what AC 3 actually measures
checks / unit (pull_request) Successful in 3m36s

TARIFF-01 and SAFETY-07 both merged with AC 3 - "monthly peak held under
the soft limit in >= 95 % of intervals over a 30-day simulation replay" -
honestly unmet, because two days of capture existed and it was believed
nothing longer could be produced. That belief was a true statement about
the past read as a claim about the future: HA's recorder still held the
whole month, and the reason nobody found out is that the 2026-08-25
export was a one-off script that left no artefact.

So the exporter is committed and runnable now.
scenarios/p1-net-30d-2026-08/ is 2026-08-01 to 2026-08-30, 485,841
samples, 30/30 days read, 0 failed, 4.13 MB gzipped, in the schema the
two committed days already fixed.

VERIFIED AGAINST THE DAYS THAT EXIST. `--verify` re-fetches 2026-08-20
and 2026-08-23 by this exact route and reproduces both committed files
BYTE FOR BYTE after decompression (865,024 B / 15,600 samples and
894,387 B / 16,351 samples). The gzip containers differ by design: this
exporter writes mtime 0 so its output is reproducible, where the one-off
wrote a wall clock.

A FAILED READ IS NOT AN OBSERVATION. A day whose read fails writes no
file, is recorded "read": "FAILED", and the run exits non-zero; the
entity is proved to exist through /api/states before any empty day is
believed, because a typo would otherwise answer 200 [] thirty times and
produce a consistent dataset of nothing. Nothing is interpolated, so the
month's 13 gaps (1291 s, 99.95 % covered) and its 3 `unavailable`
samples stay visible as holes.

SIZE: COMMITTED, DELIBERATELY, AND MEASURED. A git bundle of the whole
history goes from 1.58 MB (release/1.0 @ 86c43eb) to 5.28 MB - +3.70 MB,
x3.3 - and a Home Assistant supervisor clones that on every install.
Downsampling was not on the table: meter_max_age_s is 30 s, so any
coarser resample turns real coverage into modelled meter-gap and moves
the number being measured. "Outside the repo with a pointer" is what
already happened and is why this card exists. The files sit in a
SUBDIRECTORY so the non-recursive globs in test_tariff.py part 9 and
test_peakguard.py part 6 do not pick them up - CI keeps replaying the two
small days instead of growing ~50 s per PR.

AC 3, MEASURED OVER 30 DAYS (tools/replay_ac3.py, which must reproduce
test_peakguard part 6's 189/190 to be believed):

  uncontrolled  2847/2879 = 98.89 % of quarters at or under 3500 W
  guarded       2850/2879 = 98.99 %
  month peak    5029.8 W -> 4107.3 W

Met on the ">= 95 % of intervals" reading - and the uncontrolled figure
is the finding, because a month with no controller at all passes it. Not
met on the other reading of the same sentence: 4107.3 W is still over the
soft limit. The guard pulls 31 of the 32 over-cap quarters down but lands
only 3 under the cap, because CEILING_MONTH_PEAK defends the running
month peak rather than the cap once one is set. Both suites' honesty
notes are corrected to point at the month instead of at its absence.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_015VXjA3LWccN1rJsk3okyPC
This commit is contained in:
glenn schrooyen
2026-08-31 11:15:02 +02:00
co-authored by Claude Opus 5
parent 86c43eba24
commit 04292c4a08
37 changed files with 1779 additions and 16 deletions
+39
View File
@@ -2,6 +2,45 @@
## Unreleased
**Thirty days of the real meter, and the acceptance criterion three cards
deferred is now a number (DATA-01).** TARIFF-01 and SAFETY-07 both merged with
AC 3 - *"monthly peak held under the soft limit in >= 95 % of intervals over a
30-day simulation replay"* - honestly unmet, on the belief that only two days of
capture existed and nothing longer could be produced. That belief came from a
true statement about the past being read as one about the future: HA's recorder
still held the whole month. `scenarios/p1-net-30d-2026-08/` is 2026-08-01 to
2026-08-30, **485,841 samples, 30/30 days read, 0 failed, 4.13 MB gzipped**, in
the same schema as the two days that were already there.
`tools/export_p1_history.py` is the exporter, committed and runnable - the
2026-08-25 one-off was not, and that is exactly why the data was thought
unobtainable. It reads day-at-a-time, retries, and **never lets a failed read
look like an empty hour**: a day whose read fails writes no file, is recorded as
`"read": "FAILED"`, and the run exits non-zero; the entity is proved to exist
before any empty day is believed. Nothing is interpolated, so the month's 13
gaps (1291 s, 99.95 % covered) and its 3 `unavailable` samples stay visible.
`--verify` re-fetches the two committed days by the same route and reproduces
them **byte for byte** after decompression.
`tools/replay_ac3.py` runs the month. Over 30 days the criterion measures
**98.89 % uncontrolled and 98.99 % guarded**, so it is met on that reading - and
the uncontrolled figure is the finding: a month with no controller at all passes
it. On the other reading of the same sentence it is not met - the guard takes
August's peak from **5029.8 W to 4107.3 W**, still over the 3500 W soft limit,
because once a month peak is set `CEILING_MONTH_PEAK` defends that peak rather
than the cap. Neither number is hidden; both are in that directory's README.
The size decision is committed and measured, not absorbed: a `git bundle` of
the whole history goes from **1.58 MB to 5.28 MB** (+3.70 MB, x3.3), which a
Home Assistant supervisor clones on every install. Downsampling was not
available - `meter_max_age_s` is 30 s, so any coarser resample converts real
coverage into modelled meter-gap and moves the number being measured.
The thirty files sit in a SUBDIRECTORY on purpose: `test_tariff.py` part 9 and
`test_peakguard.py` part 6 glob `scenarios/p1-net-*.jsonl.gz` non-recursively,
so CI keeps replaying the two small days and does not grow ~50 s per PR. Both
files' honesty notes are corrected to point at the month.
**OPT-04's AC4 is met: twelve months of real EPEX BE day-ahead prices are now in
the repository, and the strategy has been replayed against them (DATA-02).**
AC4 asked for "net-positive across 12 months of replayed prices". OPT-04 shipped