TEST-16: pin the two one-sided arbitrage rungs, and un-mask them from each other #37

Merged
admin merged 2 commits from TEST-16 into release/1.0 2026-09-01 08:02:58 +02:00
Owner

SAFETY-26's AC4 gave the same tolerance mutation to every price and quantity
boundary in arbitrage.py and static_tariff.py. Everything in arbitrage.py went
red - price < 0, soc <= floor_pct, soc >= ceiling_pct are each red under
+/-5. Two survived, both in static_tariff.py, and this card closes them.

D spread == 0.0 (:912) weakened to spread <= 0.001 SURVIVED at +2 B.
F len(firm) < 2 (:901) weakened to len(firm) < 1 SURVIVED at +0 B - the
delta MUTATION.md names as the risky one.

THE DEFECT IS NOT EITHER ROW, IT IS THE INTERACTION. D and F MASK EACH OTHER. A
single firm hour also has a spread of 0.0, so with F weakened the flat rung
refuses the stimulus anyway; with D weakened the small-but-real spread is still
refused, only for a lie. Each rung's failure is absorbed by the other, so BOTH
can be weakened together and a suite grading kind == "refused" reports
nothing. That is structurally invisible to single-mutation testing, which is how
this pair came through four rounds of review on TARIFF-03 and FCST-03 - and it
is the arrangement in which the next edit to either rung opens a real hole with
nothing to report it.

D is not cosmetic either. With the tolerance in place a series priced 0.20000 /
0.20050 - a REAL 0.0005 EUR/kWh spread - flips ALLOWED to REFUSED at
min_spread_eur_kwh=0.0, a value arbitrage()'s own docstring documents ("pass 0.0
to mean any positive spread, explicitly") and its validator at :861 accepts on
purpose. At a shipped threshold the outcome does not move, but the operator
reads the false sentence "the tariff is flat - every one of the 2 firm hours
costs 0.2000 EUR/kWh" about a tariff that is not flat.

WHAT WAS ADDED. test_static_tariff.py section 9, and the shape of it is the
argument:

  • THE REASON IS GRADED, NOT THE VERDICT. The masked case refuses CORRECTLY
    while reporting the wrong sentence, so a check asserting only "refused"
    passes on a broken tree. A rung9() helper names which refusal answered,
    from the sentence the operator would read; an unrecognised refusal reports
    itself as UNATTRIBUTED rather than quietly matching nothing.
  • EACH RUNG IS GIVEN A STIMULUS THE OTHER CANNOT ABSORB, or the pinning is
    circular. The flat rung gets a THREE-firm-hour flat series, which no
    len(firm) < N a person would write can reach. The firm-pair rung gets a
    ONE-FIRM-HOUR series, which the flat rung CAN reach - so its attribution is
    the whole check, and that is why it is written as a rung name rather than a
    verdict.
  • AC1 is a sweep of small-but-real spreads (0.0005 down to 0.000001) all
    ALLOWED at min_spread_eur_kwh=0.0, with the exactly flat series on the other
    side still refused BY THE FLAT RUNG - without that mirror the sweep would
    also pass for a rung deleted outright. 1e-6 is the floor because the shipped
    line rounds the spread to 6 decimals; that quantisation is graded in the
    open as its own row rather than left unstated.
  • AC3 is a five-row table graded on rung attribution, which denies the masking
    from both sides at once.
  • The firm-pair count is also pinned from ABOVE (< 3) and BELOW (< 0),
    which the criteria do not ask for but which is what stops this section being
    one-sided in exactly the way it was written to fix.

EVIDENCE. Eight rounds through TEST-15's tools/mutation_run.sh, used UNCHANGED:
recursive pycache purge before each run, python3 -B, the tree re-copied FROM
DISK between rounds, the mutated line grepped out of the file before the run,
byte delta printed, test_static_tariff.py and test_arbitrage.py graded each
time. Baseline green.

baseline, shipped +0 B PASS
D1 spread == 0.0 -> <= 0.001 +2 B RED, 3 checks
D2 spread == 0.0 -> <= 0.000001 +5 B RED, AC1 alone
D3 spread == 0.0 -> < 0.0 (rung gone) +0 B RED (section 2 as well)
F1 len(firm) < 2 -> < 1 +0 B RED, 3 checks
F2 len(firm) < 2 -> < 3 +0 B RED, 6 checks
F3 len(firm) < 2 -> < 0 (rung gone) +0 B RED (ValueError)
D1+F1 BOTH AT ONCE - THE TICKET +2 B RED, 5 checks

Four of the seven are +0 B, the delta MUTATION.md names as the one stale
bytecode can hide. All are REDS, the direction that defect cannot fabricate -
but they were run under the purge anyway, because "it went red so the cache
cannot have lied" is a conclusion and not a procedure.

NO SHIPPED BEHAVIOUR CHANGED. app/ is untouched; both rungs were correct all
along, and the card is explicit that a rung found actually wrong is a stop-and-
report rather than an edit. Also updated: MUTATION.md gains a short section on
masking as a SECOND way a survivor lies, with the two rules that fall out of it
(grade the reason, and mutate suspected pairs together); and test_arbitrage.py's
SAFETY-26 AC4 note is marked closed rather than left reading as an open finding.

UNSURE ABOUT. The 5e-7 row asserts the shipped round(spread, 6) quantisation.
That is a real property of the line and worth stating, but it does pin a
rounding the ticket never named - if a reviewer would rather that stayed
unpinned, it is one check to drop and nothing else depends on it.

SAFETY-26's AC4 gave the same tolerance mutation to every price and quantity boundary in arbitrage.py and static_tariff.py. Everything in arbitrage.py went red - `price < 0`, `soc <= floor_pct`, `soc >= ceiling_pct` are each red under +/-5. Two survived, both in static_tariff.py, and this card closes them. D `spread == 0.0` (:912) weakened to `spread <= 0.001` SURVIVED at +2 B. F `len(firm) < 2` (:901) weakened to `len(firm) < 1` SURVIVED at +0 B - the delta MUTATION.md names as the risky one. THE DEFECT IS NOT EITHER ROW, IT IS THE INTERACTION. D and F MASK EACH OTHER. A single firm hour also has a spread of 0.0, so with F weakened the flat rung refuses the stimulus anyway; with D weakened the small-but-real spread is still refused, only for a lie. Each rung's failure is absorbed by the other, so BOTH can be weakened together and a suite grading `kind == "refused"` reports nothing. That is structurally invisible to single-mutation testing, which is how this pair came through four rounds of review on TARIFF-03 and FCST-03 - and it is the arrangement in which the next edit to either rung opens a real hole with nothing to report it. D is not cosmetic either. With the tolerance in place a series priced 0.20000 / 0.20050 - a REAL 0.0005 EUR/kWh spread - flips ALLOWED to REFUSED at min_spread_eur_kwh=0.0, a value arbitrage()'s own docstring documents ("pass 0.0 to mean any positive spread, explicitly") and its validator at :861 accepts on purpose. At a shipped threshold the outcome does not move, but the operator reads the false sentence "the tariff is flat - every one of the 2 firm hours costs 0.2000 EUR/kWh" about a tariff that is not flat. WHAT WAS ADDED. test_static_tariff.py section 9, and the shape of it is the argument: * THE REASON IS GRADED, NOT THE VERDICT. The masked case refuses CORRECTLY while reporting the wrong sentence, so a check asserting only "refused" passes on a broken tree. A `rung9()` helper names which refusal answered, from the sentence the operator would read; an unrecognised refusal reports itself as UNATTRIBUTED rather than quietly matching nothing. * EACH RUNG IS GIVEN A STIMULUS THE OTHER CANNOT ABSORB, or the pinning is circular. The flat rung gets a THREE-firm-hour flat series, which no `len(firm) < N` a person would write can reach. The firm-pair rung gets a ONE-FIRM-HOUR series, which the flat rung CAN reach - so its attribution is the whole check, and that is why it is written as a rung name rather than a verdict. * AC1 is a sweep of small-but-real spreads (0.0005 down to 0.000001) all ALLOWED at min_spread_eur_kwh=0.0, with the exactly flat series on the other side still refused BY THE FLAT RUNG - without that mirror the sweep would also pass for a rung deleted outright. 1e-6 is the floor because the shipped line rounds the spread to 6 decimals; that quantisation is graded in the open as its own row rather than left unstated. * AC3 is a five-row table graded on rung attribution, which denies the masking from both sides at once. * The firm-pair count is also pinned from ABOVE (`< 3`) and BELOW (`< 0`), which the criteria do not ask for but which is what stops this section being one-sided in exactly the way it was written to fix. EVIDENCE. Eight rounds through TEST-15's tools/mutation_run.sh, used UNCHANGED: recursive __pycache__ purge before each run, python3 -B, the tree re-copied FROM DISK between rounds, the mutated line grepped out of the file before the run, byte delta printed, test_static_tariff.py and test_arbitrage.py graded each time. Baseline green. baseline, shipped +0 B PASS D1 `spread == 0.0` -> `<= 0.001` +2 B RED, 3 checks D2 `spread == 0.0` -> `<= 0.000001` +5 B RED, AC1 alone D3 `spread == 0.0` -> `< 0.0` (rung gone) +0 B RED (section 2 as well) F1 `len(firm) < 2` -> `< 1` +0 B RED, 3 checks F2 `len(firm) < 2` -> `< 3` +0 B RED, 6 checks F3 `len(firm) < 2` -> `< 0` (rung gone) +0 B RED (ValueError) D1+F1 BOTH AT ONCE - THE TICKET +2 B RED, 5 checks Four of the seven are +0 B, the delta MUTATION.md names as the one stale bytecode can hide. All are REDS, the direction that defect cannot fabricate - but they were run under the purge anyway, because "it went red so the cache cannot have lied" is a conclusion and not a procedure. NO SHIPPED BEHAVIOUR CHANGED. app/ is untouched; both rungs were correct all along, and the card is explicit that a rung found actually wrong is a stop-and- report rather than an edit. Also updated: MUTATION.md gains a short section on masking as a SECOND way a survivor lies, with the two rules that fall out of it (grade the reason, and mutate suspected pairs together); and test_arbitrage.py's SAFETY-26 AC4 note is marked closed rather than left reading as an open finding. UNSURE ABOUT. The 5e-7 row asserts the shipped `round(spread, 6)` quantisation. That is a real property of the line and worth stating, but it does pin a rounding the ticket never named - if a reviewer would rather that stayed unpinned, it is one check to drop and nothing else depends on it.
admin added 1 commit 2026-09-01 07:37:29 +02:00
SAFETY-26's AC4 gave the same tolerance mutation to every price and quantity
boundary in arbitrage.py and static_tariff.py. Everything in arbitrage.py went
red - `price < 0`, `soc <= floor_pct`, `soc >= ceiling_pct` are each red under
+/-5. Two survived, both in static_tariff.py, and this card closes them.

  D  `spread == 0.0` (:912) weakened to `spread <= 0.001` SURVIVED at +2 B.
  F  `len(firm) < 2` (:901) weakened to `len(firm) < 1` SURVIVED at +0 B - the
     delta MUTATION.md names as the risky one.

THE DEFECT IS NOT EITHER ROW, IT IS THE INTERACTION. D and F MASK EACH OTHER. A
single firm hour also has a spread of 0.0, so with F weakened the flat rung
refuses the stimulus anyway; with D weakened the small-but-real spread is still
refused, only for a lie. Each rung's failure is absorbed by the other, so BOTH
can be weakened together and a suite grading `kind == "refused"` reports
nothing. That is structurally invisible to single-mutation testing, which is how
this pair came through four rounds of review on TARIFF-03 and FCST-03 - and it
is the arrangement in which the next edit to either rung opens a real hole with
nothing to report it.

D is not cosmetic either. With the tolerance in place a series priced 0.20000 /
0.20050 - a REAL 0.0005 EUR/kWh spread - flips ALLOWED to REFUSED at
min_spread_eur_kwh=0.0, a value arbitrage()'s own docstring documents ("pass 0.0
to mean any positive spread, explicitly") and its validator at :861 accepts on
purpose. At a shipped threshold the outcome does not move, but the operator
reads the false sentence "the tariff is flat - every one of the 2 firm hours
costs 0.2000 EUR/kWh" about a tariff that is not flat.

WHAT WAS ADDED. test_static_tariff.py section 9, and the shape of it is the
argument:

  * THE REASON IS GRADED, NOT THE VERDICT. The masked case refuses CORRECTLY
    while reporting the wrong sentence, so a check asserting only "refused"
    passes on a broken tree. A `rung9()` helper names which refusal answered,
    from the sentence the operator would read; an unrecognised refusal reports
    itself as UNATTRIBUTED rather than quietly matching nothing.
  * EACH RUNG IS GIVEN A STIMULUS THE OTHER CANNOT ABSORB, or the pinning is
    circular. The flat rung gets a THREE-firm-hour flat series, which no
    `len(firm) < N` a person would write can reach. The firm-pair rung gets a
    ONE-FIRM-HOUR series, which the flat rung CAN reach - so its attribution is
    the whole check, and that is why it is written as a rung name rather than a
    verdict.
  * AC1 is a sweep of small-but-real spreads (0.0005 down to 0.000001) all
    ALLOWED at min_spread_eur_kwh=0.0, with the exactly flat series on the other
    side still refused BY THE FLAT RUNG - without that mirror the sweep would
    also pass for a rung deleted outright. 1e-6 is the floor because the shipped
    line rounds the spread to 6 decimals; that quantisation is graded in the
    open as its own row rather than left unstated.
  * AC3 is a five-row table graded on rung attribution, which denies the masking
    from both sides at once.
  * The firm-pair count is also pinned from ABOVE (`< 3`) and BELOW (`< 0`),
    which the criteria do not ask for but which is what stops this section being
    one-sided in exactly the way it was written to fix.

EVIDENCE. Eight rounds through TEST-15's tools/mutation_run.sh, used UNCHANGED:
recursive __pycache__ purge before each run, python3 -B, the tree re-copied FROM
DISK between rounds, the mutated line grepped out of the file before the run,
byte delta printed, test_static_tariff.py and test_arbitrage.py graded each
time. Baseline green.

  baseline, shipped                            +0 B  PASS
  D1  `spread == 0.0` -> `<= 0.001`            +2 B  RED, 3 checks
  D2  `spread == 0.0` -> `<= 0.000001`         +5 B  RED, AC1 alone
  D3  `spread == 0.0` -> `< 0.0`  (rung gone)  +0 B  RED (section 2 as well)
  F1  `len(firm) < 2` -> `< 1`                 +0 B  RED, 3 checks
  F2  `len(firm) < 2` -> `< 3`                 +0 B  RED, 6 checks
  F3  `len(firm) < 2` -> `< 0`  (rung gone)    +0 B  RED (ValueError)
  D1+F1  BOTH AT ONCE - THE TICKET             +2 B  RED, 5 checks

Four of the seven are +0 B, the delta MUTATION.md names as the one stale
bytecode can hide. All are REDS, the direction that defect cannot fabricate -
but they were run under the purge anyway, because "it went red so the cache
cannot have lied" is a conclusion and not a procedure.

NO SHIPPED BEHAVIOUR CHANGED. app/ is untouched; both rungs were correct all
along, and the card is explicit that a rung found actually wrong is a stop-and-
report rather than an edit. Also updated: MUTATION.md gains a short section on
masking as a SECOND way a survivor lies, with the two rules that fall out of it
(grade the reason, and mutate suspected pairs together); and test_arbitrage.py's
SAFETY-26 AC4 note is marked closed rather than left reading as an open finding.

UNSURE ABOUT. The 5e-7 row asserts the shipped `round(spread, 6)` quantisation.
That is a real property of the line and worth stating, but it does pin a
rounding the ticket never named - if a reviewer would rather that stayed
unpinned, it is one check to drop and nothing else depends on it.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
admin added 1 commit 2026-09-01 07:58:59 +02:00
Merge remote-tracking branch 'origin/release/1.0' into TEST-16
checks / unit (pull_request) Successful in 3m41s
6ea84a46f6
# Conflicts:
#	goodwe_controller/CHANGELOG.md
admin merged commit 950472662e into release/1.0 2026-09-01 08:02:58 +02:00
Sign in to join this conversation.
No Reviewers
No labels
1 Participants
Notifications
Due Date
No due date set.
Dependencies

No dependencies set.

Reference: admin/goodwe-addon#37