diff --git a/goodwe_controller/test_rehearse.py b/goodwe_controller/test_rehearse.py index b5bec8b..6950ac3 100644 --- a/goodwe_controller/test_rehearse.py +++ b/goodwe_controller/test_rehearse.py @@ -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 " diff --git a/goodwe_controller/tools/rehearsal/state-both-latched.json b/goodwe_controller/tools/rehearsal/state-both-latched.json index ff04f39..65cd690 100644 --- a/goodwe_controller/tools/rehearsal/state-both-latched.json +++ b/goodwe_controller/tools/rehearsal/state-both-latched.json @@ -1,5 +1,5 @@ { - "_comment": "SAFETY-44 SYNTHETIC FIXTURE - not a copy of any live state file; this session cannot read that one and did not try. It exists for ONE control: a store in which TWO ROSTER UNITS ARE LATCHED AT THE SAME VALUE. state-legacy.json cannot serve it - it is pre-DEV-02 and flat, so after migration only the FIRST roster entry is ever latched, and a rule that suppresses a vanished key when another key holds the same value can never be exercised against it. That is exactly how M12's first draft came to pass on the UNMUTATED tree. Both units are latched by ONE site event, so the reasons match too, which is the arrangement in which the suppression is most dangerous.", + "_comment": "SAFETY-44 SYNTHETIC FIXTURE - not a copy of any live state file; this session cannot read that one and did not try. It exists for ONE control: a store in which TWO ROSTER UNITS ARE LATCHED AT THE SAME VALUE. `state-legacy.json` cannot serve it - it is pre-DEV-02 and flat, so after migration only the FIRST roster entry is ever latched, and a rule that suppresses a vanished key when another key holds the same value can never be exercised against it. That is exactly how M12's first draft came to pass on the UNMUTATED tree. Both units are latched by ONE site event, so the reasons match too, which is the arrangement in which the suppression is most dangerous.", "schema_version": 1, "maint_schema_version": 1, "auto": true, @@ -7,4 +7,4 @@ "unit/garage/sign_reason": "SIGN_DISAGREEMENT: grid meter reversed, both units", "unit/shed/sign_tripped": true, "unit/shed/sign_reason": "SIGN_DISAGREEMENT: grid meter reversed, both units" -} \ No newline at end of file +}