SAFETY-129: find late Home Assistant readings sooner at a 5 s meter #236

Merged
admin merged 5 commits from SAFETY-129 into release/1.0 2026-11-07 01:24:40 +01:00
Owner

SAFETY-129: late Home Assistant readings found sooner at a 5 s meter

Change (app/lateness.py): a meter too slow for 16 new values in 60 s (the owner's 5 s P1) is now also fitted over 120 s (MeterFit.slow(), meter_slow). That fit calls a delay late only over 16 s, on 2 fits in a row, with SAFETY-128's corroboration (an ask slow to start, no battery fit on time), and it never ends a verdict. A 10-12 s slow battery (R2-1) reads up to 15 s at a 5 s meter, so it runs exactly as before.

Result, 5 s meter, N=2, house 1 800 W, 30 s late: found 88 s after the start (base: 194 s), grid -124 W (base -420 W; -1 325 W with no gate). N=1: 88 s, -125 W.

Not met, and why: under 60 s, and 10 s late. In a flat house the loop first moves 100 W 62 s after the lag starts, and a reading shows it 30 s later; nothing earlier can be fitted without fitting noise. 10 s late at a 5 s meter does not swing (grid -98 W) and reads like a 10 s battery, so finding it would make R2-1 worse (dead10 at 5 s: 0 s late now, 362+ s late with a threshold of 8 s). See the dev report.

Checks

  • 48 no-lag scenarios (1/2/4/5/10 s meters, N=1/2, owner shape, clouds, ovens, EV, limits, HA restarts, meter pauses, jitter, reversals, 6-8 s dead times): 0 s late, 0 W command difference, identical to base.
  • 15 R2-1 scenarios (slow battery): identical to base. 15 harm runs: identical.
  • Digests base vs head, 9 cases at 5/2/1 s ticks: identical.
  • New test_safety129.py (red on c66aa7f); 4 mutants red. Full suite local: 97 files, 0 failed.

CHANGELOG: one line. No text on the page changes.

🤖 Generated with Claude Code

https://claude.ai/code/session_01Bdqr7PiaHcBnzPituu2yTC

## SAFETY-129: late Home Assistant readings found sooner at a 5 s meter **Change** (`app/lateness.py`): a meter too slow for 16 new values in 60 s (the owner's 5 s P1) is now also fitted over 120 s (`MeterFit.slow()`, `meter_slow`). That fit calls a delay late only over 16 s, on 2 fits in a row, with SAFETY-128's corroboration (an ask slow to start, no battery fit on time), and it never ends a verdict. A 10-12 s slow battery (R2-1) reads up to 15 s at a 5 s meter, so it runs exactly as before. **Result, 5 s meter, N=2, house 1 800 W, 30 s late:** found 88 s after the start (base: 194 s), grid -124 W (base -420 W; -1 325 W with no gate). N=1: 88 s, -125 W. **Not met, and why:** under 60 s, and 10 s late. In a flat house the loop first moves 100 W 62 s after the lag starts, and a reading shows it 30 s later; nothing earlier can be fitted without fitting noise. 10 s late at a 5 s meter does not swing (grid -98 W) and reads like a 10 s battery, so finding it would make R2-1 worse (dead10 at 5 s: 0 s late now, 362+ s late with a threshold of 8 s). See the dev report. **Checks** - 48 no-lag scenarios (1/2/4/5/10 s meters, N=1/2, owner shape, clouds, ovens, EV, limits, HA restarts, meter pauses, jitter, reversals, 6-8 s dead times): 0 s late, 0 W command difference, identical to base. - 15 R2-1 scenarios (slow battery): identical to base. 15 harm runs: identical. - Digests base vs head, 9 cases at 5/2/1 s ticks: identical. - New `test_safety129.py` (red on c66aa7f); 4 mutants red. Full suite local: 97 files, 0 failed. CHANGELOG: one line. No text on the page changes. 🤖 Generated with [Claude Code](https://claude.com/claude-code) https://claude.ai/code/session_01Bdqr7PiaHcBnzPituu2yTC
admin added 2 commits 2026-11-06 20:27:37 +01:00
The meter's delay fit needed 16 new values in 60 s, so at the owner's 5 s P1
only the batteries' fit ran and 30 s late was found after about 3 minutes
(export to -420 W). A meter that slow is now also fitted over 120 s; it calls
a delay late only over 16 s, on two fits in a row, with the same corroboration
as before, and never ends a verdict, so a slow battery (R2-1) runs as before.
Found about 90 s after the start, export above -200 W. 10 s late at a 5 s
meter is not found (nothing swings; it cannot be told from a 10 s battery).

Co-Authored-By: Claude <noreply@anthropic.com>
SAFETY-129: the 5 s row no longer waits for the batteries' figure
checks / unit (pull_request) Successful in 23m52s
infra-pin / fresh (pull_request) Successful in 1s
2667cf0dda
At a 5 s meter the slow meter fit now finds 30 s late first, and the hold leaves
the batteries' fit nothing to measure, so the row says it without a figure.

Co-Authored-By: Claude <noreply@anthropic.com>
admin added 2 commits 2026-11-06 22:37:35 +01:00
Co-Authored-By: Claude <noreply@anthropic.com>
SAFETY-129 round 2: next() with a default in test_safety129
checks / unit (pull_request) Successful in 23m26s
infra-pin / fresh (pull_request) Successful in 2s
03541a1eee
Co-Authored-By: Claude <noreply@anthropic.com>
Author
Owner

Review of 03541a1 (Opus). Not merged: the owner decides on the two missed targets.

Verdict: accept both missed targets for the reasons below. One short dev round is needed (D1, D2); no logic change. After it: ready to merge if the owner accepts.

Target 1: under 60 s at a 5 s meter, 30 s late (88 s). I accept 88 s.

  • Reproduced: 88 s with N=2 and 76 s with N=1, grid -124 W (base 194 s, -420 W).
  • In a flat house the request moves only 20-40 W until 62 s, inside the house noise. The slow fit first reads late at 72-74 s. The first ask slow to start comes at 75 s.
  • Variants I tried, against 88 s on head:
    • one late fit is enough: 86 s;
    • a 50 W move gate: 88 s;
    • a 90 s window: 112 s, and R2-1 gets worse;
    • no slow-start check: 74 s, but false holds (dead8_p6 122 s, rev6_p6 8 s) and tau20_p5 late 550 -> 806 s.
  • With load changes: 38-84 s on base and head alike.
  • A perfect detector gives the same harm in the flat house (-137 W, 2 Wh).
  • Under 60 s would need a P1 source timestamp or an active probe.

Target 2: 10 s late at a 5 s meter is not found. I accept leaving it, but the harm is small only in a flat house.

  • With an oven, a kettle or the owner shape: export 21-142 Wh against 2-27 Wh with no lag.
  • A perfect hold barely helps (oven 90 -> 84 Wh, kettle 142 -> 121 Wh), so detection is not the fix. It also cannot be told from R2-1. This is a card, not this PR.

Checks, all met:

  • No false holds: 95 scenarios through the real cycle(), meters 1/2/4/5/6/10 s, N=1/2. All 71 no-lag runs: 0 s late, commands the same as with no gate.
  • R2-1 is unchanged, and the 15 harm runs give the same JSON as base.
  • Digests are identical: 5 s modes_off c1b230c2, 5 s own_fresh_state_epex 81d4c1f2, 2 s n1_modes_off 9dc58905, 1 s modes_off d849afb3.
  • The test_safety128 change is fine. The 5 s row now has no figure, and the check pins that text exactly.
  • Worst watch() on a 5 s meter: 2.4-2.9 ms (base 1.0-2.7 ms).
  • Full suite on my machine: 97 files, 0 failed, 0 TIMEOUT, 1 382 s. CI 1545/1546 green on 03541a1.
  • Mutants: 3 of 4 are red.

Change list:

  • D1 (docs). The reason given for the 16 s limit and "2 in a row" is wrong. On healthy runs the slow fit alone reads 35-90 s, 2 to 48 times in a row (owner shape, meter pause, reversal, 10 s dead time). What keeps these at 0 late is the slow-start and battery-fit check. Fix the comment at lateness.py:174-178, the DECISIONS sentence and the test name that says "up to 15 s".
  • D2 (test). No test covers that check on the slow path: the "no slow-start check" mutant passes test_safety128 and test_safety129. Add one cheap check that fails on it, for example a 6 s meter with an 8 s dead time, owner shape, never late.
  • N1 (DECISIONS, one sentence). In a quiet house the "readings late" row stays about 2 minutes longer after the lag ends: 126 s against 32 s on base. I measured no harm, and when load changes the row clears as early as on base.

Report: reports/SAFETY-129-review-report.md

**Review of 03541a1 (Opus). Not merged: the owner decides on the two missed targets.** **Verdict:** accept both missed targets for the reasons below. One short dev round is needed (D1, D2); no logic change. After it: ready to merge if the owner accepts. **Target 1: under 60 s at a 5 s meter, 30 s late (88 s).** I accept 88 s. - Reproduced: 88 s with N=2 and 76 s with N=1, grid -124 W (base 194 s, -420 W). - In a flat house the request moves only 20-40 W until 62 s, inside the house noise. The slow fit first reads late at 72-74 s. The first ask slow to start comes at 75 s. - Variants I tried, against 88 s on head: - one late fit is enough: 86 s; - a 50 W move gate: 88 s; - a 90 s window: 112 s, and R2-1 gets worse; - no slow-start check: 74 s, but false holds (dead8_p6 122 s, rev6_p6 8 s) and tau20_p5 late 550 -> 806 s. - With load changes: 38-84 s on base and head alike. - A perfect detector gives the same harm in the flat house (-137 W, 2 Wh). - Under 60 s would need a P1 source timestamp or an active probe. **Target 2: 10 s late at a 5 s meter is not found.** I accept leaving it, but the harm is small only in a flat house. - With an oven, a kettle or the owner shape: export 21-142 Wh against 2-27 Wh with no lag. - A perfect hold barely helps (oven 90 -> 84 Wh, kettle 142 -> 121 Wh), so detection is not the fix. It also cannot be told from R2-1. This is a card, not this PR. **Checks, all met:** - No false holds: 95 scenarios through the real `cycle()`, meters 1/2/4/5/6/10 s, N=1/2. All 71 no-lag runs: 0 s late, commands the same as with no gate. - R2-1 is unchanged, and the 15 harm runs give the same JSON as base. - Digests are identical: 5 s modes_off c1b230c2, 5 s own_fresh_state_epex 81d4c1f2, 2 s n1_modes_off 9dc58905, 1 s modes_off d849afb3. - The `test_safety128` change is fine. The 5 s row now has no figure, and the check pins that text exactly. - Worst `watch()` on a 5 s meter: 2.4-2.9 ms (base 1.0-2.7 ms). - Full suite on my machine: 97 files, 0 failed, 0 TIMEOUT, 1 382 s. CI 1545/1546 green on 03541a1. - Mutants: 3 of 4 are red. **Change list:** - **D1 (docs).** The reason given for the 16 s limit and "2 in a row" is wrong. On healthy runs the slow fit alone reads 35-90 s, 2 to 48 times in a row (owner shape, meter pause, reversal, 10 s dead time). What keeps these at 0 late is the slow-start and battery-fit check. Fix the comment at `lateness.py:174-178`, the DECISIONS sentence and the test name that says "up to 15 s". - **D2 (test).** No test covers that check on the slow path: the "no slow-start check" mutant passes test_safety128 and test_safety129. Add one cheap check that fails on it, for example a 6 s meter with an 8 s dead time, owner shape, never late. - **N1 (DECISIONS, one sentence).** In a quiet house the "readings late" row stays about 2 minutes longer after the lag ends: 126 s against 32 s on base. I measured no harm, and when load changes the row clears as early as on base. Report: `reports/SAFETY-129-review-report.md`
admin added 1 commit 2026-11-07 00:36:32 +01:00
SAFETY-129 round 3: the real reason for the 16 s limit, a slow-start check, the row's tail
checks / unit (pull_request) Successful in 23m1s
infra-pin / fresh (pull_request) Successful in 1s
c70eeb6916
Co-Authored-By: Claude <noreply@anthropic.com>
Author
Owner

Re-review of round 3 (head c70eeb6): ready, merging.

  • Diff 03541a1..c70eeb6: comment in lateness.py, DECISIONS, one test. No logic change.
  • D1 fixed: comment and DECISIONS now say the slow fit alone reads 35-90 s on healthy runs, and the slow-start and battery-fit check is what keeps them at 0 late. The test name no longer makes the old claim.
  • D2 fixed: I rebuilt mutant v5 (slow path without the slow-start check) on this head. test_safety129 turns red (8 s dead time at a 6 s meter: 122 s late; only the new check fails). Head: green, 0 s, 29 s for the file. test_safety128 green.
  • N1: the DECISIONS sentence matches my numbers (126 s against 32 s).
  • CI on c70eeb6: run 1547 checks / unit and run 1548 infra-pin / fresh, both success.
  • Owner accepted the two missed targets (88 s at a 5 s meter; 10 s late moved to SAFETY-136).
  • Nit, not blocking: "a few times in a row" is low; I measured 2 to 48 late fits in a row. The point stands: the 2-in-a-row rule does not protect, the slow-start check does.
Re-review of round 3 (head c70eeb6): **ready, merging.** - Diff 03541a1..c70eeb6: comment in `lateness.py`, DECISIONS, one test. No logic change. - D1 fixed: comment and DECISIONS now say the slow fit alone reads 35-90 s on healthy runs, and the slow-start and battery-fit check is what keeps them at 0 late. The test name no longer makes the old claim. - D2 fixed: I rebuilt mutant v5 (slow path without the slow-start check) on this head. `test_safety129` turns red (8 s dead time at a 6 s meter: 122 s late; only the new check fails). Head: green, 0 s, 29 s for the file. `test_safety128` green. - N1: the DECISIONS sentence matches my numbers (126 s against 32 s). - CI on c70eeb6: run 1547 `checks / unit` and run 1548 `infra-pin / fresh`, both success. - Owner accepted the two missed targets (88 s at a 5 s meter; 10 s late moved to SAFETY-136). - Nit, not blocking: "a few times in a row" is low; I measured 2 to 48 late fits in a row. The point stands: the 2-in-a-row rule does not protect, the slow-start check does.
admin merged commit b291262ee1 into release/1.0 2026-11-07 01:24:40 +01:00
Sign in to join this conversation.
No Reviewers
No labels
1 Participants
Notifications
Due Date
No due date set.
Dependencies

No dependencies set.

Reference: admin/goodwe-addon#236