SAFETY-43: delinquency measured against the ask, not against a flat 500 W #69

Merged
admin merged 3 commits from SAFETY-43 into release/1.0 2026-09-08 05:56:45 +02:00
5 changed files with 216 additions and 68 deletions
Showing only changes of commit b21e229adf - Show all commits
+7
View File
@@ -138,6 +138,13 @@ one-inverter runs, and the flapping family is 0.0 s in all 840.
`delivery_hold_s` is declared `int(30,900)` while the measured legitimate worst
was 35.0 s; it is now 40.0 s, so the band of schema-legal false-tripping values
widens from `[30, 35]` to `[30, 40]`. CFG-07 should be re-derived against 40.0 s.
⚠️ **IT MUST CLOSE BEFORE INVERTER B IS COMMISSIONED (~2026-09-12)**, not before
the next deploy: the band is UNREACHABLE at N=1 - `delinquent()` answers `{}` for
every input at a roster of one, so no `delivery_hold_s` can false-trip on the
install running today - and commissioning B is the moment it becomes reachable.
⚠️ **AND CFG-07 HAS NO DECISION DOCUMENT IN THIS TREE** - it exists as a card
reference here and in SAFETY-43's record and nowhere else, so whoever takes it
writes `DECISIONS/CFG-07-*.md` first.
**SAFETY-43 CHANGES NO OPTION VALUE, NO SCHEMA BOUND AND NO DEFAULT** - the
fraction is a derived constant with a committed harness behind it, deliberately
not a knob, for the reason there is no `delivery_w`. The one edit to
@@ -100,12 +100,15 @@ row in it, run for run.
cd goodwe/sim && GOODWE_ADDON_REPO=/path/to/goodwe-addon \
python3 -B delivery_window.py --selftest --campaign --fractions
⚠️ **`FRACTIONS` IN THAT FILE HOLDS TEN VALUES AND THE TABLE BELOW HAS TWENTY.**
It was run twice - one pass over `(0.25, 0.50, 0.60, 0.70, 0.75, 0.80, 0.85,
0.90, 0.95, 0.99)`, the shipped list, and one over `(0.05, 0.10, 0.15, 0.20,
0.30, 0.35, 0.40, 0.45, 0.55, 0.65)` with only that tuple changed, to resolve
the low end. **The absolute-arm control row came out identical in both**
(30.0 / 0.0 / 35.0 / 0.0), which is what says the two passes are one campaign.
⚠️ **THE TABLE BELOW WAS PRODUCED BY TWO PASSES; `FRACTIONS` NOW HOLDS ALL
TWENTY SO IT TAKES ONE.** The derivation ran the shipped ten
`(0.25 … 0.99)` and then the ten that resolve the low end
`(0.05 … 0.65)` with only that tuple edited between them. **The absolute-arm
control row came out identical in both** (30.0 / 0.0 / 35.0 / 0.0, same argmax),
which is what says the two passes are one campaign. A table a reviewer cannot
reproduce without knowing to edit a line nobody wrote down is PROC-01's shape in
miniature, so the committed `FRACTIONS` was widened to all twenty in review: the
command above now reproduces every row below.
### 3.1 The curve
@@ -223,22 +226,58 @@ A card that adds a way to raise an alarm has to show what it did **not** add.
`test_packshare.py` part 8b runs the same fixture, the same weights and the same
125 W share with the one fact that makes the shortfall legitimate changed:
| fixture | named |
|---|---|
| B wedged at a healthy 15 % (the fault) | **200 / 200** |
| B at its own 10 % cut-out, otherwise identical trace | **0 / 200** |
| B delivering **half** its share | **0 / 200** |
| fixture | B's share | named | why it is silent |
|---|---|---|---|
| B wedged at a healthy 15 % (the fault) | 77–154 W | **200 / 200** | — it is the fault |
| B at its own 10 % cut-out | **0 W, all 200 cycles** | **0 / 200** | it is never **asked** |
| B delivering **half** its share | 120 W | **0 / 200** | short by 50 %, inside both arms |
The first and second have **identical power traces** — 0 W against a positive
share, 100 % of the ask missing, the relative arm's exact shape — and what
separates them is `account()`, the pack's own `bms_soc_floor`. SAFETY-43 did not
go near that gate, and the third row is ordinary tracking on a small share, which
neither arm reports.
### ⚠️ The cut-out row does NOT grade `account()`, and this record said it did
`test_delivery.py` part 1 carries the same controls on the predicate itself,
including that the relative bound is **strict** (a gap of exactly `frac · share`
is not over it) and that the proper-subset rule still refuses a site-wide cause
(both units delivering none of a 125 W share names nobody).
**Corrected in review.** The first draft of this section claimed the wedged and
cut-out arms had *"identical power traces — 0 W against a positive share, 100 %
of the ask missing"* and that *"what separates them is `account()`"*. **Every
part of that was false**, and the check that carried it was **vacuous**:
* at its own cut-out the pack's usable energy **above that cut-out is zero**, so
`packshare.weights()` answers **0.0** for it, `_fill()`'s preferred pass gives
it nothing, the healthy sibling covers the load alone so the last-resort pass
never runs, and its share is **0 W on all 200 cycles**;
* a unit with a 0 W share is not in `asked`, so `len(asked) < 2` returns `{}`
**before either arm is evaluated** and `account()` is **never consulted**;
* the traces are not identical — the cut-out arm's share is **0 W on every
cycle** (asserted in part 8b and printed on its line) while the wedged arm's
is **125 W** at the last cycle (asserted in the GREEN check) and takes four
distinct values 77/125/133/154 W across the 200, measured by re-running the
same loop with per-cycle recording during review — and "100 % of the ask" is
0/0.
Measured, by deleting the gate the claim rested on:
cut-out arm, account() live named 0/200, distinct B shares: [0]
cut-out arm, account() DELETED named 0/200, distinct B shares: [0]
wedged arm, account() live named 200/200, shares [77,125,133,154]
⚠️ **The fact that replaces it is better, not weaker.** At its own cut-out
**OPT-09 stops asking the pack at all**, so SAFETY-43's relative arm is never
reached — a **second, independent protection sitting upstream of `account()`**:
the allocator declines to ask before the detector has to decline to alarm. Part
8b now asserts the 0 W share and prints it, and runs the arm a second time with
`account()` deleted to show which mechanism is doing the work.
⚠️ **It was invisible for one reason worth keeping**: that line was the only one
in part 8b that did not print its shares. `inverter-b+0` would have been on
screen from the first run. Every line in that part prints them now, and the
derated control's vacuity guard now asserts **its own** unit is asked, rather
than re-asserting a different run's 200/200 — which is exactly why the old guard
could not see this.
**The account gate is graded where it is real**, on a positive 125 W share, in
`test_delivery.py` part 1 (*"THE ACCOUNT GATE IS UNTOUCHED BY IT"* — the same
0 of 125 W with the shortfall explained names nobody). That part also carries
that the relative bound is **strict** (a gap of exactly `frac · share` is not
over it) and that the proper-subset rule still refuses a site-wide cause (both
units delivering none of a 125 W share names nobody).
## 5. N=1 is byte-identical, and it is asserted rather than argued
@@ -262,18 +301,36 @@ is commissioned (~2026-09-12), not before the next deploy.
⚠️ **RUN, NOT REASONED ABOUT.** Each mutation was applied to a tree **copied
fresh** from this branch and mounted `:ro` inside the checks image, so no `.pyc`
could go stale — MUTATION.md's defect, and all three of these are **reds**, the
direction that defect cannot fabricate. Recorded in full in `test_packshare.py`
part 11 as M12–M14.
direction that defect cannot fabricate. Recorded in `test_packshare.py` part 11
as M12–M14.
| mutation | caught by |
|---|---|
| **M12** drop the relative arm, keep `gap > min_w` — *the card itself reverted* | `test_delivery.py` part 1 (1 named check) and `test_packshare.py` 8b (4): the GREEN check goes back to 0/200, the equal arm back to 199, the 6000 W arm back to 195/199. `test_alloc.py` and `test_control.py` stay green — nothing outside this check moves. |
| **M13** `DELIVERY_SHARE_FRACTION` 0.85 → **1.0** — *too loose* | 5 named checks, including part 8b's PRECONDITION that the fraction is strictly below 1.0. At 1.0 the card is a no-op: gap/share of exactly 1.0 is not *over* 1.0. |
| **M14** `DELIVERY_SHARE_FRACTION` 0.85 → **0.05** — *too sensitive* | `test_delivery.py` parts 1 and **4b** (4 named checks) and part 8b's DERATED positive control: a unit delivering half its share starts being named, and 4b's `saturation_w` pin goes vacuous. |
| mutation | named checks | where |
|---|---:|---|
| **M12** drop the relative arm, keep `gap > min_w` — *the card itself reverted* | **7** | `test_delivery.py` part 1 (3: the 0-of-125 W naming, the proportion in the sentence, the strict relative bound) + `test_packshare.py` 8b (4: GREEN back to 0/200, the equal arm's 200 back to 199, the 6000 W arm back to 195/199, the derated control's guard). `test_alloc.py` / `test_control.py` stay green — nothing outside this check moves. |
| **M13** `DELIVERY_SHARE_FRACTION` → **1.0** — *too loose* | **7** | part 1 (2) + 8b (5), including the PRECONDITION that the fraction is strictly below 1.0. At 1.0 the card is a no-op: gap/share of exactly 1.0 is not *over* 1.0. |
| **M14** `DELIVERY_SHARE_FRACTION` → **0.05** — *too sensitive* | **6** | part 1 (2: the strict bound, and *"IT TOOK NOTHING AWAY"* stops being true) + part **4b** (3: the `saturation_w` pin goes **vacuous**, the relative arm naming B at every threshold) + 8b's derated control, where a unit delivering half its share starts being named. |
M13 and M14 are the pair that matters: the constant cannot be moved in **either**
direction without a named check moving with it.
### ⚠️ Two of these counts were wrong, and the reason is worth keeping
**Corrected in review.**
* **M12 and M13 read 1 and 1 in `test_delivery.py`, not 3 and 2.** Part 1 printed
the alarm sentence with a bare subscript, `delinquent(_tiny, 500)["b"]`. On any
tree where the relative arm is broken or absent that raises `KeyError` and
**aborts the file at part 1**, leaving parts 2–8 ungraded — so the recorded
coverage of a mutation run read *smaller* than the truth. The direction is safe
(an abort is a red, and MUTATION.md's defect can only fabricate a green), but a
figure that does not reproduce is a figure that does not reproduce. It is a
`.get` now, with the reason written beside it, and the counts above are from
re-runs with the guard in place.
* **M14 was recorded as 4 named checks in `test_delivery.py` and it is 5** — part
1's pre-existing *"a shortfall AT the threshold is not one"* also goes red. That
one under-claimed, so it never inflated the evidence; it is still a recorded
number that did not reproduce.
## 6. ⚠️ [[CFG-07]] is adjacent and is NOT absorbed here
CFG-07 is that `delivery_hold_s` is declared `int(30,900)` in `config.yaml`'s
@@ -290,6 +347,21 @@ with its own compatibility argument (an existing config carrying `35` would star
being refused), and folding it into a safety fix would hide it. **CFG-07 should
be re-derived against 40.0 s, not 35.0 s.**
⚠️ **WHEN IT HAS TO CLOSE: BEFORE INVERTER B IS COMMISSIONED (~2026-09-12).**
Not before the next deploy. The band is **unreachable at N=1** — `delinquent()`
returns `{}` for every input at a roster of one, so no value of
`delivery_hold_s` can false-trip on the install that is running today — and the
live install is N=1 until B exists. Commissioning B is the moment the band
becomes reachable, and that is the deadline this card hands it.
⚠️ **AND CFG-07 HAS NO DECISION DOCUMENT IN THIS TREE.** It exists as a
`[[CFG-07]]` mention in `CHANGELOG.md` and in this section, and nowhere else —
so there is no file for the 40.0 s to be recorded in, and a reader who goes
looking will find a card reference with no record behind it. Whoever takes
CFG-07 writes `DECISIONS/CFG-07-*.md` first; the number it has to answer to is
**40.0 s**, measured here, and the harness that produces it is
`admin/goodwe:sim/delivery_window.py --campaign --fractions`.
## 7. Provenance of every number in this document
| number | where it came from |
@@ -300,7 +372,10 @@ be re-derived against 40.0 s, not 35.0 s.**
| 1000 W / 6500 W suppression windows | part 8b's arithmetic, asserted there |
| 185 s, 5.29× | SAFETY-42 §3.3 / TEST-21, unchanged by this card |
| 4.62× | 185 / 40.0, printed by the campaign |
| 0/200 on both positive controls | part 8b, run |
| 0/200 on both positive controls, and B's 0 W share at the cut-out | part 8b, run and asserted |
| 0 W cut-out share / 125 W wedged share | part 8b, asserted and printed |
| 77/125/133/154 W (the wedged arm's four distinct shares) | the same loop re-run in review with per-cycle recording — NOT part 8b's printed line, which shows the last cycle only |
| M12/M13/M14 named-check counts (7 / 7 / 6) | re-run in review on fresh `:ro` trees, after the `KeyError` abort in part 1 was guarded |
| 84 single-unit rosters | part 8b, run |
⚠️ Every two-inverter figure above is **two copies of inverter A**.
+6 -5
View File
@@ -478,11 +478,12 @@ MIN_W_IS_SATURATION_W = "control.Tuning.saturation_w"
# stagger lands B's number up to four cycles late and a unit whose new command
# has not arrived IS delivering a small fraction of what is standing on its
# wire. What is zero at every fraction is false ALARMS: the longest legitimate
# episode anywhere in the 20-point sweep is 90.0 s (at 0.05, twelve times more
# sensitive than shipped) against a `delivery_hold_s` of 185 s, so NOTHING in
# 2640 no-fault runs comes within 95 s of notifying an operator at any fraction
# measured. At 0.85 the hold is 4.62x the worst legitimate episode where the
# absolute arm alone gave 5.29x. That is the price, in full.
# episode anywhere in the 20-point sweep is 90.0 s - at 0.05, the most sensitive
# fraction measured and far below anything this card would ship - against a
# `delivery_hold_s` of 185 s, so NOTHING in 2640 no-fault runs comes within 95 s
# of notifying an operator at any fraction measured. At 0.85 the hold is 4.62x
# the worst legitimate episode where the absolute arm alone gave 5.29x. That is
# the price, in full.
#
# ⚠️ THE DIRECTION IS THE OPPOSITE OF `min_w`'s AND IT IS EASY TO GET BACKWARDS.
# A SMALLER fraction names MORE units - it is the more sensitive setting and the
+10 -3
View File
@@ -172,12 +172,19 @@ check("A UNIT DELIVERING 0 OF 125 W IS NAMED, AND UNDER THE OLD RULE IT WAS "
"because 100 % of its ask is not arriving",
delinquent(_tiny, 500, _ABS) == {}
and list(delinquent(_tiny, 500)) == ["b"])
print(f" {delinquent(_tiny, 500)['b']}")
# ⚠️ `.get`, NOT `["b"]`, AND THAT IS NOT STYLE. A bare subscript here raises
# KeyError on any tree where the relative arm is broken or absent, which ABORTS
# THE FILE at part 1 and leaves parts 2-8 UNGRADED. The direction is safe - an
# abort is a red, and MUTATION.md's defect can only fabricate a green - but the
# recorded coverage of a mutation run then reads larger than it was, which is
# the shape M11's entry in test_packshare.py part 11 already discloses. Found
# in review of this card, on M12 and M13.
_tiny_said = delinquent(_tiny, 500).get("b", "(not named - see the check above)")
print(f" {_tiny_said}")
check("...and the sentence carries the PROPORTION as well as the watts, because "
"'125 W is not arriving' reads like a rounding error and '125 W (100 % of "
"it)' is the fault",
"125 W of its share (100 % of it) is not arriving"
in delinquent(_tiny, 500)["b"])
"125 W of its share (100 % of it) is not arriving" in _tiny_said)
check("THE ACCOUNT GATE IS UNTOUCHED BY IT - the same 0 of 125 W with the "
"shortfall EXPLAINED names nobody. A relative criterion that could talk "
+90 -32
View File
@@ -662,7 +662,7 @@ ABSOLUTE_ONLY = None # `share_frac=None` - SAFETY-42's rule
def wedged_loop(load_w, weighted, cycles=200, share_frac=DELIVERY_SHARE_FRACTION,
b_delivers=0.0, b_soc=WEDGED_B_SOC):
b_delivers=0.0, b_soc=WEDGED_B_SOC, no_account=False):
"""The closed loop with unit B WEDGED at a healthy SoC. Real everything.
Real `compute()`, real `plan()`, real `packshare.weights()`, real
@@ -679,6 +679,12 @@ def wedged_loop(load_w, weighted, cycles=200, share_frac=DELIVERY_SHARE_FRACTION
cycles under SAFETY-42's rule, which is how the red and the green below come
out of ONE run over ONE tree instead of out of two commits.
`no_account=True` DELETES the account gate - every unit is handed
`accounted=None` - and it exists to answer "would this arm still be silent
if `account()` did nothing at all?". A control that answers the same way
with the gate removed is not grading the gate, and the cut-out arm below is
exactly that case. See it there; it is the point of that block.
Returns `(cycles on which delinquent() named somebody, last cycle)`.
"""
packs = [PE(A, WEDGED_A_SOC, A_KWH), PE(Bee, b_soc, B_KWH)]
@@ -699,6 +705,7 @@ def wedged_loop(load_w, weighted, cycles=200, share_frac=DELIVERY_SHARE_FRACTION
grid = load_w - sum(power)
who = delinquent(
[UnitDelivery(p.name, r.shares[p.name], m,
None if no_account else
account(live=True, parked=False, soc=p.soc,
bms_floor=p.bms_floor))
for p, m in zip(packs, power)], MIN_W, share_frac)
@@ -825,18 +832,56 @@ print(" THE POSITIVE CONTROL: what the relative arm must STILL NOT say")
# HA". So: the same fixture, the same weights, the same tiny 125 W share, with
# the ONE fact that makes the shortfall legitimate changed.
# ⚠️ AND THE FIRST DRAFT OF THIS BLOCK WAS VACUOUS, WHICH IS WHY IT NOW PRINTS
# ITS SHARES. It ran the cut-out arm, saw 0/200, and concluded "`account()`
# explains it" and "identical trace to the wedged arm". BOTH WERE FALSE. At its
# own cut-out the pack's usable energy ABOVE that cut-out is zero, so
# `weights()` gives it 0.0, `_fill()`'s preferred pass gives it nothing, the
# healthy sibling covers the load alone so the LAST-RESORT pass never runs, and
# its share is 0 W on ALL 200 CYCLES. A unit with a 0 W share is not in `asked`,
# so `len(asked) < 2` returns {} BEFORE EITHER ARM IS EVALUATED and `account()`
# is never consulted - measured below by deleting the gate and getting the same
# answer. The wedged arm's share is the 125 W printed on its own line above;
# this one's is 0, printed and asserted below. Nothing was identical and nothing
# reached the comparison.
#
# ⚠️ THE FACT THAT REPLACES IT IS BETTER, NOT WEAKER: at its own cut-out OPT-09
# STOPS ASKING THE PACK AT ALL, so SAFETY-43's relative arm is never reached.
# That is a SECOND, INDEPENDENT protection sitting UPSTREAM of `account()` - the
# allocator declines to ask before the detector has to decline to alarm. The
# account gate itself is graded where it is REAL, on a positive 125 W share, in
# `test_delivery.py` part 1 ("THE ACCOUNT GATE IS UNTOUCHED BY IT").
#
# ⚠️ AND IT WAS INVISIBLE FOR ONE REASON: this was the only line in part 8b that
# did not print its shares. `inverter-b+0` would have been on screen from the
# first run. Every line in this part prints them now.
_sat_named, _sat_last = wedged_loop(1500.0, True, b_soc=FLOOR)
_sat_nogate, _sat_nogate_last = wedged_loop(1500.0, True, b_soc=FLOOR,
no_account=True)
print(f" load 1500 W, B AT ITS OWN {FLOOR:.0f} % CUT-OUT, OPT-09 weights, "
f"frac {DELIVERY_SHARE_FRACTION:.2f}: named on {_sat_named:3d}/200 "
f"cycles, named="
+ (str(sorted(_sat_last[3])) if _sat_last[3] else "(nobody)"))
check("A PACK AT ITS OWN CUT-OUT DELIVERING NOTHING OF A SMALL SHARE IS STILL "
"NOT DELINQUENT. Identical trace to the wedged arm - 0 W against a "
"positive share, 100 % of the ask missing, the relative arm's exact "
"shape - and `account()` explains it, so nobody is named on any of the "
"200 cycles. The account gate is what keeps normal saturation out and "
"SAFETY-43 did not go near it",
_sat_named == 0 and _sat_last[3] == {})
f"cycles, shares "
+ ", ".join(f"{u}{v:+d}" for u, v in sorted(_sat_last[1].items()))
+ ", named="
+ (str(sorted(_sat_last[3])) if _sat_last[3] else "(nobody)")
+ f"; with account() DELETED: {_sat_nogate:3d}/200")
check("A PACK AT ITS OWN CUT-OUT IS NEVER ASKED, SO THE RELATIVE ARM IS NEVER "
"REACHED. Its usable energy above its own cut-out is zero, `weights()` "
"answers 0.0 for it, the healthy sibling covers the load so `_fill()`'s "
"last-resort pass never runs, and its share is 0 W on every one of the "
"200 cycles - so it is not in `asked` and `len(asked) < 2` returns {} "
"before either arm is compared. ⚠️ THE SHARE IS ASSERTED, not inferred "
"from the silence: a control that cannot say WHY it is quiet is a control "
"that cannot fail",
_sat_named == 0 and _sat_last[3] == {} and _sat_last[1][Bee] == 0)
check("⚠️ AND THAT IS A SECOND, INDEPENDENT PROTECTION - NOT THE ACCOUNT GATE, "
"WHICH THIS ARM DOES NOT TOUCH. Delete `account()` entirely, hand every "
"unit `accounted=None`, and this arm is STILL silent on all 200 cycles, "
"because the protection is UPSTREAM of it: the allocator declines to ask "
"before the detector has to decline to alarm. ⚠️ SO DO NOT READ THIS "
"BLOCK AS EVIDENCE ABOUT `account()` - it is evidence about the ask. The "
"account gate on a POSITIVE share is graded in test_delivery.py part 1",
_sat_nogate == 0 and _sat_nogate_last[3] == {})
_derate_named, _derate_last = wedged_loop(1500.0, True, b_delivers=0.5)
print(f" load 1500 W, B delivering HALF its share, OPT-09 weights, frac "
@@ -853,11 +898,15 @@ check("...and ORDINARY TRACKING ON A SMALL SHARE IS NOT DELINQUENCY EITHER. "
"whole module is written against",
_derate_named == 0 and _derate_last[3] == {})
check("...and the two controls are not vacuous: the SAME loop with the SAME "
"weights and a WEDGED B names it on all 200, so what separates them is "
"the pack's own cut-out and the size of the shortfall, not something "
"about the fixture that stopped the check reaching the comparison",
_wedge[(1500.0, True, DELIVERY_SHARE_FRACTION)][0] == 200)
check("...and the DERATED control is not vacuous, which is asserted on the ONE "
"thing that could make it so: unlike the cut-out arm above, its unit IS "
"asked - a positive share on every cycle - so it really does reach both "
"arms and is turned away by the size of its shortfall. ⚠️ THIS GUARD USED "
"TO RE-ASSERT THE WEDGED ARM's 200/200 INSTEAD, WHICH IS WHY IT DID NOT "
"CATCH THE CUT-OUT ARM BEING VACUOUS: a check on a DIFFERENT run cannot "
"say anything about whether THIS one reached the comparison",
_derate_last[1][Bee] > 0
and _wedge[(1500.0, True, DELIVERY_SHARE_FRACTION)][0] == 200)
print()
print(" N=1 IS BYTE-IDENTICAL, AND THAT IS ASSERTED RATHER THAN ARGUED")
@@ -1186,24 +1235,27 @@ MUT = [
# --- SAFETY-43's three, and they pin the new arm from BOTH sides --------
("M12 delinquent(): drop the relative arm, keep `gap > min_w` <- THE "
"CARD ITSELF REVERTED",
"test_delivery 1 (one named check) and test_packshare 8b (FOUR): the "
"GREEN check goes back to 0/200 under OPT-09's weights, the equal arm "
"goes back to 199, the 6000 W arm back to 195/199, and the vacuity guard "
"on the positive controls falls with them. test_alloc and test_control "
"stay green, which is the point - nothing outside this check moves"),
"SEVEN named checks: test_delivery 1 (THREE - the 0-of-125 W naming, the "
"proportion in the sentence, and the strict relative bound) and "
"test_packshare 8b (FOUR - the GREEN check goes back to 0/200 under "
"OPT-09's weights, the equal arm's 200 back to 199, the 6000 W arm back "
"to 195/199, and the derated control's vacuity guard falls with them). "
"test_alloc and test_control stay green, which is the point - nothing "
"outside this check moves"),
("M13 DELIVERY_SHARE_FRACTION 0.85 -> 1.0 <- THE TOO-LOOSE DIRECTION",
"test_delivery 1 and test_packshare 8b, five named checks including the "
"PRECONDITION that the fraction is strictly below 1.0. At 1.0 the arm can "
"only fire on a unit IMPORTING while asked to discharge, so the card's "
"own case - 0 of 125 W, gap over share exactly 1.0 - is missed and the "
"whole card is a no-op"),
"SEVEN named checks: test_delivery 1 (TWO) and test_packshare 8b (FIVE), "
"including the PRECONDITION that the fraction is strictly below 1.0. At "
"1.0 the arm can only fire on a unit IMPORTING while asked to discharge, "
"so the card's own case - 0 of 125 W, gap over share exactly 1.0 - is "
"missed and the whole card is a no-op"),
("M14 DELIVERY_SHARE_FRACTION 0.85 -> 0.05 <- THE TOO-SENSITIVE ONE",
"test_delivery 1 and 4b (four named checks) and test_packshare 8b's "
"DERATED positive control: a unit delivering half its share starts being "
"named, and part 4b's `saturation_w` pin goes vacuous because the "
"relative arm names B at every threshold. ⚠️ THIS IS THE ROW THAT MATTERS "
"- the fraction is pinned from BOTH directions, so it is a derived number "
"with checks around it rather than a literal nobody can move"),
"SIX named checks: test_delivery 1 (TWO - the strict bound, and 'IT TOOK "
"NOTHING AWAY' stops being true) and 4b (THREE - the `saturation_w` pin "
"goes VACUOUS, because the relative arm names B at every threshold), plus "
"test_packshare 8b's DERATED positive control, where a unit delivering "
"half its share starts being named. ⚠️ THIS IS THE ROW THAT MATTERS - the "
"fraction is pinned from BOTH directions, so it is a derived number with "
"checks around it rather than a literal nobody can move"),
]
for _n, _w in MUT:
print(f" caught {_n}")
@@ -1216,7 +1268,13 @@ check("every mutation in the table above was RUN and every one of them is "
"why the call site is pinned statically as well. ⚠️ M12-M14 ARE "
"SAFETY-43's and were run the same way, on trees copied fresh and "
"mounted :ro so no `.pyc` could go stale - MUTATION.md's defect. All "
"three are REDS, which is the direction that defect cannot fabricate",
"three are REDS, which is the direction that defect cannot fabricate. "
"⚠️ AND THEIR COUNTS WERE RE-RUN IN REVIEW AND TWO OF THEM MOVED: "
"test_delivery.py part 1 used to subscript `delinquent(...)['b']` for a "
"print, which raised KeyError under M12 and M13 and ABORTED THE FILE at "
"part 1, leaving parts 2-8 ungraded and the recorded coverage smaller "
"than the truth. It is a `.get` now. M14's count was simply wrong: five "
"named checks in test_delivery, not four",
len(MUT) == 14)
print()