The Summary cards labelled `metered_import` / `metered_export` as "(kWh)", but
both fields are monetary totals (Σ import_cost / Σ export_revenue). Today's
page therefore showed "Import 1.339 kWh" when the meter had actually imported
4.188 kWh — the 1.339 was EUR. Cross-checked against the DSMR cumulative
registers and Home Assistant: our energy figures were correct all along, only
the label was wrong.
summarize() now also aggregates the metered energy, reusing the already-fetched
non-degraded rows so no extra query is issued:
metered_import_kwh = Σ (d1_kwh + d2_kwh)
metered_export_kwh = Σ (r1_kwh + r2_kwh)
The Import/Export cards show kWh as the headline figure and keep the monetary
equivalent as a sub-line, so the split between energy cost and standing
charges/credits behind total_payable stays visible.
The `_kwh` suffix is now the only thing separating energy from money in this
payload, so the docstrings on both summarize() and SummaryResponse call that
out explicitly.
app/integrations/expose.py reads only the money keys, so the HA outbound
sensors are unaffected by the additive fields.
The local gate list only covered `scripts/export_openapi.py` + a clean
`openapi/` diff, but `frontend/src/api/schema.d.ts` is generated from that JSON
and CI re-runs `npm run codegen` with `git diff --exit-code`. d07a083 changed a
route docstring, refreshed openapi.json, and skipped codegen — local green,
remote red on a one-line comment diff. Spell out both steps and note that route
docstrings feed the OpenAPI description too.
Also add AGENTS.md as a symlink to CLAUDE.md so other agent tooling picks up
the same contract.
d07a083 changed the /api/energy/prices docstring (sell now deducts sell_fee)
and refreshed openapi/openapi.json, but frontend/src/api/schema.d.ts was not
regenerated, so CI's "check codegen is in sync" step failed. Comment-only diff.
The price chart keyed its X axis on formatLocalTime() "HH:mm" labels, which
repeat across a today+tomorrow range. Recharts resolves axis tooltips by value
(combineTooltipPayload -> findEntryInArray), so hovering a slot after midnight
matched today's identically labelled point: the tooltip showed today's prices
and the active dot jumped back to today's position instead of following the
cursor.
Key the axis on the ISO instant instead (buildChartRows, sorted by slot start)
and format down to HH:mm in the tick formatter; the tooltip label now carries
the date so today and tomorrow are distinguishable.
Also mark the price slot currently in effect by default: findActiveSlotIndex()
locates the slot containing now, rendered as a ReferenceDot on the buy and sell
lines plus a caption, re-evaluated every 30s.
Regression test drives a real mousemove over a sized chart in jsdom and asserts
the resolved slot and active-dot position.