SAFETY-38 round 4: the enumeration covered one sink, and it was not the one this codebase uses
checks / unit (pull_request) Successful in 5m12s
checks / unit (pull_request) Successful in 5m12s
The scanner's two censuses between them scored ONE syntactic sink and called it
the family. Every one of census B's 16 members was a sentence that is APPENDED,
ASSIGNED to a `reason`-shaped name, or passed as a LOG ARGUMENT. Not one was
RETURNED - and census A's return bucket only ever held a callee formatting its
own PARAMETERS, so a method formatting its own ATTRIBUTES and handing the string
back was invisible to both. That is the whole describe() / explain() /
reason-builder family, which is where this repository actually keeps its
operator sentences. Worse than the gap: it was in NONE of the five blind spots
the tool printed about itself.
THE SCANNER, WIDENED - and it rediscovered both members without being told:
* CENSUS C, the return sink, resolved through the returning method's CALL
SITES so a returned KEY (store.unit_key, mqtt.unit_state_key - MAINT-05's
card) is not mistaken for a returned SENTENCE. 53 returned pairs, 39
reaching an operator, 16 of those sharing a format spec.
* A sentence handed to a constructor as `reason=` or placed under a "text"
dict key is a MESSAGE. That one line of the sink walker was hiding SIX more
caller-built members, census B 16 -> 22.
* Every census B and C row now prints whether the two interpolations share a
FORMAT SPEC - the difference between a transposition that is silent and one
that merely looks broken.
* The blind-spot list is now TWO lists: what it scans (printed from the
constants, so they cannot drift) and WHAT IT DOES NOT SCAN AT ALL, largest
hole first - `%s`-style lazy logging, MEASURED at 31 calls across 8 modules
and each one listed, not asserted.
CLOSED, both zero-byte survivors of a green 21-file suite:
* clamp.py:253 ClampResult.describe(), requested_w <-> applied_w. No
test_*.py mentioned describe() at all. It is the SS15 action-log row
(main.py:1366) AND the ClampWatchdog notification reason (main.py:2452) -
the alarm SAFETY-40 and SAFETY-41 are about. Under the swap the guard
reports a setpoint clamped UPWARD, to +9999 W by a bound whose rating the
same sentence gives as 2000 W. Pinned on the ORDERED PAIR on the contiguous
literal at BOTH consumers, operands read off ctl.target and
hass.writes[-1] - what the loop asked and what the device was sent - not
off the ClampResult the swap lives in. 4 checks red.
* peakguard.py:493 PeakDecision.explain(), projected_w <-> ceiling_w. "peak
guard idle" was in no test_*.py. The row then reads "projects 5013 W under
a 2300 W ceiling" - 2713 W OVER - on a row whose own words say idle and
whose own flag says ok. Pinned on the decision and on the shipped status
row. 3 checks red.
* test_arbiter.py's scope-violation check, whose CLAIM was wider than its
ASSERTION. Measured this round rather than left at source level: 0 bytes,
21/21 green before, red now. 2 checks.
DISCLOSED, NOT CLOSED - 11 measured zero-byte survivors, each with its file
fingerprint and its 21/21 verdict, in the decision doc SS7e-SS7g. Three in
allocator.py's UnitPlan.explain(), three across arbiter.py's two explain()s,
two in tariff.py, two in arbitrage.py's trade reasons, one in main.py's
SoC-floor notification. An enumerated list with honest gaps beats a fifth round
finding a fifth instance.
CORRECTIONS THIS ROUND OWES:
* The idle sentence does NOT reach main.py:3299/3302 - those are the
floor-limited branch, where explain() returns self.reason before the idle
literal is built. It reaches main.py:3313 and, on the release edge, 1951.
1951 is disclosed unpinned.
* SS4's "Every one of the ten is red" sat under a twelve-row table: it is the
ten site_standing entries.
* SS6b said "weaker evidence than A1-A3"; A4 was measured, so SS7d's
"A1-A4 and B1" is the right list and SS6b now says it.
* AND THE PROBE THAT GRADES THESE MUTATIONS WAS THE DEFECT, ONCE. Its first
cut numbered the operands BY ORDER OF APPEARANCE, so after a transposition
the other leaf took the same number and all thirteen mutant renders came
back byte-identical - which reads exactly like "the edit is inert". Keying
the value to the NAME fixed it. Habit 4, in the measuring instrument:
MUTATION.md habit 16 is the new entry, and the count there is corrected to
eleven rather than inflated.
14 mutations measured: fresh full-repo copy each, mounted :ro, bytecode purged
and the purge COUNT printed, the edit re-read from disk, length and sha256
printed on both sides, and every one required to change the EMITTED SENTENCE
and not merely the bytes. 12 survived the pre-round suite, 1 was already
caught, 3 are caught now. Full 21-file suite green on the final tree.
NOT ONE BYTE OF app/ MOVES. This card changes coverage only.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01BwRLw7eKYj2byVdwB6kbjU
This commit is contained in:
@@ -5774,6 +5774,86 @@ check("...and so is the last one, which is not a defeat at all but the EDGE OF "
|
||||
not MUT[12][1] and EV["min_soc"] <= BMS_FLOOR + 0.05)
|
||||
|
||||
|
||||
# ==============================================================================
|
||||
print()
|
||||
print("13. SAFETY-38 round 4: the ORDERED PAIR inside PeakDecision.explain()")
|
||||
|
||||
# ⚠️ THE STRING "peak guard idle" APPEARED IN NO test_*.py UNTIL THIS PART.
|
||||
# `peakguard.py:493` formats its OWN ATTRIBUTES and RETURNS the sentence:
|
||||
#
|
||||
# f"peak guard idle - quarter projects {self.projected_w:.0f} W under a "
|
||||
# f"{self.ceiling_w:.0f} W ceiling ({self.ceiling_from})"
|
||||
#
|
||||
# Transpose the two and this fixture's row reads "projects 5013 W under a
|
||||
# 2300 W ceiling" - a quarter projected 2713 W OVER the ceiling, printed on a
|
||||
# row whose own words say the guard is IDLE and whose own flag says ok.
|
||||
# MEASURED on this tree: zero-byte edit (50 032 bytes
|
||||
# before, 50 032 after, sha256 d95df61a51716c26 -> 2d2ee3d0bcd51251), the
|
||||
# emitted sentence changes, and the full 21-file suite stayed GREEN.
|
||||
#
|
||||
# The sentence was invisible to SAFETY-38's scanner for two rounds because both
|
||||
# censuses scored one syntactic sink - APPEND, ASSIGN, LOG ARG - and this one is
|
||||
# RETURNED. `tools/symmetric_message_scan.py` census C now scans the return sink
|
||||
# and resolves it through the method's call sites; it rediscovered this pair and
|
||||
# clamp.py's on its own, which is the only reason to trust the rest of its list.
|
||||
#
|
||||
# ⚠️ THE OPERANDS COME OFF THE PROJECTION AND OFF `quarter_ceiling_w()`, NOT OFF
|
||||
# THE DECISION. `d.projected_w` and `d.ceiling_w` are the very fields the swap
|
||||
# exchanges, so grading the sentence against them would compare the swap against
|
||||
# itself and pass under it.
|
||||
_S38_PROJ = PeakTracker.project(averager_at(CAP_W - 1200.0, 450.0),
|
||||
B + timedelta(seconds=450))
|
||||
_S38_CEIL_W, _S38_CEIL_FROM = quarter_ceiling_w(CAP_W, obs_hi)
|
||||
_S38_IDLE = decide(_S38_PROJ, batt_w=0.0, cap_w=CAP_W, reading=obs_hi,
|
||||
achievable_w=LIVE_MAX_W, max_hold_s=MAX_HOLD_S,
|
||||
soc=SOC_OK, soc_floor=SOC_FLOOR)
|
||||
_S38_LITERAL = (f"quarter projects {_S38_PROJ.projected_w:.0f} W under a "
|
||||
f"{_S38_CEIL_W:.0f} W ceiling")
|
||||
_S38_SWAPPED = (f"quarter projects {_S38_CEIL_W:.0f} W under a "
|
||||
f"{_S38_PROJ.projected_w:.0f} W ceiling")
|
||||
print(f" projection {_S38_PROJ.projected_w:.0f} W against a "
|
||||
f"{_S38_CEIL_W:.0f} W ceiling ({_S38_CEIL_FROM})")
|
||||
print(f" {_S38_IDLE.explain()!r}")
|
||||
check("PRECONDITION: the guard is IDLE with a projection to print, the ceiling "
|
||||
"came from the MONTH PEAK rather than the cap, and the two operands are "
|
||||
"DIFFERENT NUMBERS that RENDER differently. Equal operands would make the "
|
||||
"transposed sentence identical and every check below decoration",
|
||||
not _S38_IDLE.engaged and _S38_IDLE.projected_w is not None
|
||||
and _S38_CEIL_FROM == CEILING_MONTH_PEAK
|
||||
and _S38_PROJ.projected_w != _S38_CEIL_W
|
||||
and f"{_S38_PROJ.projected_w:.0f}" != f"{_S38_CEIL_W:.0f}"
|
||||
and _S38_PROJ.projected_w < _S38_CEIL_W)
|
||||
check("⚠️ THE ORDERED PAIR ON THE CONTIGUOUS LITERAL. The PROJECTION is named "
|
||||
"first and the CEILING second; a substring test for either number passes "
|
||||
"under the transposition because both numbers are still in the sentence, "
|
||||
"so only the ordered pair can tell the two slots apart (MUTATION.md "
|
||||
"habit 14)", _S38_LITERAL in _S38_IDLE.explain())
|
||||
check("...and the TRANSPOSED sentence is NOT what it says, so the check above "
|
||||
"discriminates rather than decorates",
|
||||
_S38_SWAPPED not in _S38_IDLE.explain())
|
||||
check("...and the row still names WHERE the ceiling came from, which is the "
|
||||
"difference between a cap an operator set and a peak the month already "
|
||||
"banked", f"ceiling ({CEILING_MONTH_PEAK})" in _S38_IDLE.explain())
|
||||
|
||||
# THE SHIPPED CONSUMER. `explain()` is not read by anybody until main.py prints
|
||||
# it, and round 3's lesson is that the pin belongs on the CALL SITE: the status
|
||||
# row at main.py:3313 is what a browser shows, and the action-log line at
|
||||
# main.py:1951 is what the release edge writes.
|
||||
_c38, _h38 = built(TMP / "s38pin.db")
|
||||
_c38.peak_guard = _S38_IDLE
|
||||
_rows38 = [r for r in _c38.checks() if "peak guard" in r["text"]]
|
||||
print(" status row: " + (_rows38[0]["text"] if _rows38 else "(none)"))
|
||||
check("⚠️ ...AND THE SAME ORDERED PAIR ON THE STATUS PAGE (main.py:3313), read "
|
||||
"off the shipped `checks()` rather than off `explain()` a second time. "
|
||||
"This is the surface the owner actually looks at",
|
||||
len(_rows38) == 1 and _S38_LITERAL in _rows38[0]["text"]
|
||||
and _S38_SWAPPED not in _rows38[0]["text"])
|
||||
check("...and the row is green and un-warned, which is what makes the "
|
||||
"transposed version dangerous rather than merely untidy: an OK row "
|
||||
"carrying a projection 2713 W OVER its own ceiling is the one an "
|
||||
"operator scrolls past", _rows38[0]["ok"] and not _rows38[0]["warn"]
|
||||
and _S38_CEIL_W - _S38_PROJ.projected_w == 2713.0)
|
||||
|
||||
# ==============================================================================
|
||||
print()
|
||||
shutil.rmtree(TMP, ignore_errors=True)
|
||||
|
||||
Reference in New Issue
Block a user