delivery.delinquent() named a unit whose short_by() gap exceeded a flat min_w = Tuning.saturation_w = 500 W. OPT-09's SoC-aware weights shrink a
low-headroom unit's share, and shrinking the share shrinks the gap — so a unit
standing at +125 W and delivering 0 W, 100 % delinquent, was never named.
Measured end to end on the real loop (test_packshare.py part 8b: real compute(), real plan(), real packshare.weights(), real account(), real delinquent(); B wedged at a healthy 15 % against its own 10 % cut-out, so no
envelope closes and nothing explains the shortfall — a SAFETY-42 true
positive by that card's own definition):
load 1500 W, B wedged, equal weights named on 199/200 cycles
load 1500 W, B wedged, OPT-09 weights named on 0/200 cycles
⚠️The suppressed regime is the quiet one. At a load the healthy sibling
covers, the meter is satisfied, unmet_w is 0 and no action-log line fires, so
this alarm is the only instrument that would have told the operator the site
was running one inverter.
The fix
named if short_by() > min_w OR short_by() > frac * share
⚠️min_w WAS NOT LOWERED, and that is the larger half of this card. It
exists to stop normal saturation being reported as delinquency; lowering it
trades a missed alarm for a false one on every unit at once — SAFETY-41's
four-attempt regime, "i'm getting really annoyed by the notifications in my
HA". This adds a second way to be named:
all seven of test_delivery.py part 1's existing delinquent() fixtures
answer identically under SAFETY-42's rule and the shipped one;
the absolute arm's suppression window is still exactly 1000 W (equal
weights) and 6500 W (OPT-09's), and part 8b still asserts both numbers.
⭐ Deriving the fraction — 0.85
admin/goodwe:sim/delivery_window.py (the harness TEST-21 committed) gained a --fractions grading axis: the same 2640 no-fault runs at N=2 and 2640 at
N=1 that produced delivery_hold_s's 35.0 s floor, graded at the shipped min_w for each candidate fraction, on every cycle of every run.
Worst continuous legitimate episode, worst of the three families:
frac 0.05 0.10 0.15 0.20 0.25 0.30 0.35 0.40 0.45 0.50
worst 90.0 90.0 70.0 70.0 60.0 55.0 55.0 60.0 45.0 45.0 s
frac 0.55 0.60 0.65 0.70 0.75 0.80 *0.85 0.90 0.95 0.99
worst 40.0 40.0 45.0 45.0 45.0 45.0 40.0 40.0 40.0 40.0 s
absolute arm alone: 35.0 s — SAFETY-42 §3.3's figure, reproduced by the
same runs, same argmax (gain=0.2 slew_w=1000 stagger=4 split=0.10/0.90)
⚠️NO CLIFF ANYWHERE, AND THAT IS THE FINDING. 0.45–0.99 is flat to within one control cycle (5.0 s); below 0.45 it rises gradually to 90.0 s at
0.05. A reviewer asking "why not 0.90?" is asking about a difference this
campaign cannot resolve, and the record says so.
⚠️IT IS NOT MONOTONE (0.40 → 60.0 s where 0.35 → 55.0) — SAFETY-42
§3.3's own mechanism (c): a more sensitive rule puts more units into the
short set, which can turn a proper subset into the whole roster and end the
episode.
N=1 control: 0.0 s at every fraction, all 2640 one-inverter runs. Flapping: 0.0 s at every fraction, all 840 runs.
⚠️ "Zero false namings" is not achievable at any fraction
The card asked for the largest fraction with zero false namings. There is
none — every fraction adds naming cycles (reversals 460 → 840 runs naming). A
relative arm that never fired on a legitimate transient is one that never fires:
the modelled write stagger lands B's number up to four cycles late.
What is zero at every fraction is false alarms: the longest legitimate
episode in the whole sweep is 90.0 s against a 185 s hold, so nothing in
2640 no-fault runs comes within 95 s of notifying anybody — 145 s of
slack at the shipped 0.85. delivery_hold_s goes from 5.29× to 4.62× the
worst legitimate episode and is not changed.
The bounds 0.85 answers to
lower — the shoulder at ~0.45 (0.85 is 0.40 above it);
upper — strictly below 1.0, or the card's own case (gap/share exactly 1.0)
is missed; the 0.15 covers a wedged box reporting a standby figure rather than
a clean zero;
not derived, and said so: the exact value inside [0.45, 1.0).
⭐ DRIVEN: the pin inverted
Part 8b pinned the suppressed behaviour and said "if it ever goes red
because the alarm fired, read the card that made it fire before 'fixing' this
line". This is that card. It now grades both rules on one run — share_frac=None is SAFETY-42's rule exactly — so the red and the green are in
one output rather than in two commits:
load 1500 W OPT-09 weights absolute arm alone named on 0/200
load 1500 W OPT-09 weights the shipped rule named on 200/200
load 1500 W equal weights absolute arm alone named on 199/200
load 1500 W equal weights the shipped rule named on 200/200
The equal arm gains exactly one cycle — the first, where the slew limit holds
the split at 500/500 and a 500 W gap is not over a 500 W threshold.
Positive control — what it must still NOT say
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
⚠️ Corrected in review — the cut-out row does NOT grade account()
The first version of this table said the cut-out row had an "identical power
trace" to the wedged one and that account() was what separated them. Both
were false, and the check was vacuous. At its own cut-out the pack's usable
energy above that cut-out is zero, so weights() answers 0.0, plan() gives
it a 0 W share on all 200 cycles, it is never in asked, and len(asked) < 2 returns {}before either arm is evaluated. 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 wedged arm's four distinct shares come from re-running that loop with
per-cycle recording in review; part 8b's own line prints the last cycle, 125 W,
and asserts it.)
⚠️The replacement fact is stronger, not weaker: at its own cut-out OPT-09
stops asking the pack at all, so the relative arm is never reached — a second, independent protection upstream of account(). The allocator
declines to ask before the detector has to decline to alarm. Part 8b now asserts the 0 W share, prints the shares on that line (it was the only line
in the part that did not — inverter-b+0 would have been visible from the first
run), and re-runs the arm with account() deleted to show which mechanism does
the work. 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 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"). That part
also carries that the relative bound is strict and that the proper-subset
rule still refuses a site-wide cause.
N=1 byte-identical, asserted not argued
plan() handed a weights mapping that raises on any read answers
identically at a roster of one — and the same mapping raises at a roster of
two, so the tripwire is real;
delinquent() answers {} on all 84 single-unit (share, measured, rule)
combinations, including 0 of 125 W.
Mutation — run, on fresh :ro trees
named checks
caught by
M12 drop the relative arm
7
part 1 (3) + part 8b (4); test_alloc / test_control stay green
M13 frac → 1.0
7
part 1 (2) + 8b (5) — at 1.0 the card is a no-op
M14 frac → 0.05
6
part 1 (2) + 4b (3, the saturation_w pin goes vacuous) + 8b's derated control
The constant cannot move in either direction unseen.
⚠️Two of these counts were corrected in review. Part 1 printed the alarm
sentence with a bare delinquent(...)["b"], which raises KeyError under M12/M13
and aborted the file at part 1, leaving parts 2–8 ungraded — so M12 and M13
were recorded as 1 named check each in test_delivery.py when they are 3 and 2.
The direction is safe (an abort is a red; MUTATION.md's defect fabricates only
greens), but a figure that does not reproduce is a figure that does not
reproduce. It is a .get now. M14 was recorded as 4 and is 5 — part 1's
pre-existing "a shortfall AT the threshold is not one" also goes red.
⚠️CFG-07 — worse by one control cycle, deliberately not fixed here
delivery_hold_s is declared int(30,900) while the measured legitimate worst
was 35.0 s; with the relative arm it is 40.0 s, so the band of
schema-legal but false-tripping values widens from [30, 35] to [30, 40]. CFG-07 should be re-derived against 40.0 s, not 35.0 s. Raising a schema
floor is an option-surface change with its own compatibility argument, and
folding it into a safety fix would hide it.
Scope
No option value, no schema bound, no default changed. The one config.yaml
edit is a comment — the delivery_hold_s block described the check as "short by
more than saturation_w", which is now half of it. The fraction is a derived
constant, deliberately not a knob, for the reason there is no delivery_w.
DECISIONS/SAFETY-43-delinquency-relative-to-the-ask.md carries the full curve,
the controls and the provenance of every number. OPT-09's §5 disclosure and packshare.py's docstring are replaced by a statement of the closure, with the
old measurement kept beside it.
Companion PR in admin/goodwe (#50): the harness change that derives the
fraction. ⚠️THIS PR MERGES FIRST.admin/goodwe's checks.yml fetches this
repo's release/1.0, never a PR ref, so until this lands there #50's new
selftest arm self-skips and grades nothing. It is written to pass in that state
deliberately — a hard assert would report this repo as broken for being older
than the harness — but the order is #69, then #50.
Suite: 27/27 green. Positive control on the harness confirmed first (a
deliberately broken assert reports RED, restored clean).
## The defect
`delivery.delinquent()` named a unit whose `short_by()` gap exceeded a **flat**
`min_w = Tuning.saturation_w = 500 W`. [[OPT-09]]'s SoC-aware weights shrink a
low-headroom unit's share, and shrinking the share shrinks the gap — so a unit
standing at **+125 W and delivering 0 W**, 100 % delinquent, was never named.
Measured end to end on the real loop (`test_packshare.py` part 8b: real
`compute()`, real `plan()`, real `packshare.weights()`, real `account()`, real
`delinquent()`; B wedged at a healthy 15 % against its own 10 % cut-out, so no
envelope closes and nothing explains the shortfall — a SAFETY-42 **true
positive** by that card's own definition):
load 1500 W, B wedged, equal weights named on 199/200 cycles
load 1500 W, B wedged, OPT-09 weights named on 0/200 cycles
⚠️ **The suppressed regime is the quiet one.** At a load the healthy sibling
covers, the meter is satisfied, `unmet_w` is 0 and no action-log line fires, so
this alarm is the **only** instrument that would have told the operator the site
was running one inverter.
## The fix
named if short_by() > min_w OR short_by() > frac * share
⚠️ **`min_w` WAS NOT LOWERED**, and that is the larger half of this card. It
exists to stop normal saturation being reported as delinquency; lowering it
trades a missed alarm for a false one on every unit at once — SAFETY-41's
four-attempt regime, *"i'm getting really annoyed by the notifications in my
HA"*. This **adds** a second way to be named:
* all **seven** of `test_delivery.py` part 1's existing `delinquent()` fixtures
answer **identically** under SAFETY-42's rule and the shipped one;
* the absolute arm's suppression window is still exactly **1000 W** (equal
weights) and **6500 W** (OPT-09's), and part 8b still asserts both numbers.
## ⭐ Deriving the fraction — 0.85
`admin/goodwe:sim/delivery_window.py` (the harness TEST-21 committed) gained a
`--fractions` grading axis: the **same 2640 no-fault runs at N=2** and **2640 at
N=1** that produced `delivery_hold_s`'s 35.0 s floor, graded at the shipped
`min_w` for each candidate fraction, on every cycle of every run.
Worst continuous legitimate episode, worst of the three families:
frac 0.05 0.10 0.15 0.20 0.25 0.30 0.35 0.40 0.45 0.50
worst 90.0 90.0 70.0 70.0 60.0 55.0 55.0 60.0 45.0 45.0 s
frac 0.55 0.60 0.65 0.70 0.75 0.80 *0.85 0.90 0.95 0.99
worst 40.0 40.0 45.0 45.0 45.0 45.0 40.0 40.0 40.0 40.0 s
absolute arm alone: 35.0 s — SAFETY-42 §3.3's figure, reproduced by the
same runs, same argmax (gain=0.2 slew_w=1000 stagger=4 split=0.10/0.90)
* ⚠️ **NO CLIFF ANYWHERE, AND THAT IS THE FINDING.** 0.45–0.99 is flat to within
**one control cycle (5.0 s)**; below 0.45 it rises **gradually** to 90.0 s at
0.05. A reviewer asking "why not 0.90?" is asking about a difference this
campaign cannot resolve, and the record says so.
* ⚠️ **IT IS NOT MONOTONE** (0.40 → 60.0 s where 0.35 → 55.0) — SAFETY-42
§3.3's own mechanism (c): a more sensitive rule puts **more** units into the
short set, which can turn a proper subset into the whole roster and **end** the
episode.
* **N=1 control: 0.0 s at every fraction**, all 2640 one-inverter runs.
**Flapping: 0.0 s at every fraction**, all 840 runs.
### ⚠️ "Zero false namings" is not achievable at any fraction
The card asked for the largest fraction with zero false namings. **There is
none** — every fraction adds naming cycles (reversals 460 → 840 runs naming). A
relative arm that never fired on a legitimate transient is one that never fires:
the modelled write stagger lands B's number up to four cycles late.
What **is** zero at every fraction is **false alarms**: the longest legitimate
episode in the whole sweep is **90.0 s** against a **185 s** hold, so nothing in
2640 no-fault runs comes within **95 s** of notifying anybody — **145 s** of
slack at the shipped 0.85. `delivery_hold_s` goes from 5.29× to **4.62×** the
worst legitimate episode and is **not changed**.
### The bounds 0.85 answers to
* **lower** — the shoulder at ~0.45 (0.85 is 0.40 above it);
* **upper** — strictly below 1.0, or the card's own case (gap/share exactly 1.0)
is missed; the 0.15 covers a wedged box reporting a standby figure rather than
a clean zero;
* **not derived, and said so**: the exact value inside [0.45, 1.0).
## ⭐ DRIVEN: the pin inverted
Part 8b pinned the **suppressed** behaviour and said *"if it ever goes red
because the alarm fired, read the card that made it fire before 'fixing' this
line"*. This is that card. It now grades **both rules on one run** —
`share_frac=None` is SAFETY-42's rule exactly — so the red and the green are in
one output rather than in two commits:
load 1500 W OPT-09 weights absolute arm alone named on 0/200
load 1500 W OPT-09 weights the shipped rule named on 200/200
load 1500 W equal weights absolute arm alone named on 199/200
load 1500 W equal weights the shipped rule named on 200/200
The equal arm gains **exactly one cycle** — the first, where the slew limit holds
the split at 500/500 and a 500 W gap is not *over* a 500 W threshold.
## Positive control — what it must still NOT say
| 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 |
### ⚠️ Corrected in review — the cut-out row does NOT grade `account()`
The first version of this table said the cut-out row had an *"identical power
trace"* to the wedged one and that `account()` was what separated them. **Both
were false, and the check was vacuous.** At its own cut-out the pack's usable
energy above that cut-out is zero, so `weights()` answers **0.0**, `plan()` gives
it a **0 W share on all 200 cycles**, it is never in `asked`, and
`len(asked) < 2` returns `{}` **before either arm is evaluated**. 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 wedged arm's four distinct shares come from re-running that loop with
per-cycle recording in review; part 8b's own line prints the last cycle, 125 W,
and asserts it.)
⚠️ **The replacement fact is stronger, not weaker**: at its own cut-out **OPT-09
stops asking the pack at all**, so the relative arm is never reached — a
**second, independent protection upstream of `account()`**. The allocator
declines to ask before the detector has to decline to alarm. Part 8b now
**asserts the 0 W share, prints the shares on that line** (it was the only line
in the part that did not — `inverter-b+0` would have been visible from the first
run), and re-runs the arm with `account()` deleted to show which mechanism does
the work. 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 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"*). That part
also carries that the relative bound is **strict** and that the proper-subset
rule still refuses a site-wide cause.
## N=1 byte-identical, asserted not argued
* `plan()` handed a `weights` mapping that **raises on any read** answers
identically at a roster of one — and the **same mapping raises at a roster of
two**, so the tripwire is real;
* `delinquent()` answers `{}` on all **84** single-unit (share, measured, rule)
combinations, **including 0 of 125 W**.
## Mutation — run, on fresh `:ro` trees
| | named checks | caught by |
|---|---:|---|
| **M12** drop the relative arm | **7** | part 1 (3) + part 8b (4); `test_alloc` / `test_control` stay green |
| **M13** frac → **1.0** | **7** | part 1 (2) + 8b (5) — at 1.0 the card is a no-op |
| **M14** frac → **0.05** | **6** | part 1 (2) + **4b** (3, the `saturation_w` pin goes vacuous) + 8b's derated control |
The constant cannot move in **either** direction unseen.
⚠️ **Two of these counts were corrected in review.** Part 1 printed the alarm
sentence with a bare `delinquent(...)["b"]`, which raises `KeyError` under M12/M13
and **aborted the file at part 1**, leaving parts 2–8 ungraded — so M12 and M13
were recorded as 1 named check each in `test_delivery.py` when they are 3 and 2.
The direction is safe (an abort is a red; MUTATION.md's defect fabricates only
greens), but a figure that does not reproduce is a figure that does not
reproduce. It is a `.get` now. **M14 was recorded as 4 and is 5** — part 1's
pre-existing *"a shortfall AT the threshold is not one"* also goes red.
## ⚠️ [[CFG-07]] — worse by one control cycle, deliberately not fixed here
`delivery_hold_s` is declared `int(30,900)` while the measured legitimate worst
was **35.0 s**; with the relative arm it is **40.0 s**, so the band of
schema-legal but false-tripping values widens from `[30, 35]` to `[30, 40]`.
**CFG-07 should be re-derived against 40.0 s, not 35.0 s.** Raising a schema
floor is an option-surface change with its own compatibility argument, and
folding it into a safety fix would hide it.
## Scope
**No option value, no schema bound, no default changed.** The one `config.yaml`
edit is a comment — the `delivery_hold_s` block described the check as "short by
more than `saturation_w`", which is now half of it. The fraction is a derived
constant, deliberately not a knob, for the reason there is no `delivery_w`.
`DECISIONS/SAFETY-43-delinquency-relative-to-the-ask.md` carries the full curve,
the controls and the provenance of every number. OPT-09's §5 disclosure and
`packshare.py`'s docstring are replaced by a statement of the closure, with the
old measurement kept beside it.
Companion PR in `admin/goodwe` (**#50**): the harness change that derives the
fraction. ⚠️ **THIS PR MERGES FIRST.** `admin/goodwe`'s `checks.yml` fetches this
repo's `release/1.0`, never a PR ref, so until this lands there #50's new
selftest arm self-skips and grades nothing. It is written to pass in that state
deliberately — a hard assert would report this repo as broken for being older
than the harness — but the order is #69, then #50.
**Suite: 27/27 green.** Positive control on the harness confirmed first (a
deliberately broken assert reports RED, restored clean).
🤖 Generated with [Claude Code](https://claude.com/claude-code)
https://claude.ai/code/session_01BwRLw7eKYj2byVdwB6kbjU
`delivery.delinquent()` named a unit whose `short_by()` gap exceeded an
ABSOLUTE `min_w = Tuning.saturation_w = 500 W`. OPT-09's SoC-aware weights
shrink a low-headroom unit's share, and shrinking the share shrinks the gap, so
a unit standing at +125 W and delivering 0 W - 100 % delinquent - was never
named. Measured end to end on the real loop (test_packshare.py part 8b):
load 1500 W, B wedged at 15 %, equal weights named on 199/200 cycles
load 1500 W, B wedged at 15 %, OPT-09 weights named on 0/200 cycles
⚠️ The suppressed regime is the quiet one: at a load the healthy sibling covers,
the meter is satisfied, `unmet_w` is 0 and no action-log line fires, so this
alarm is the ONLY instrument that would have told the operator.
WHAT CHANGED, in one line:
named if short_by() > min_w OR short_by() > frac * share
⚠️ `min_w` WAS NOT LOWERED. It exists to stop normal saturation being reported
as delinquency, and lowering it trades a missed alarm for a false one on every
unit at once - SAFETY-41's four-attempt regime. This is a SECOND way to be
named, not a looser first one: all seven of test_delivery.py part 1's existing
fixtures answer identically under both rules, and the absolute arm's suppression
window is still exactly 1000 W / 6500 W, still asserted in part 8b.
THE FRACTION IS DERIVED, 0.85. admin/goodwe:sim/delivery_window.py gained a
`--fractions` axis and grades the constant over the SAME 2640 no-fault runs that
produced `delivery_hold_s`'s 35.0 s floor. Worst continuous legitimate episode,
worst of three families, twenty fractions:
frac 0.05 0.10 0.15 0.20 0.25 0.30 0.35 0.40 0.45 0.50
worst 90.0 90.0 70.0 70.0 60.0 55.0 55.0 60.0 45.0 45.0 s
frac 0.55 0.60 0.65 0.70 0.75 0.80 *0.85 0.90 0.95 0.99
worst 40.0 40.0 45.0 45.0 45.0 45.0 40.0 40.0 40.0 40.0 s
absolute arm alone: 35.0 s (SAFETY-42 §3.3, reproduced in the same runs)
⚠️ NO CLIFF ANYWHERE: 0.45-0.99 is flat within one control cycle, and it is not
monotone - §3.3's own mechanism (c). ⚠️ "Zero false namings" is NOT achievable
at any fraction and the record says so; what is zero is false ALARMS - 90.0 s
worst against a 185 s hold, so nothing comes within 95 s of notifying anybody.
N=1 control 0.0 s at every fraction in all 2640 one-inverter runs; flapping
0.0 s in all 840.
DRIVEN. Part 8b pinned the SUPPRESSED behaviour and said "if it ever goes red
because the alarm fired, read the card that made it fire". It now grades BOTH
rules on one run - `share_frac=None` is SAFETY-42's rule exactly:
OPT-09 weights, absolute arm alone named on 0/200
OPT-09 weights, the shipped rule named on 200/200
POSITIVE CONTROL. Same fixture, same weights, same 125 W share, one legitimate
fact changed: a pack at its own 10 % cut-out is named on 0/200 (account() still
gates it), and a unit delivering HALF its share is named on 0/200.
N=1 BYTE-IDENTICAL, asserted: `plan()` handed a `weights` mapping that raises on
any read still answers identically at a roster of one, and the same mapping
raises at a roster of two; `delinquent()` answers {} on all 84 single-unit
(share, measured, rule) combinations including 0 of 125 W.
MUTATION, run on fresh :ro trees: M12 (drop the relative arm), M13 (frac -> 1.0)
and M14 (frac -> 0.05) are all red on named checks. The constant cannot move in
either direction unseen.
⚠️ CFG-07 gets ONE CONTROL CYCLE WORSE and is deliberately not fixed here: the
worst legitimate episode goes 35.0 -> 40.0 s, so the schema's `int(30,900)`
false-tripping band widens from [30,35] to [30,40]. CFG-07 should be re-derived
against 40.0 s.
No option value, no schema bound and no default changed. 27/27 suites green.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01BwRLw7eKYj2byVdwB6kbjU
stated the wrong mechanism
⚠️ REVIEW FINDING, BLOCKING, AND IT IS THE EVIDENCE THAT WAS WRONG RATHER THAN
THE BEHAVIOUR. Part 8b's cut-out arm claimed an "identical power trace" to the
wedged arm and that "what separates them is `account()`". EVERY PART OF THAT WAS
FALSE, and the check survived deleting the gate it named. Measured:
cut-out arm, account() live named 0/200, distinct B shares: [0]
cut-out arm, account() FORCED None named 0/200, distinct B shares: [0]
wedged arm, account() live named 200/200, shares 77/125/133/154 W
At its own cut-out the pack's usable energy ABOVE that cut-out is zero, so
`weights()` answers 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. Nothing was identical, "100 % of the ask" was 0/0, and the arm
never reached the comparison it was written to grade.
WHAT REPLACES IT IS A BETTER FACT, NOT A WEAKER ONE: 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. So the arm
is kept and re-pointed, not deleted:
* the 0 W share is now ASSERTED (`_sat_last[1][Bee] == 0`), not inferred from
the silence - a control that cannot say WHY it is quiet cannot fail;
* the arm runs a SECOND time with `account()` DELETED (`no_account=True`) and
must still be silent, which is what proves which mechanism does the work;
* the account gate's claim is re-pointed at test_delivery.py part 1, where it
is graded on a REAL positive 125 W share.
⚠️ AND IT WAS INVISIBLE FOR ONE REASON WORTH KEEPING: that 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 the part prints them now. The derated control's
vacuity guard also 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.
ALSO, from the same review:
N1 app/delivery.py said 0.05 was "twelve times more sensitive" than 0.85.
0.85/0.05 = 17 and no reading of the pair gives 12. An unsupported number
in shipped source; replaced with what was actually measured.
N2 M14's recorded count was 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. It under-claimed, so it never inflated the evidence, but a recorded
figure that does not reproduce is still one.
N3 test_delivery.py part 1 printed the alarm sentence with a bare
`delinquent(...)["b"]`, which raises KeyError under M12/M13 and ABORTED
THE FILE AT PART 1, leaving parts 2-8 ungraded. The direction is safe (an
abort is a red; MUTATION.md's defect fabricates only greens) but the
recorded coverage read smaller than the truth. It is a `.get` now, and
M12/M13's counts are re-run: 7 and 7 named checks, not 5 and 6.
CFG-07: the assessment is unchanged (worse by one control cycle, 35.0 -> 40.0 s,
deliberately not fixed here) and now says WHEN it has to close - BEFORE INVERTER
B IS COMMISSIONED (~2026-09-12), because the band is unreachable at N=1 and
commissioning B is when it first becomes reachable - and that CFG-07 HAS NO
DECISION DOCUMENT IN THIS TREE, so whoever takes it writes one first.
No behaviour change. `delinquent()`'s two arms, the fraction, `min_w` and the
N=1 path are all untouched by this commit. 27/27 suites green.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01BwRLw7eKYj2byVdwB6kbjU
Review's remaining non-blocking finding, and it is B1's shape one level down -
in the fix for B1.
`wedged_loop`'s `no_account=True` was used in exactly ONE place: the cut-out
fixture, where it PROVABLY cannot change the answer, because a pack at its own
cut-out is never asked and the gate is never reached. Review neutered the switch
so it removed nothing, and the file stayed GREEN while printing
...named=(nobody); with account() DELETED: 0/200
with `account()` not deleted. A line asserting a mechanism that did not happen.
⭐ THE SWITCH DOES BITE, ON A FIXTURE THIS HELPER COULD ALREADY REACH. At the
same cut-out with EQUAL weights, `plan()` hands B a 50/50 share, so the account
gate is the only thing keeping it silent. Measured:
cut-out, OPT-09 weights gate on 0/200 gate DELETED 0/200
cut-out, EQUAL weights gate on 0/200 gate DELETED 200/200
Asserted. Driven: neutering the switch now goes RED on exactly that check, and
nothing else.
Two things this buys beyond closing the finding. It proves the switch removes
the gate, so the printed "with account() DELETED" line is about a run in which
something was. And it gives part 8b the end-to-end account-gate control ON A
POSITIVE SHARE that the block previously had to outsource to test_delivery.py
part 1 - the arm is no longer only true, it is locally demonstrated.
Suite: 27 files, all pass.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01BwRLw7eKYj2byVdwB6kbjU
admin
merged commit 37dd0f00cc into release/1.02026-09-08 05:56:45 +02:00
Blocking a user prevents them from interacting with repositories, such as opening or commenting on pull requests or issues. Learn more about blocking a user.
The defect
delivery.delinquent()named a unit whoseshort_by()gap exceeded a flatmin_w = Tuning.saturation_w = 500 W. OPT-09's SoC-aware weights shrink alow-headroom unit's share, and shrinking the share shrinks the gap — so a unit
standing at +125 W and delivering 0 W, 100 % delinquent, was never named.
Measured end to end on the real loop (
test_packshare.pypart 8b: realcompute(), realplan(), realpackshare.weights(), realaccount(), realdelinquent(); B wedged at a healthy 15 % against its own 10 % cut-out, so noenvelope closes and nothing explains the shortfall — a SAFETY-42 true
positive by that card's own definition):
⚠️ The suppressed regime is the quiet one. At a load the healthy sibling
covers, the meter is satisfied,
unmet_wis 0 and no action-log line fires, sothis alarm is the only instrument that would have told the operator the site
was running one inverter.
The fix
⚠️
min_wWAS NOT LOWERED, and that is the larger half of this card. Itexists to stop normal saturation being reported as delinquency; lowering it
trades a missed alarm for a false one on every unit at once — SAFETY-41's
four-attempt regime, "i'm getting really annoyed by the notifications in my
HA". This adds a second way to be named:
test_delivery.pypart 1's existingdelinquent()fixturesanswer identically under SAFETY-42's rule and the shipped one;
weights) and 6500 W (OPT-09's), and part 8b still asserts both numbers.
⭐ Deriving the fraction — 0.85
admin/goodwe:sim/delivery_window.py(the harness TEST-21 committed) gained a--fractionsgrading axis: the same 2640 no-fault runs at N=2 and 2640 atN=1 that produced
delivery_hold_s's 35.0 s floor, graded at the shippedmin_wfor each candidate fraction, on every cycle of every run.Worst continuous legitimate episode, worst of the three families:
one control cycle (5.0 s); below 0.45 it rises gradually to 90.0 s at
0.05. A reviewer asking "why not 0.90?" is asking about a difference this
campaign cannot resolve, and the record says so.
§3.3's own mechanism (c): a more sensitive rule puts more units into the
short set, which can turn a proper subset into the whole roster and end the
episode.
Flapping: 0.0 s at every fraction, all 840 runs.
⚠️ "Zero false namings" is not achievable at any fraction
The card asked for the largest fraction with zero false namings. There is
none — every fraction adds naming cycles (reversals 460 → 840 runs naming). A
relative arm that never fired on a legitimate transient is one that never fires:
the modelled write stagger lands B's number up to four cycles late.
What is zero at every fraction is false alarms: the longest legitimate
episode in the whole sweep is 90.0 s against a 185 s hold, so nothing in
2640 no-fault runs comes within 95 s of notifying anybody — 145 s of
slack at the shipped 0.85.
delivery_hold_sgoes from 5.29× to 4.62× theworst legitimate episode and is not changed.
The bounds 0.85 answers to
is missed; the 0.15 covers a wedged box reporting a standby figure rather than
a clean zero;
⭐ DRIVEN: the pin inverted
Part 8b pinned the suppressed behaviour and said "if it ever goes red
because the alarm fired, read the card that made it fire before 'fixing' this
line". This is that card. It now grades both rules on one run —
share_frac=Noneis SAFETY-42's rule exactly — so the red and the green are inone output rather than in two commits:
The equal arm gains exactly one cycle — the first, where the slew limit holds
the split at 500/500 and a 500 W gap is not over a 500 W threshold.
Positive control — what it must still NOT say
⚠️ Corrected in review — the cut-out row does NOT grade
account()The first version of this table said the cut-out row had an "identical power
trace" to the wedged one and that
account()was what separated them. Bothwere false, and the check was vacuous. At its own cut-out the pack's usable
energy above that cut-out is zero, so
weights()answers 0.0,plan()givesit a 0 W share on all 200 cycles, it is never in
asked, andlen(asked) < 2returns{}before either arm is evaluated. Measured, bydeleting the gate the claim rested on:
(the wedged arm's four distinct shares come from re-running that loop with
per-cycle recording in review; part 8b's own line prints the last cycle, 125 W,
and asserts it.)
⚠️ The replacement fact is stronger, not weaker: at its own cut-out OPT-09
stops asking the pack at all, so the relative arm is never reached — a
second, independent protection upstream of
account(). The allocatordeclines to ask before the detector has to decline to alarm. Part 8b now
asserts the 0 W share, prints the shares on that line (it was the only line
in the part that did not —
inverter-b+0would have been visible from the firstrun), and re-runs the arm with
account()deleted to show which mechanism doesthe work. 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 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.pypart 1 ("THE ACCOUNT GATE IS UNTOUCHED BY IT"). That partalso carries that the relative bound is strict and that the proper-subset
rule still refuses a site-wide cause.
N=1 byte-identical, asserted not argued
plan()handed aweightsmapping that raises on any read answersidentically at a roster of one — and the same mapping raises at a roster of
two, so the tripwire is real;
delinquent()answers{}on all 84 single-unit (share, measured, rule)combinations, including 0 of 125 W.
Mutation — run, on fresh
:rotreestest_alloc/test_controlstay greensaturation_wpin goes vacuous) + 8b's derated controlThe constant cannot move in either direction unseen.
⚠️ Two of these counts were corrected in review. Part 1 printed the alarm
sentence with a bare
delinquent(...)["b"], which raisesKeyErrorunder M12/M13and aborted the file at part 1, leaving parts 2–8 ungraded — so M12 and M13
were recorded as 1 named check each in
test_delivery.pywhen they are 3 and 2.The direction is safe (an abort is a red; MUTATION.md's defect fabricates only
greens), but a figure that does not reproduce is a figure that does not
reproduce. It is a
.getnow. M14 was recorded as 4 and is 5 — part 1'spre-existing "a shortfall AT the threshold is not one" also goes red.
⚠️ CFG-07 — worse by one control cycle, deliberately not fixed here
delivery_hold_sis declaredint(30,900)while the measured legitimate worstwas 35.0 s; with the relative arm it is 40.0 s, so the band of
schema-legal but false-tripping values widens from
[30, 35]to[30, 40].CFG-07 should be re-derived against 40.0 s, not 35.0 s. Raising a schema
floor is an option-surface change with its own compatibility argument, and
folding it into a safety fix would hide it.
Scope
No option value, no schema bound, no default changed. The one
config.yamledit is a comment — the
delivery_hold_sblock described the check as "short bymore than
saturation_w", which is now half of it. The fraction is a derivedconstant, deliberately not a knob, for the reason there is no
delivery_w.DECISIONS/SAFETY-43-delinquency-relative-to-the-ask.mdcarries the full curve,the controls and the provenance of every number. OPT-09's §5 disclosure and
packshare.py's docstring are replaced by a statement of the closure, with theold measurement kept beside it.
Companion PR in
admin/goodwe(#50): the harness change that derives thefraction. ⚠️ THIS PR MERGES FIRST.
admin/goodwe'schecks.ymlfetches thisrepo's
release/1.0, never a PR ref, so until this lands there #50's newselftest arm self-skips and grades nothing. It is written to pass in that state
deliberately — a hard assert would report this repo as broken for being older
than the harness — but the order is #69, then #50.
Suite: 27/27 green. Positive control on the harness confirmed first (a
deliberately broken assert reports RED, restored clean).
🤖 Generated with Claude Code
https://claude.ai/code/session_01BwRLw7eKYj2byVdwB6kbjU
`delivery.delinquent()` named a unit whose `short_by()` gap exceeded an ABSOLUTE `min_w = Tuning.saturation_w = 500 W`. OPT-09's SoC-aware weights shrink a low-headroom unit's share, and shrinking the share shrinks the gap, so a unit standing at +125 W and delivering 0 W - 100 % delinquent - was never named. Measured end to end on the real loop (test_packshare.py part 8b): load 1500 W, B wedged at 15 %, equal weights named on 199/200 cycles load 1500 W, B wedged at 15 %, OPT-09 weights named on 0/200 cycles ⚠️ The suppressed regime is the quiet one: at a load the healthy sibling covers, the meter is satisfied, `unmet_w` is 0 and no action-log line fires, so this alarm is the ONLY instrument that would have told the operator. WHAT CHANGED, in one line: named if short_by() > min_w OR short_by() > frac * share ⚠️ `min_w` WAS NOT LOWERED. It exists to stop normal saturation being reported as delinquency, and lowering it trades a missed alarm for a false one on every unit at once - SAFETY-41's four-attempt regime. This is a SECOND way to be named, not a looser first one: all seven of test_delivery.py part 1's existing fixtures answer identically under both rules, and the absolute arm's suppression window is still exactly 1000 W / 6500 W, still asserted in part 8b. THE FRACTION IS DERIVED, 0.85. admin/goodwe:sim/delivery_window.py gained a `--fractions` axis and grades the constant over the SAME 2640 no-fault runs that produced `delivery_hold_s`'s 35.0 s floor. Worst continuous legitimate episode, worst of three families, twenty fractions: frac 0.05 0.10 0.15 0.20 0.25 0.30 0.35 0.40 0.45 0.50 worst 90.0 90.0 70.0 70.0 60.0 55.0 55.0 60.0 45.0 45.0 s frac 0.55 0.60 0.65 0.70 0.75 0.80 *0.85 0.90 0.95 0.99 worst 40.0 40.0 45.0 45.0 45.0 45.0 40.0 40.0 40.0 40.0 s absolute arm alone: 35.0 s (SAFETY-42 §3.3, reproduced in the same runs) ⚠️ NO CLIFF ANYWHERE: 0.45-0.99 is flat within one control cycle, and it is not monotone - §3.3's own mechanism (c). ⚠️ "Zero false namings" is NOT achievable at any fraction and the record says so; what is zero is false ALARMS - 90.0 s worst against a 185 s hold, so nothing comes within 95 s of notifying anybody. N=1 control 0.0 s at every fraction in all 2640 one-inverter runs; flapping 0.0 s in all 840. DRIVEN. Part 8b pinned the SUPPRESSED behaviour and said "if it ever goes red because the alarm fired, read the card that made it fire". It now grades BOTH rules on one run - `share_frac=None` is SAFETY-42's rule exactly: OPT-09 weights, absolute arm alone named on 0/200 OPT-09 weights, the shipped rule named on 200/200 POSITIVE CONTROL. Same fixture, same weights, same 125 W share, one legitimate fact changed: a pack at its own 10 % cut-out is named on 0/200 (account() still gates it), and a unit delivering HALF its share is named on 0/200. N=1 BYTE-IDENTICAL, asserted: `plan()` handed a `weights` mapping that raises on any read still answers identically at a roster of one, and the same mapping raises at a roster of two; `delinquent()` answers {} on all 84 single-unit (share, measured, rule) combinations including 0 of 125 W. MUTATION, run on fresh :ro trees: M12 (drop the relative arm), M13 (frac -> 1.0) and M14 (frac -> 0.05) are all red on named checks. The constant cannot move in either direction unseen. ⚠️ CFG-07 gets ONE CONTROL CYCLE WORSE and is deliberately not fixed here: the worst legitimate episode goes 35.0 -> 40.0 s, so the schema's `int(30,900)` false-tripping band widens from [30,35] to [30,40]. CFG-07 should be re-derived against 40.0 s. No option value, no schema bound and no default changed. 27/27 suites green. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01BwRLw7eKYj2byVdwB6kbjUno_accountswitch was graded by nothingReview's remaining non-blocking finding, and it is B1's shape one level down - in the fix for B1. `wedged_loop`'s `no_account=True` was used in exactly ONE place: the cut-out fixture, where it PROVABLY cannot change the answer, because a pack at its own cut-out is never asked and the gate is never reached. Review neutered the switch so it removed nothing, and the file stayed GREEN while printing ...named=(nobody); with account() DELETED: 0/200 with `account()` not deleted. A line asserting a mechanism that did not happen. ⭐ THE SWITCH DOES BITE, ON A FIXTURE THIS HELPER COULD ALREADY REACH. At the same cut-out with EQUAL weights, `plan()` hands B a 50/50 share, so the account gate is the only thing keeping it silent. Measured: cut-out, OPT-09 weights gate on 0/200 gate DELETED 0/200 cut-out, EQUAL weights gate on 0/200 gate DELETED 200/200 Asserted. Driven: neutering the switch now goes RED on exactly that check, and nothing else. Two things this buys beyond closing the finding. It proves the switch removes the gate, so the printed "with account() DELETED" line is about a run in which something was. And it gives part 8b the end-to-end account-gate control ON A POSITIVE SHARE that the block previously had to outsource to test_delivery.py part 1 - the arm is no longer only true, it is locally demonstrated. Suite: 27 files, all pass. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01BwRLw7eKYj2byVdwB6kbjU