diff --git a/goodwe_controller/CHANGELOG.md b/goodwe_controller/CHANGELOG.md index 1ec6f33..8412c33 100644 --- a/goodwe_controller/CHANGELOG.md +++ b/goodwe_controller/CHANGELOG.md @@ -266,12 +266,14 @@ shipped `sum` is correct and must not be "fixed".** it does not belong on"* and asserted `"peak" in scope_errors[0]`, which is still true after the two swap roles. Measured this round: **0 bytes, 21/21 green**; now red on 2 checks, pinned on the ordered pair. -* **14 more zero-byte mutations measured, and 11 SURVIVORS ARE DISCLOSED RATHER +* **14 more zero-byte mutations measured, and 10 SURVIVORS ARE DISCLOSED RATHER THAN CLOSED**, each with its file fingerprint and its 21/21 verdict, in - `DECISIONS/SAFETY-38-site-standing-pin.md` §7e–§7g: three in + `DECISIONS/SAFETY-38-site-standing-pin.md` §7e–§7g: **two** in `allocator.py`'s `UnitPlan.explain()`, three across `arbiter.py`'s two `explain()`s, two in `tariff.py`, two in `arbitrage.py`'s trade reasons and - one in `main.py`'s SoC-floor notification. **An enumerated list with honest + one in `main.py`'s SoC-floor notification. The other four of the fourteen are + kills: `allocator.py:162` was already caught by `test_alloc.py`, and + `clamp.py:253`, `peakguard.py:493` and `arbiter.py:264` are closed here. **An enumerated list with honest gaps beats a fifth round finding a fifth instance.** ⚠️ **And the probe that grades those mutations was itself the defect, once.** Its first cut numbered the operands **by order of appearance**, so after a diff --git a/goodwe_controller/DECISIONS/SAFETY-38-site-standing-pin.md b/goodwe_controller/DECISIONS/SAFETY-38-site-standing-pin.md index c86a774..2010492 100644 --- a/goodwe_controller/DECISIONS/SAFETY-38-site-standing-pin.md +++ b/goodwe_controller/DECISIONS/SAFETY-38-site-standing-pin.md @@ -640,11 +640,21 @@ below, unpinned. **Open, named, and measured — see §7f for the ledger:** -* **Nine further zero-byte survivors** found by the widened scan, each measured - at 21/21 green on this tree: three in `allocator.py`'s `UnitPlan.explain()`, - three in `arbiter.py`'s two `explain()`s, two in `tariff.py`, and one each in - `arbitrage.py`'s two decision reasons and `main.py`'s SoC-floor notification. +* **TEN further zero-byte survivors** found by the widened scan, each measured + at 21/21 green on this tree: **two** in `allocator.py`'s `UnitPlan.explain()` + (C1 :154, C2 :160), three in `arbiter.py`'s two `explain()`s (C4a, C4b :344, + C5 :392), two in `tariff.py` (C8, C9), two in `arbitrage.py`'s trade reasons + (B17, B18) and one in `main.py`'s SoC-floor notification (B19). None is a control decision; every one is a sentence an operator reads. + ⚠️ **CORRECTED after review, and the error is worth keeping visible.** This + bullet first said "Nine" while listing eleven, and the CHANGELOG said eleven + while listing eleven — and BOTH counted `allocator.py:162` (C3) among the + survivors when §7f records it as a KILL, red in `test_alloc.py`. The + authoritative tables in §7e and §7f were right throughout; only the summary + sentences a reader actually relies on were wrong. That is this card's own + recurring defect in prose rather than in code: a claim wider than the + measurement beneath it. Arithmetic, from §7f: 14 measured = 10 surviving + + 1 already caught (C3) + 3 caught by this round (C6, C7, B12). * **The action-log surface of the peak-guard idle line** (`main.py:1951`) is not pinned. The status row (3313) is, and both come off the same `explain()`, so the *sentence* is closed and the *second call site* is not — which is