CI-02 probe F: the ORIGINAL gate, unchanged, on the same unmergeable PR
checks / unit (pull_request) Successful in 3m38s

This commit is contained in:
glenn schrooyen
2026-09-01 03:38:00 +02:00
parent 4c64aa2106
commit 6ff223d44b
25 changed files with 1269 additions and 217 deletions
+41
View File
@@ -5,6 +5,13 @@ three refusable configurations are refused. The second asserts that everything
on validate.py's "deliberately not refused" list still STARTS - because the way
a validator dies is not by missing a fault, it is by refusing something harmless
until somebody deletes the call.
⚠️ MUTATING THE MODULE THIS FILE GRADES? PURGE `__pycache__` FIRST - or run
`tools/mutation_run.sh`, which does. `python3 -B` alone does NOT save you: it
stops bytecode being WRITTEN, not a stale one being READ, and a size-preserving
edit reverted inside one second is invisible to CPython's staleness test. That
is TEST-15, and it has already turned one live mutation into a false survivor.
Read MUTATION.md before you report a survivor.
"""
import asyncio
@@ -76,6 +83,40 @@ check("an unreachable device skips the range check rather than assuming",
check("a non-numeric max_w is refused",
why(validate_startup_config(base(max_w="lots"), -5000, 5000), "not a number"))
# --------------------------------------------------------------------------- #
# 1b. SAFETY-20's AC4 decision, PINNED HERE RATHER THAN ONLY WRITTEN DOWN
# --------------------------------------------------------------------------- #
# AC4 asked whether a device rating that disarms SAFETY-18's freeze rail
# additionally warrants a refusal of its own, the way `sign_disagree_w >= max_w`
# is refused. THE ANSWER IS NO, AND THE REASON IS RULE 2 ABOVE: the configuration
# is `max_w` above the device rating, which rule 2 already refuses on the
# identical predicate. A rail-specific rule (`0.95 * max_w > dev_max`) would fire
# on a strict SUBSET of what rule 2 refuses, so it could never be the rule that
# stopped a start.
#
# ⚠️ THAT DECISION HAS A PREMISE, AND THIS IS THE PREMISE, EXECUTED. If rule 2 is
# ever softened to a warning - which is exactly what main.py used to do before
# CFG-01 - the reasoning recorded in validate.py's "deliberately not refused"
# list silently stops being true, and SAFETY-18 is left with only its runtime
# NOT COVERED row. Then somebody has to come back and re-decide AC4.
from app.freeze import RAIL_FRAC # noqa: E402 - imported here, beside its use
_DEV = 4700.0 # the ticket's inverter
_CEIL = 5000.0 # the ticket's configured ceiling
check("SAFETY-20's premise: a rating below max_w disarms the freeze rail, so "
f"{RAIL_FRAC:g} * max_w is unreachable on the ticket's install",
_DEV < RAIL_FRAC * _CEIL)
check("...and rule 2 REFUSES that whole configuration at startup, which is why "
"SAFETY-20 added no rule of its own (AC4)",
len(validate_startup_config(base(max_w=_CEIL), -_DEV, _DEV)) == 1)
check("...on the rating side specifically, not incidentally through some other "
"rule", why(validate_startup_config(base(max_w=_CEIL), -_DEV, _DEV),
"THE DEVICE WINS"))
check("...and the case the refusal CANNOT reach - the rating unread because "
"ESPHome was not up - still starts, which is precisely why SAFETY-20's "
"answer had to be a runtime status row and not a startup gate",
validate_startup_config(base(max_w=_CEIL), None, None) == [])
# --------------------------------------------------------------------------- #
print("2. an actuator to write to")
# A controller with no actuator: write_setpoint() returns on the blank entity,