ARCH-02: assert the invariant, because a fixture cannot enumerate arrangements
checks / unit (pull_request) Successful in 6m55s

Review approved and then attacked part 5b, the control that stands between B1's
defect and a green suite. It got through in three edits:

    A1  delete `END LEG`                        5b CATCHES it        2 FAIL
    A2  ...and reorder the legs                 5b BLIND             1 FAIL
    A3  ...and reword the closing summary       0 FAIL, "all checks passed"
                                                with a splitter that closed
                                                ZERO legs

⚠️ TWO OF THOSE THREE ARE ORDINARY REFACTORS - reordering report legs, rewording
a summary line - and neither reads as touching a safety check. 5b caught the
unclosed splitter only because the clean leg happened to be printed LAST, and
the backstop that saved A2 was a hardcoded transcription of the tool's own
sentence, so rewording that sentence blinded it too.

FIXED BY ASSERTING THE STRUCTURE RATHER THAN ADDING A FIXTURE: a leg may not
open while one is open, and every leg that opens must be explicitly closed.
Driven - deleting `END LEG` now fails on the FIRST edit, whatever the order or
the wording:

    AssertionError: leg 'SAME-STEP' opened while 'STAGED' was still open - the
    tool stopped closing its legs, and a splitter that never closes swallows the
    closing summary into the last leg.

All three attacks include that edit, so one assertion kills the class. Clean
tree unchanged: 28/28, all checks passed.

⭐ AND THE RULE IN MUTATION.md IS EXTENDED, because review's finding is the
general case of it. It said "a per-thing check that has never seen the things
DISAGREE is a total". Part 5b DOES make them disagree, every run, and was still
blind. So:

    ...AND ONE THAT HAS ONLY SEEN THEM DISAGREE IN ONE ARRANGEMENT IS A TOTAL
    OVER THAT ARRANGEMENT. When a fixture cannot enumerate the arrangements,
    assert the invariant they share.

Also recorded, NOT fixed, with the reason: the reference carries `entity_id
unique_id device` and grades all three, but never the discovery TOPIC. Review
measured `homeassistant/... -> ha/...` exiting 0 with no findings while every
announced entity dies. `discovery_payloads()` already returns the topic and
`announced_rows` discards it, so a fourth column closes it - but the prefix is
HA's fixed contract rather than a name this project chooses, so it is not what a
tidy-up rename reaches. Lower LIKELIHOOD than the N1 gap it resembles, not lower
consequence, and it stops being a note the day the topic becomes configurable.

Two stale figures corrected: the tool claimed five migration mutations where
there are nine, and pointed at a DOCS.md heading that does not exist (the real
one is "Before you commission inverter B", verified present at DOCS.md:1577).

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-08 15:01:55 +02:00
co-authored by Claude Opus 5
parent 9c1a9e0f17
commit 22ca341459
3 changed files with 64 additions and 3 deletions
+27 -1
View File
@@ -246,15 +246,41 @@ def legs(out: str) -> dict:
leg is genuinely clean: it still reported SAME-STEP disarmed. Part 5b is
the running control for exactly that.
"""
out_legs, current = {}, None
out_legs, current, closed = {}, None, set()
for line in out.splitlines():
if line.startswith(" LEG "):
# ⚠️ AND THIS ASSERTION IS THE ONE THAT KILLS THE CLASS. Review
# attacked part 5b directly and got through in three edits: delete
# `END LEG` (5b catches it), ALSO reorder the legs (5b goes blind -
# it only ever saw them disagree with the clean leg LAST), and ALSO
# reword the closing summary (the backstop is a transcription of the
# tool's own sentence, so rewording blinds that too). Result: "all
# checks passed" with a splitter that closed ZERO legs.
#
# Two of those three are ordinary refactors - reordering report legs
# and rewording a summary line - neither of which reads as touching
# a safety check. A fixture cannot cover every arrangement, so the
# STRUCTURE is asserted instead: a leg may not open while one is
# open, and every leg that opens must be explicitly closed. Under
# all three attacks nothing is ever closed, so this fires on the
# FIRST edit regardless of order or wording.
assert current is None, (
f"leg {line.strip()[4:].strip()!r} opened while {current!r} was "
"still open - the tool stopped closing its legs, and a splitter "
"that never closes swallows the closing summary into the last "
"leg. That is the defect this function exists to fix.")
current = line.strip()[4:].strip()
out_legs[current] = []
elif line.startswith(" END LEG "):
assert current is not None, "END LEG without an open leg"
closed.add(current)
current = None
elif current is not None:
out_legs[current].append(line)
assert current is None, f"leg {current!r} was never closed"
assert closed == set(out_legs), (
f"legs opened {sorted(out_legs)} but closed {sorted(closed)} - a leg "
"that is never closed absorbs everything after it")
return {k: "\n".join(v) for k, v in out_legs.items()}