SAFETY-44: keep attribution in-tree, add the third clause, and correct a claim I made for my own precondition
checks / unit (pull_request) Successful in 6m56s

Review APPROVED f109153 and the split. Three asks, all applied, plus a
correction it caught in the round-4 commit message.

C STAYS IN-TREE. Attribution is a third property of the same comprehension -
`sorted()` decides which vanished key wins a destination, so a build renaming
`inverter-b` -> `garage` while DELETING `inverter-a` names the deleted key as
migrated and the one that really moved as VANISHED. A reader of the disclosure
paragraph wants it beside the other two rather than only in Trello. One
sentence, same block.

AND A FOURTH CLAUSE REVIEW MEASURED THIS ROUND: `and after.data.get(k) ==
value` survives the suite and is load-bearing. Without it the rule degenerates
to BARE-NAME matching - a deleted `unit/old-x/sign_reason` was reported as
having migrated into a `sign_reason` holding a COMPLETELY DIFFERENT SENTENCE,
and essentially every off-roster vanished `unit/*` key would be suppressed.
Added to the paragraph and to INSTR-01, so all of `moved_to` is covered by one
fixture design rather than two-thirds of one.

⚠️ AND THE POINT IS THAT THEY ARE FOUR CLAUSES OF **ONE COMPREHENSION**, WHICH
IS STRUCTURAL AND NOT A LIST OF CHORES. Four conditions, four different reasons
to exist, one fixture set that can reach only some at a time - so rebuilding a
fixture to reach clause N moves the others. That is exactly how round 4's
disarming happened, and it is what INSTR-01 has to design against rather than
patch around. Review called this the sharpest thing found in four rounds and it
is a fact about the function, not about the two clauses that exposed it.

⚠️ AND I OVERCLAIMED FOR MY OWN PRECONDITION. The round-4 message said the
strengthened M12 precondition was needed because "the exit code alone cannot
say the second thing". Review checked: on a clean run the finding regex matches
nothing, so the second conjunct is IMPLIED by the first today. It is
belt-and-braces, load-bearing only if the exit-0 requirement is ever relaxed.
WHAT ACTUALLY CLOSED THE FIRST DRAFT'S GAP IS `_m12_new` BEING A SET DIFFERENCE
- the mutation must ADD a finding - and that is the check the narrowing's
removal turns red. The wrong half was credited, and the comment now says which
half does the work.

Nit: the fixture's trailing newline and two backticks, lost last round.

`rehearse_roster.py` is still byte-identical to d1b7e3f - this round touches
only the test file's disclosure paragraph and the fixture's comment. 28/28 pass.

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 19:02:59 +02:00
co-authored by Claude Opus 5
parent f109153216
commit 775f3a2e82
2 changed files with 31 additions and 5 deletions
+29 -3
View File
@@ -452,10 +452,16 @@ _m12_new = (set(re.findall(r"⚠️ ([A-Z ]+): (\S+)", _m12_out))
print(f" both-latched store, shipped -> exit {_m12_clean_code}; "
f"one unit's latch key deleted -> exit {_m12_code}")
print(f" findings the mutation ADDS: {sorted(_m12_new)}")
# ⚠️ THE SECOND CONJUNCT IS IMPLIED BY THE FIRST TODAY - on a clean run the
# finding regex matches nothing - and the commit message that introduced it
# overclaimed by saying the exit code "cannot say" it. It is belt-and-braces,
# load-bearing only if the exit-0 requirement is ever relaxed. WHAT ACTUALLY
# CLOSED THE FIRST DRAFT'S GAP IS `_m12_new` BEING A SET DIFFERENCE: the
# mutation must ADD a finding, which is the check the narrowing's removal turns
# red. Said plainly here because the wrong half was credited once already.
check("⚠️ PRECONDITION: the fixture is clean on the shipped tree AND does not "
"already report the finding this mutation exists to produce. The exit "
"code alone cannot say the second thing, and the previous draft passed "
"on exactly that gap",
"already report the finding this mutation exists to produce - the second "
"is implied by the first today and kept as a belt-and-braces guard",
_m12_clean_code == RR.EXIT_OK
and not any(k == "unit/shed/sign_tripped"
for _, k in re.findall(r"⚠️ ([A-Z ]+): (\S+)", _m12_clean_out)))
@@ -724,6 +730,19 @@ check("...and no leg's text has swallowed the CLOSING SUMMARY, which repeats "
# renaming `old-b` -> `shed`: exit 0, NO FINDINGS, `old-a` reported as having
# moved into a key that already held True.
#
# ATTRIBUTION. Which vanished key gets a destination is decided by
# `sorted()`, so on a build renaming `inverter-b` -> `garage` while DELETING
# `inverter-a`, the deleted key sorts first and takes it: the report names the
# DELETED key as migrated and the one that really moved as VANISHED. The run
# is still exit 1, so this is a wrong sentence rather than a hidden loss - but
# an operator chasing the named key looks at the wrong inverter.
#
# VALUE MATCHING. `and after.data.get(k) == value` survives the suite and is
# load-bearing: without it the rule degenerates to BARE-NAME matching, and
# review measured a deleted `unit/old-x/sign_reason` reported as having
# migrated into a `sign_reason` holding a COMPLETELY DIFFERENT SENTENCE.
# Essentially every off-roster vanished `unit/*` key would be suppressed.
#
# ⚠️ BOTH FIXES ARE ONE LINE AND BOTH WERE WRITTEN, AND BOTH ARE REVERTED OUT
# OF THIS CARD, because THIS SUITE CANNOT MEASURE EITHER ONE. Three attempts:
# a check over part 5's destinations passed with the whole injectivity
@@ -742,6 +761,13 @@ check("...and no leg's text has swallowed the CLOSING SUMMARY, which repeats "
# They go on their own card, with review's measurements as the starting
# evidence and a fixture built BEFORE the fix.
#
# ⚠️ ALL FOUR ARE CLAUSES OF **ONE COMPREHENSION**, WHICH IS THE STRUCTURAL
# POINT AND NOT A LIST OF CHORES. `diff()`'s `moved_to` now carries four
# conditions with four different reasons to exist, against one fixture set that
# can reach only some of them at a time - so rebuilding a fixture to reach
# clause N moves the others. That is exactly how (3) happened, and it is what
# INSTR-01 has to design against rather than patch around.
#
# What IS measured here is the narrowing, by M12 above, both ways.
check("⚠️ and the key that MOVED is not reported as lost: the before-snapshot "
"holds `unit/inverter-a/sign_tripped = True` and the after-snapshot "