SAFETY-32 fix round: grade the reduction on packs whose floors DIFFER

AC 6 was not met for the reduction main.py actually hands decide(). The
reviewer removed the per-pack grading twice and the 19-file suite stayed green
both times. No shipped behaviour changes here - app/ is untouched. What changes
is what observes it.

WHY BOTH SURVIVED, and it is this repository's recurring defect landing on this
card's own Decision 2: under any rule-8-valid config every pack's
pack_floor_pct() equals peak_soc_floor, so `floors` is a list of IDENTICAL
numbers and max/min/first/last are four spellings of one answer. The only check
using a cut-out ABOVE the EMS floor - 12c's `_n1_deep` - ran on a roster of ONE,
where every reduction agrees. So no check ever evaluated binding_soc_floor() on
two packs whose floors differ. And the degeneracy is not a defence: this PR's own
argument ("unreachable is a claim about today's rule ordering, and
validate_startup_config() is also sim/inject.py's entry point") justifies writing
the reduction and equally obliges grading it.

  * test_peakguard.py part 12c2 - NEW. binding_soc_floor() on a roster whose
    per-pack floors ALL DIFFER: four SIMULATED cut-outs 30/25/40/35 %, each
    strictly above peak_soc_floor, so max (40), min (25), first (30), last (35)
    and the mean (32.5) are five different numbers and the extremes sit at
    INTERIOR roster positions. Two packs structurally cannot separate those -
    there max==last and min==first - and neither can three; four is the smallest
    roster that can. Precondition is its own check (habit 1); the counterfactual
    raises ONE pack - the last, neither extreme - past the old maximum and the
    answer follows (habit 7); peak_soc_floor is then lifted above every cut-out
    to grade the other side of the conjunction.
  * test_peakguard.py part 12g - REWRITTEN as behaviour (habit 4). The old
    assertion was `"self.packs" in <the unparsed call site>`, which `self.packs[:1]`
    still satisfies. It now drives REAL Controller.cycle()s on a two-pack roster,
    both packs at the same SoC, and reads PeakDecision.soc_floor - the argument,
    echoed back by the shipped decide(). The cut-outs are the only thing varied,
    and the SAME PAIR is carried in BOTH ORDERS.
  * ⚠️ TWO MORE SURVIVORS, found by this round's own battery and recorded rather
    than quietly repaired. (a) The first cut of 12g varied only pack B's cut-out,
    so `self.packs[-1:]` (+5 bytes) agreed with the roster on both runs and stayed
    green across all 19 files; the swapped pair closes it, and between the two
    directions no single-position slice passes all three runs. (b)
    binding_soc_floor()'s EMPTY-roster branch rewritten to `return None`
    (-43 bytes) was green too - a defensive branch nothing in the suite reached.
    Both directions of it are pinned now.
  * wired_over_limit() gained a prepare(ctl) hook, inside its retry loop so every
    attempt grades the same site.
  * In-process mutation rows 22, 22b and 23 record all four survivors.

Nine further source mutations went through the harness on the fixed tree
(binding_soc_floor -> floors[0] / floors[-1], pack_floor_pct conjoining with
min, pack_permissions grading against packs[0], `any` -> `all` on the unknown
floor, Controller.packs reversed, decide(soc=) taking inverters[0].soc, and the
two survivors above). Seven were red on first run; the two survivors are now red
as well. Three of the nine have a ZERO byte delta and still went red, which is
the direction stale bytecode cannot fabricate - and the harness purged anyway.

MANDATORY PROOF, all in the CI image over a tree rsynced to a plain path and
bind-mounted :ro, bytecode entry count printed before and after the purge:
each of the four mutations now takes test_peakguard.py RED, and the unmutated
tree is 19/19 green (twice, plus test_peakguard.py five times in isolation -
card CI-06's flake did not reappear). The zero-byte one was proved to have RUN rather than
assumed: dis.get_instructions LOAD_GLOBALs were [float, pack_floor_pct, any,
min] and binding_soc_floor() returned 25.0 on the 12c2 roster where the shipped
code returns 40.0.

No measurement of inverter B appears anywhere. It does not physically exist.
Every second-pack and fourth-pack figure added here is SIMULATED and labelled at
its definition; only inverter A's 10 % is read off hardware. No hardware was
touched.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01BwRLw7eKYj2byVdwB6kbjU
This commit is contained in:
glenn schrooyen
2026-09-04 21:42:07 +02:00
co-authored by Claude Opus 5
parent 041ec0a61b
commit 619b218110
3 changed files with 493 additions and 10 deletions
+338 -10
View File
@@ -1063,9 +1063,15 @@ check("...and the status page says NOT COVERED rather than 'idle' or a green "
# Controller rather than left to flake. It is bounded at three attempts: a fourth
# would mean something is wrong that is not a boundary.
def wired_over_limit(db, want_floor_w, opts=None, store=None, batt_w=0.0,
standing_w=None, soc=55.0):
standing_w=None, soc=55.0, prepare=None):
"""A real Controller driven one real cycle over a real over-limit quarter.
`prepare(ctl)` runs after the Controller is built and before the telegrams
are fed, which is the only window in which a SECOND inverter can be put on
the roster and given its own readings. It is inside the retry loop on
purpose: each attempt builds a fresh Controller, so a hook that mutated only
the first one would leave attempts 2-4 grading a different site.
⚠️ THE LOAD IS DERIVED FROM WHERE IN THE QUARTER THE WALL CLOCK LANDS, and
it has to be. `excess = 900 × (projected − ceiling) ÷ remaining`, so a fixed
5200 W fixture asks for 1700 W with ten minutes left and 300 kW with five
@@ -1079,6 +1085,8 @@ def wired_over_limit(db, want_floor_w, opts=None, store=None, batt_w=0.0,
store=_Store(store) if store is not None else None)
ctl.auto, ctl.soc, ctl.batt = True, soc, batt_w
ctl.dev_min, ctl.dev_max = -LIVE_MAX_W, LIVE_MAX_W
if prepare is not None:
prepare(ctl)
if standing_w is not None:
# The command STANDING ON THE WIRE, which is what B3 below needs to
# differ from the measured battery power.
@@ -3291,6 +3299,130 @@ check("...and on the pair rule 8 REFUSES - a cut-out above the EMS floor - the "
"would be satisfied by `soc_floor` typed straight through",
_n1_deep == B_PACK_FLOOR_DEEP_SIM and _n1_deep != SOC_FLOOR)
# --- 12c2. THE REDUCTION ITSELF, ON A ROSTER WHOSE FLOORS ALL DIFFER ---------
# ⚠️ THIS IS THE CHECK PR #48 DID NOT HAVE, AND ITS ABSENCE IS THIS REPOSITORY'S
# RECURRING DEFECT LANDING ON THIS CARD. Every other fixture above grades
# `binding_soc_floor()` on a roster of ONE (12c) or on a config rule 8 accepts,
# where `pack_floor_pct()` answers `peak_soc_floor` for EVERY pack - so `floors`
# is a list of IDENTICAL numbers and `max`, `min`, `floors[0]` and `floors[-1]`
# are four spellings of one answer. A reviewer changed `max(floors)` to
# `min(floors)` and all 19 files stayed GREEN. The data could not reach the
# failure the check names.
#
# ⚠️ AND THE DEGENERACY IS NOT A DEFENCE, BY THIS CARD'S OWN ARGUMENT.
# `pack_floor_pct()`'s docstring, main.py's call-site comment and DECISIONS §4
# all say "unreachable is a claim about today's rule ordering, not a property of
# this function, and `validate_startup_config()` is also `sim/inject.py`'s entry
# point". That argument justifies WRITING the reduction; it equally OBLIGES
# grading it. Via `sim/inject.py`, which does not run rule 8 at all, `min` here
# lets the guard command a forced discharge down to 20 % on a pack whose BMS
# cuts out at 35 %. So the reduction is graded on a roster rule 8 would refuse -
# deliberately, because that is the only roster on which it does anything.
#
# ⚠️ THE FOUR NUMBERS, AND WHY THESE FOUR. Every one is ABOVE `peak_soc_floor`,
# so `pack_floor_pct()` selects the CUT-OUT for each and `floors` IS this tuple
# in this order. Read as a list, the four candidate reductions are four
# DIFFERENT numbers:
#
# floors = (30, 25, 40, 35)
# max(floors) = 40 <- the shipped answer, the deepest cut-out
# min(floors) = 25
# floors[0] = 30 <- "grade the site against pack A", survivor 2's
# defect expressed inside the function
# floors[-1] = 35
# mean = 32.5
#
# so no two of them can be confused, and the extremes sit at INTERIOR roster
# positions (index 2 is the max, index 1 the min) - which is what a two-pack
# fixture structurally cannot do, since there `max` and `last` coincide and so
# do `min` and `first`. Three packs cannot do it either. Four is the smallest
# roster that separates all four.
#
# ⚠️ ALL FOUR ARE SIMULATED. There is ONE pack on this site; inverter B is ~8
# days out and does not physically exist, and a roster of four certainly does
# not. Nothing here is a measurement of anything. `binding_soc_floor()` is a
# pure function over a list and these are the inputs that make its answer
# observable - the only measured cut-out in this file is inverter A's 10 %.
_MANY_FLOORS_SIM = (30.0, 25.0, 40.0, 35.0)
_many_packs = [Pack(f"sim-{i}", 50.0, f) for i, f in enumerate(_MANY_FLOORS_SIM)]
_many_derived = [pack_floor_pct(pk, SOC_FLOOR) for pk in _many_packs]
_many_answers = {"max": max(_MANY_FLOORS_SIM), "min": min(_MANY_FLOORS_SIM),
"first": _MANY_FLOORS_SIM[0], "last": _MANY_FLOORS_SIM[-1],
"mean": sum(_MANY_FLOORS_SIM) / len(_MANY_FLOORS_SIM)}
print(f" a SIMULATED roster of {len(_many_packs)} with cut-outs "
f"{[f'{f:.0f}' for f in _MANY_FLOORS_SIM]} % over peak_soc_floor "
f"{SOC_FLOOR:.0f} % -> per-pack floors {[f'{f:.0f}' for f in _many_derived]} %")
print(" candidate reductions: "
+ ", ".join(f"{k}={v:g}" for k, v in _many_answers.items())
+ f"; binding_soc_floor() -> {binding_soc_floor(_many_packs, SOC_FLOOR):g}")
check("PRECONDITION (MUTATION.md habit 1): on this roster max, min, first, last "
"and the mean are FIVE DIFFERENT numbers, and every cut-out is strictly "
"above peak_soc_floor so the per-pack floors ARE the cut-outs. A later "
"edit that makes any two of them equal takes this line red rather than "
"leaving the claim below quietly vacuous - which is exactly what a "
"rule-8-valid roster does to it",
len(set(_many_answers.values())) == 5
and all(f > SOC_FLOOR for f in _MANY_FLOORS_SIM)
and _many_derived == list(_MANY_FLOORS_SIM))
check("⚠️ `binding_soc_floor()` answers the MAXIMUM of the packs' own floors - "
"the DEEPEST cut-out on the roster - and on this roster that is not the "
"minimum, not the first pack's, not the last pack's and not the mean. "
"This is the conservative pairing with the MINIMUM in `pack_floor_soc`: "
"`min(soc) <= max(floor)` is implied by 'some pack is at or below its own "
"floor', so the site verdict is never more permissive than grading each "
"pack separately. `min(floors)` here would let a forced discharge be "
"sized down to 25 % on the pack whose BMS cuts out at 40 %",
binding_soc_floor(_many_packs, SOC_FLOOR) == _many_answers["max"]
and binding_soc_floor(_many_packs, SOC_FLOOR) != _many_answers["min"]
and binding_soc_floor(_many_packs, SOC_FLOOR) != _many_answers["first"]
and binding_soc_floor(_many_packs, SOC_FLOOR) != _many_answers["last"]
and binding_soc_floor(_many_packs, SOC_FLOOR) != _many_answers["mean"])
# ⚠️ THE COUNTERFACTUAL, ONE THING VARIED FROM AN ACCEPTED BASELINE (habit 7).
# The pack that is raised is the LAST one, which is neither the max nor the min
# above - so this line can only move if the reduction really looked at it. It is
# raised past the old maximum, and the answer follows it.
_deeper = list(_many_packs)
_deeper[-1] = Pack("sim-3", 50.0, 45.0)
print(f" ...raise ONLY the last pack 35 % -> 45 %: "
f"{binding_soc_floor(_many_packs, SOC_FLOOR):g} -> "
f"{binding_soc_floor(_deeper, SOC_FLOOR):g}")
check("...and the counterfactual: raise ONE pack - the LAST, which was neither "
"the deepest nor the shallowest - past the old deepest, and the answer "
"follows it to 45 %. So the reduction reads every entry, and the 40 % "
"above was not a coincidence of position",
binding_soc_floor(_deeper, SOC_FLOOR) == 45.0
and binding_soc_floor(_many_packs, SOC_FLOOR) == 40.0)
# ...and the EMS floor is still the other half of the conjunction: lift it above
# every cut-out on the roster and it wins for all of them.
_over = SOC_FLOOR + 40.0
check("...and with `peak_soc_floor` lifted above every cut-out on this roster "
"the answer is the OPTION, for all four - `pack_floor_pct()` is a "
"conjunction and this is its other side, so a reduction that dropped the "
"EMS floor entirely goes red here as well as in the N=1 sweep",
_over > max(_MANY_FLOORS_SIM)
and binding_soc_floor(_many_packs, _over) == float(_over))
# ...and the EMPTY roster, the SECOND thing this fix round's own battery found
# unguarded: `return None` in place of `float(soc_floor)` there (-43 bytes) was
# GREEN across all 19 files. It is a defensive branch - `Controller.inverters` is never
# empty on a started controller, and `inputs_ok` refuses the cycle before the
# guard is reached if it were - so nothing in the suite went near it. Pinned
# rather than argued, because a branch with no check is a branch that can be
# rewritten under a green suite, and BOTH directions of it are asserted: the
# option when there is one, and None when there is not.
print(f" an EMPTY roster: binding_soc_floor([], {SOC_FLOOR:.0f}) -> "
f"{binding_soc_floor([], SOC_FLOOR)}, binding_soc_floor([], None) -> "
f"{binding_soc_floor([], None)}")
check("an EMPTY roster answers the OPTION - there is no pack to conjoin with, "
"so there is nothing to raise the floor above it - and answers None when "
"the option itself is None. ⚠️ AND IT CANNOT PERMIT ANYTHING EITHER WAY: "
"`Controller.pack_floor_soc` is None at an empty roster, and "
"`discharge_permitted()` refuses on a None SoC whatever the floor is",
binding_soc_floor([], SOC_FLOOR) == float(SOC_FLOOR)
and binding_soc_floor([], None) is None
and discharge_permitted(None, binding_soc_floor([], SOC_FLOOR))
== FLOOR_SOC_UNREADABLE)
# --- 12d. AC 4: pack_floor_soc's None-on-missing is untouched ---------------
_c32, _h32 = built(TMP / "s32.db")
_b32, _restore32 = second_inverter(_c32)
@@ -3436,17 +3568,147 @@ check("...and with the key absent entirely the one pack takes the SHIPPED "
and BMS_FLOOR == PEAK_OPTION_DEFAULTS["bms_soc_floor"])
# --- 12g. the call site: main.py hands decide() the per-pack reduction -------
# ⚠️ REWRITTEN. THIS CHECK USED TO BE A SUBSTRING TEST OVER main.py's SOURCE -
# `"self.packs" in _floor_call` - AND IT WAS NOT A PIN. The mutation that grades
# the whole site against pack A's floor is `self.packs[:1]`, which still
# CONTAINS that substring: +4 bytes, all 19 files green, including this one.
# MUTATION.md habit 4, in the same costume CFG-04's `if entity:` wore: the check
# asserted against the TEXT of the thing under test instead of its behaviour.
# The AST is still unparsed and PRINTED (habit 3) because a reader wants to see
# the expression, but nothing below asserts on its spelling. Which OPTION KEY
# the floor comes from is a claim genuinely about the code's shape and is pinned
# on the source in part 4, where it already lives; what is graded here is the
# VALUE that reaches `decide()`.
_floor_call = ast.unparse(next(k.value for k in _call.keywords
if k.arg == "soc_floor"))
print(f" main.py's decide(soc_floor=...) is `{_floor_call}`")
check("main.py hands `decide()` the PER-PACK reduction of `peak_soc_floor`, "
"not the bare option: `binding_soc_floor(self.packs, ...)`, so the floor "
"the site is graded against can never sit below the deepest cut-out on "
"the roster. The key and the one defaults mirror are still in that "
"expression - graded three parts above - because this card moved the "
"REDUCTION and not the source",
"binding_soc_floor" in _floor_call and "self.packs" in _floor_call
and '"peak_soc_floor"' in _floor_call.replace("'", '"'))
def _floor_reaching_decide(tag, a_floor, b_floor, peak_floor=None):
"""Drive ONE REAL `Controller.cycle()` on a TWO-pack roster and report the
floor `peakguard.decide()` was actually handed, read back off the decision
main.py itself filed (`PeakDecision.soc_floor` is the argument, echoed).
⚠️ NOT A SPY AND NOT A GREP. The shipped `cycle()` runs, the shipped
`binding_soc_floor()` runs, and the observable is a field of the decision
the controller stored - so the whole path from `Controller.inverters` to the
guard's argument is under test. Both packs are held at the SAME SoC and the
same everything else; the only things that vary between calls are the packs'
own cut-outs.
"""
opts = {} if peak_floor is None else {"peak_soc_floor": peak_floor}
def _prep(ctl):
second_inverter(ctl)
for inv, fl in zip(ctl.inverters, (a_floor, b_floor)):
inv.soc, inv.batt, inv.bms_soc_floor = SOC_BETWEEN, 0.0, fl
ctl, hs, _net, _rem = wired_over_limit(
TMP / f"s32g_{tag}.db", LIVE_MAX_W * 0.3, opts=opts, prepare=_prep)
return ctl, ctl.peak_guard
# BASELINE: neither cut-out is above the EMS floor, so the conjunction selects
# the option for both packs and the site floor is `peak_soc_floor`. At
# SOC_BETWEEN (5 points above it) the guard is permitted and sizes a real
# discharge. Both runs below vary one thing from THIS baseline (habit 7).
_g_ctl_shallow, _g_shallow = _floor_reaching_decide(
"shallow", A_PACK_FLOOR, B_PACK_FLOOR_SIM)
# The SECOND pack's cut-out moves above the EMS floor. Nothing else changes -
# not pack A, not either SoC, not the option.
_g_ctl_deep, _g_deep = _floor_reaching_decide(
"deepb", A_PACK_FLOOR, B_PACK_FLOOR_DEEP_SIM)
# ⚠️ AND THE SAME TWO CUT-OUTS SWAPPED BETWEEN THE PACKS, which is the mirror
# 12h already runs on the SoC axis and which THIS part needed and did not have.
# Without it, `self.packs[-1:]` - grade the site against the LAST pack - answers
# the same two numbers as the full roster on the two runs above, because pack A
# is never the deeper one there. It SURVIVED the first cut of this fix round,
# +5 bytes, all 19 files green. With the pair swapped, `[:1]` and `[-1:]`
# disagree with the roster in opposite runs, and no single-position slice is
# left that can pass all three.
_g_ctl_deepa, _g_deepa = _floor_reaching_decide(
"deepa", B_PACK_FLOOR_DEEP_SIM, B_PACK_FLOOR_SIM)
print(f" REAL two-pack cycles, both packs at {SOC_BETWEEN:.0f} %, "
f"peak_soc_floor {SOC_FLOOR:.0f} % (every cut-out but inverter-a's own "
f"{A_PACK_FLOOR:.0f} % is SIMULATED):")
print(f" cut-outs A {A_PACK_FLOOR:.0f} / B {B_PACK_FLOOR_SIM:.0f} % -> "
f"decide() got soc_floor={_g_shallow.soc_floor:g} %, floor_limited="
f"{_g_shallow.floor_limited}")
print(f" cut-outs A {A_PACK_FLOOR:.0f} / B {B_PACK_FLOOR_DEEP_SIM:.0f} % -> "
f"decide() got soc_floor={_g_deep.soc_floor:g} %, floor_limited="
f"{_g_deep.floor_limited}")
print(f" ...the SAME PAIR SWAPPED, A {B_PACK_FLOOR_DEEP_SIM:.0f} / B "
f"{B_PACK_FLOOR_SIM:.0f} % -> decide() got "
f"soc_floor={_g_deepa.soc_floor:g} %, floor_limited="
f"{_g_deepa.floor_limited}")
check("⚠️ THE CALL-SITE PIN, AS BEHAVIOUR. Change the cut-out of a NON-FIRST "
"pack and the floor that reaches `decide()` MOVES with it: 20 % (the "
"option, because B's cut-out is under it) becomes 35 % (B's own cut-out, "
"because it is over it). A call site that graded the site against "
"`self.packs[:1]` - pack A alone - answers 20 % both times and cannot "
"produce this difference, and neither can `min(floors)`; that is the "
"+4-byte mutation that walked through the substring test this check "
"replaces",
_g_shallow.soc_floor == float(SOC_FLOOR)
and _g_deep.soc_floor == float(B_PACK_FLOOR_DEEP_SIM)
and _g_deep.soc_floor != _g_shallow.soc_floor)
check("⚠️ ...AND THE SAME PAIR SWAPPED GIVES THE SAME SITE FLOOR, so what is "
"reduced is the ROSTER and not a POSITION in it. `self.packs[-1:]` - the "
"LAST pack alone - agrees with the roster on both runs above and answers "
"20 % here, where the deeper cut-out sits on the FIRST pack. That "
"mutation SURVIVED the first cut of this fix round; this is the line "
"that closes it, and between them the two directions leave no "
"single-position slice that can pass all three runs",
_g_deepa.soc_floor == float(B_PACK_FLOOR_DEEP_SIM)
and _g_deepa.soc_floor == _g_deep.soc_floor
and _g_deepa.soc_floor != _g_shallow.soc_floor
and [pk.bms_floor for pk in _g_ctl_deepa.packs]
== [B_PACK_FLOOR_DEEP_SIM, B_PACK_FLOOR_SIM])
check("...and it is not just a number in a report - THE SITE'S VERDICT FLIPS. "
"With both packs at 25 % the shallow site is permitted and the guard "
"sizes a positive forced discharge; BOTH deep sites are FLOOR-LIMITED, "
"because 25 % is at or below the 35 % cut-out wherever on the roster it "
"sits. Grading the roster against one position would spend a pack its "
"BMS stops - through `sim/inject.py`, which does not run rule 8 - and "
"this line is what goes red when it does",
_g_shallow.floor_limited is False and _g_shallow.floor_w > 0.0
and _g_deep.floor_limited is True and _g_deep.floor_w == 0.0
and _g_deep.soc_floor_reason == FLOOR_AT_SOC_FLOOR
and _g_deepa.floor_limited is True and _g_deepa.floor_w == 0.0
and _g_deepa.soc_floor_reason == FLOOR_AT_SOC_FLOOR)
check("...and the precondition that makes the three runs comparable (habit 1): "
"the two deep runs carry THE SAME PAIR of cut-outs in opposite orders, "
"those two numbers really are different, and all six packs are at the "
"SAME state of charge - so neither the SoC reduction nor a roster "
"position can be what separated the answers",
B_PACK_FLOOR_SIM != B_PACK_FLOOR_DEEP_SIM
and A_PACK_FLOOR != B_PACK_FLOOR_DEEP_SIM
and sorted(pk.bms_floor for pk in _g_ctl_deepa.packs)
== sorted([B_PACK_FLOOR_SIM, B_PACK_FLOOR_DEEP_SIM])
and [pk.soc for pk in _g_ctl_deep.packs] == [SOC_BETWEEN, SOC_BETWEEN]
and [pk.soc for pk in _g_ctl_deepa.packs] == [SOC_BETWEEN, SOC_BETWEEN]
and [pk.bms_floor for pk in _g_ctl_deep.packs]
== [A_PACK_FLOOR, B_PACK_FLOOR_DEEP_SIM]
and [pk.bms_floor for pk in _g_ctl_shallow.packs]
== [A_PACK_FLOOR, B_PACK_FLOOR_SIM]
and _g_ctl_deep.pack_floor_soc == _g_ctl_shallow.pack_floor_soc
== _g_ctl_deepa.pack_floor_soc)
# ...and the OTHER half of the conjunction still reaches the same argument, so
# the reduction did not replace the source: move `peak_soc_floor` itself, with
# both cut-outs held under it, and the floor follows the OPTION.
_G_OPT_ODD = SOC_FLOOR + 22.0
_, _g_opt = _floor_reaching_decide("opt", A_PACK_FLOOR, B_PACK_FLOOR_SIM,
peak_floor=_G_OPT_ODD)
print(f" peak_soc_floor moved to {_G_OPT_ODD:.0f} % with both cut-outs "
f"under it -> decide() got soc_floor={_g_opt.soc_floor:g} %")
check("...and with both cut-outs held below it, moving `peak_soc_floor` moves "
"the floor that reaches `decide()` too - so this card moved the "
"REDUCTION and not the SOURCE. WHICH key that is, is a claim about the "
"code's shape and stays pinned on the source in part 4; that the option "
"still governs is a claim about behaviour and is graded here",
_g_opt.soc_floor == float(_G_OPT_ODD)
and _G_OPT_ODD > B_PACK_FLOOR_SIM and _G_OPT_ODD > A_PACK_FLOOR
and _g_opt.soc_floor != _g_shallow.soc_floor)
# --- 12h. the operator-facing half, driven through the shipped method -------
# ⚠️ RUN, NOT GREPPED. CFG-04's review found a substring test over main.py that
@@ -3729,6 +3991,61 @@ MUT.append(("the per-pack notification naming a fixed roster position",
and "inverter-b" not in _body32b.split("WHICH PACK")[-1],
"part 12h: the same two readings swapped between the packs"))
# ---- the two PR #48 SURVIVORS, and why they survived -------------------------
# ⚠️ BOTH OF THESE WERE APPLIED TO app/ AND ALL 19 FILES STAYED GREEN. They are
# this repository's recurring defect - a check whose DATA cannot reach the
# failure it names - landing on this card's own reduction, and they are recorded
# here as rows so that a later edit which re-degenerates the fixtures goes red
# on the row rather than on nothing.
# 22. `binding_soc_floor()` reduced with `min()` instead of `max()`. ZERO byte
# delta, and the reviewer proved by disassembly that it really ran. It
# survived because every roster in the suite was rule-8-valid or one pack
# long, so `floors` held IDENTICAL numbers and max/min/first/last were four
# spellings of one answer. 12c2's four simulated cut-outs are the data that
# reaches it.
_mut22 = [min(_MANY_FLOORS_SIM), _MANY_FLOORS_SIM[0], _MANY_FLOORS_SIM[-1],
sum(_MANY_FLOORS_SIM) / len(_MANY_FLOORS_SIM)]
MUT.append(("`binding_soc_floor()` reduced with `min()`, `first` or `last` "
"instead of `max()` - PR #48 SURVIVOR 1, zero byte delta",
binding_soc_floor(_many_packs, SOC_FLOOR) == max(_MANY_FLOORS_SIM)
and all(binding_soc_floor(_many_packs, SOC_FLOOR) != m
for m in _mut22),
"part 12c2: 'max, min, first, last and the mean are FIVE DIFFERENT "
"numbers'. ⚠️ The four cut-outs sit on a roster rule 8 would REFUSE, "
"deliberately: on one it accepts all four reductions are equal, "
"which is precisely why this mutation survived"))
# 22b. `binding_soc_floor()`'s EMPTY-roster branch rewritten to `return None`.
# -43 bytes, green across all 19 files until 12c2's last block pinned it.
# A defensive branch nothing reaches is still a branch.
MUT.append(("`binding_soc_floor([])` answering None instead of the option",
binding_soc_floor([], SOC_FLOOR) == float(SOC_FLOOR)
and binding_soc_floor([], None) is None,
"part 12c2's last block: 'an EMPTY roster answers the OPTION ... "
"and answers None when the option itself is None'"))
# 23. the CALL SITE grading the whole site against ONE ROSTER POSITION -
# `self.packs[:1]` (+4 bytes, PR #48's survivor) or `self.packs[-1:]`
# (+5 bytes, which survived the FIRST CUT OF THIS FIX ROUND until the
# swapped pair was added). 12g's old substring assertion
# (`"self.packs" in _floor_call`) passes on both, because a slice still
# contains that substring. Three runs close both directions at once: the
# deep cut-out is on the SECOND pack in one and on the FIRST in another, and
# the site floor is the same 35 % in both.
MUT.append(("main.py grading the site against ONE roster position - "
"`self.packs[:1]` (PR #48 SURVIVOR 2) or `self.packs[-1:]`",
_g_deep.soc_floor == float(B_PACK_FLOOR_DEEP_SIM)
and _g_deepa.soc_floor == float(B_PACK_FLOOR_DEEP_SIM)
and _g_shallow.soc_floor == float(SOC_FLOOR)
and _g_deep.floor_limited and _g_deepa.floor_limited
and not _g_shallow.floor_limited,
"part 12g, REWRITTEN as behaviour: real two-pack cycles, the SAME "
"pair of cut-outs carried in both orders, and both the floor "
"reaching decide() and the site's verdict follow the ROSTER rather "
"than a position. ⚠️ A substring test over main.py cannot see a "
"slice; MUTATION.md habit 4"))
for label, caught, where in MUT:
print(f" {'caught' if caught else 'NOT CAUGHT':>10} {label}")
print(f" {where}")
@@ -3748,7 +4065,18 @@ check("...and SAFETY-32's own eight defeats are each caught too - the flat "
"first pack's floor borrowed for all, the reduction dropped, an absent "
"cut-out defaulted to 0 %, rule 8 grading one unit, rule 8 naming a "
"hardwired one, and the alarm naming a position instead of a pack",
all(m[1] for m in MUT[13:21]) and len(MUT) == 21)
all(m[1] for m in MUT[13:21]))
check("...⚠️ AND SO ARE THE FOUR DEFEATS THAT SURVIVED A GREEN 19-FILE SUITE, "
"which is why this fix round exists: `min(floors)` in place of "
"`max(floors)` (zero byte delta) and `self.packs[:1]` at the call site "
"(+4 bytes), both green on d9388c8; `self.packs[-1:]` (+5 bytes), green "
"on the FIRST CUT OF THE FIX ITSELF; and the empty-roster branch "
"rewritten (-43 bytes). None of the four is a new guard - no shipped "
"behaviour changed - they are checks whose DATA could not reach the "
"failure they named, which is the defect this repository has now shipped "
"in six consecutive cards. The last two were found by this round's own "
"battery and are recorded rather than quietly repaired",
all(m[1] for m in MUT[21:24]) and len(MUT) == 24)
check("...and so is the last one, which is not a defeat at all but the EDGE OF "
"THIS CARD: the grid-following loop can still take the pack past this "
"floor, because the floor bounds the peak guard's own forced discharge "