Files
adminandClaude Opus 5.5 7fa045af85
checks / unit (pull_request) Successful in 8m44s
TEL-14 N1: trim DECISIONS (drop probe transcript, §1 to the reason), move the mutation ledger there with M2/M5
test_pv.py part 11 now prints a one-line pointer instead of the 12-row table.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01BwRLw7eKYj2byVdwB6kbjU
2026-09-25 01:11:40 +02:00

4.4 KiB
Raw Permalink Blame History

TEL-14 — the PV sign, declared per entity

Owner report on 0.12.0: sensor.espressif_vermogen (ESPHome clamp) and sensor.kwh_meter_actueel_vermogen (kWh meter in the PV circuit) read positive for consumption, negative for production. At night the page said "✓ PV production: 13 W" — standby draw. By day production would publish negative.

1. This reverses TEL-11 §2, and why

TEL-11 §2 refused a pv_invert on two grounds. "PV is read by nothing in the control path" still holds: the flip lives in pv.total(), and test_pv.py part 12 re-runs part 6's 40-cycle identity with a flip set. "A reversed sensor announces itself" did not survive a real site: these sensors follow a different convention, read a plausible small positive number at night, and the only other fix is a template sensor, the place TEL-12 §2 says goes quietly wrong.

2. The shape: a parallel list, pv_invert_entities

Measured by tools/supervisor_shape_probe.py §H (Supervisor 2026.08.0, against a 0.12.0 blob); re-run it for the transcript.

shape schema why it lost / won
(a) -sensor.x prefix accepted invisible: the sign is a syntax only the description explains, in a field an installer fills with the entity picker's text
(b) parallel list accepted, 0.12.0 blob unchanged ships: its own labelled, translated field ("PV entities whose sign is reversed"); an installer lists the odd ones out
(c) dicts on pv_entities refuses 0.12.0's stored strings bricks the upgrade — TEL-12's trap again
(c2) dicts as a third key accepted per-entry labels render raw (entity, invert) — probe §F; and a third PV surface
(d) global bool accepted one sign cannot describe inverter + meter in one roster

(b)'s known cost is a typo in the second list: pv.stray_inverts() turns it into a named caution. [] in options: is load-bearing (§H, isolated counterfactual). Default [] flips nothing, so every 0.12.0 install is byte-identical (part 12).

3. The negative caution: per entity, below −50 W

The owner's two meters draw ~13 W at night, so a correctly signed meter reads about −13 W then. −50 W clears that with room for a few such devices behind one entity; a reversed sensor by day reads hundreds to thousands of watts below zero. It is tested per entity, not on the total (a deviation from the brief): three correct meters at −20 W sum to −60 W and must stay quiet, while a reversed −1500 W hidden inside a positive total must not. It is a caution, never bad; a wrong threshold costs a spurious or missed caution, never data. The text says ADD (unflipped) or REMOVE (already flipped).

4. Mutations

Fresh cp -a each, __pycache__ purged, CI image, :ro, --network none; test_pv.py only unless stated. T1-T12 at 7559d21; M2/M5 are review #1628's, red since B1 (merged into release/1.0 @ 43b2740).

# mutation bytes reds
T1 flip ignored in total() −45 9
T2 flip applied to every member −7 6
T3 0.0 - w → -w −5 1
T4 flip written as abs() −1 2
T5 _read_pv() stops passing the flip −26 7
T6 caution threshold −50 → 0 W −17 3
T7 [sign inverted] marker dropped −39 3
T8 negative caution made bad +1 1
T9 stray_inverts() always empty −50 1
T10 inverted() stops stripping −8 1
T11 ADD/REMOVE advice swapped +4 2
T12 pv_invert_entities: [] deleted from options: −25 2 test_translations + 17 probe
M2 stray_inverts() roster ignores pv_entity +15 2 (REPORTED CASE, PADDING)
M5 _read_pv() flip set not stripped +25 1 (PADDING)

5. History

OPT-10's sensor.goodwe_pv_power recorded since 2026-09-24 on an install with such sensors carries the old sign; nothing rewrites it.

6. CHANGELOG entry for the next PKG cut

Not written into CHANGELOG.md: test_version_gate.py 11b/11d refuse an ## Unreleased heading (measured on this branch: 4 reds). For PKG to paste:

pv_invert_entities (TEL-14). A PV sensor that reads negative while producing — typically a kWh meter or power clamp in the PV circuit — can now be listed under PV entities whose sign is reversed in the Configuration tab; its sign is flipped before the sum and the status page marks it. Empty (the default) changes nothing. ⚠️ PV history recorded before you set it keeps the old sign.