From e5a0ba23d724533bdc3a7e85585f46b952d48cc1 Mon Sep 17 00:00:00 2001 From: glenn schrooyen Date: Mon, 28 Sep 2026 23:37:55 +0200 Subject: [PATCH] SAFETY-79: CI fixes - MUTATION.md pointer, no key-taking helper, fixture sized on the aim test_peakguard's over-limit fixture now sizes its load against cap - margin, so the floor it asks for is exact wherever in the quarter the suite runs. Co-Authored-By: Claude Opus 5.5 Claude-Session: https://claude.ai/code/session_01UBtqPrG1mDLXzTEBnhEkkV --- goodwe_controller/test_peak_margin.py | 12 ++++-------- goodwe_controller/test_peakguard.py | 4 +++- 2 files changed, 7 insertions(+), 9 deletions(-) diff --git a/goodwe_controller/test_peak_margin.py b/goodwe_controller/test_peak_margin.py index f333846..2416be5 100644 --- a/goodwe_controller/test_peak_margin.py +++ b/goodwe_controller/test_peak_margin.py @@ -11,6 +11,8 @@ has the record. Drives the REAL Controller through tools/safety79_identity.py. 3. The bill and the reports still use the real cap. 4. Each call site in main.py passes the value its side needs. 5. The setting: default, range, refusals in plain words. + +Mutations (MUTATION.md, purged copies) are listed in the pull request. """ import ast @@ -219,14 +221,8 @@ check("test_aim_w: `peak_aim_w()` is cap - margin, and the forecast sizing " print("\n5. the setting") -def _cfg_pair(key): - """(default, schema) lines for `key` at two spaces in config.yaml.""" - with open(os.path.join(HERE, "config.yaml"), encoding="utf-8") as f: - hits = re.findall(rf"^ {key}:\s*(\S+)", f.read(), re.M) - return hits - - -_hits = _cfg_pair("peak_margin_w") +with open(os.path.join(HERE, "config.yaml"), encoding="utf-8") as f: + _hits = re.findall(r"^ peak_margin_w:\s*(\S+)", f.read(), re.M) print(f" config.yaml: {_hits}") check("config.yaml ships 50, int(0,500), and the in-code mirror matches", _hits == ["50", "int(0,500)"] diff --git a/goodwe_controller/test_peakguard.py b/goodwe_controller/test_peakguard.py index 4e653b3..909ccfe 100644 --- a/goodwe_controller/test_peakguard.py +++ b/goodwe_controller/test_peakguard.py @@ -1175,7 +1175,9 @@ def wired_over_limit(db, want_floor_w, opts=None, store=None, batt_w=0.0, int(now.timestamp() // QUARTER_S) * QUARTER_S, timezone.utc) span = int((now - blk).total_seconds()) remaining = max(1.0, QUARTER_S - (now - blk).total_seconds()) - net_w = CAP_W + want_floor_w * remaining / QUARTER_S + # SAFETY-79: sized against what the guard aims at, cap - margin. + net_w = (CAP_W - ctl.peak_margin_w + + want_floor_w * remaining / QUARTER_S) for i in range(0, span + 1, 5): ctl.p1.submit(sample(blk + timedelta(seconds=i), net_w)) # ⚠️ AND ONE TELEGRAM AT `now` ITSELF. The averager credits a sample's