MAINT-05 fix round 2: the refusal has to survive the NEXT start, and both marker guards have to be visible
checks / unit (pull_request) Successful in 5m14s
checks / unit (pull_request) Successful in 5m14s
REJECTED because the fix round's own load-bearing sentence was FALSE, and the
whole suite was blind to that. `_verify_moves()` produced the red the reviewer
reproduced - that half stood - but DECISIONS §2 claimed "`ok` gates the marker,
so a misdirected migration is not stamped and the next start runs it again ...
a re-run is recoverable". THE REFUSAL LASTED EXACTLY ONE START.
MEASURED, Controller level, ONE persisted store, roster ["garage","shed"], flat
last_completed 2026-08-07, call site still handing `inverter-a` on both starts:
construction 1: ok=False misdirected=4 moved=4 kept=0 marker=<absent>
construction 2: ok=True misdirected=0 moved=0 kept=4 marker=1
history parked under unit/inverter-a/...; marker stamped after ONE restart.
WHY. `_verify_moves()` graded only `rep.moved`. On start 2 the same wrong call
site finds the four keys already present, so rule 1 routes every one of them to
`rep.kept`, `rep.moved` is EMPTY, the roster loop iterates over nothing,
`misdirected` is empty and `ok` is True. Start 3 then takes the
`from_version >= MAINT_SCHEMA_VERSION` early return FOREVER - including after
the call site is fixed. Loud-and-recoverable became silent-and-permanent after
one restart: the exact state store.py's header says must never happen, reached
by the fix written to prevent it.
WHY THE CHECK MISSED IT - the recurring defect, this time INSIDE the remedy.
Part 9b's recovery check was `migrate_maint_keys(_m5, ROSTER[0], ROSTER)` - the
CORRECTED name. It measures recovery along the one path where the operator has
ALREADY fixed the bug. Nothing in the 19 files called `migrate_maint_keys()`
twice with the SAME WRONG `unit`. The check was true and passed for the wrong
reason.
WHAT CHANGED
1. app/store.py `_verify_moves()` grades `set(rep.moved) | set(rep.kept)`.
Sound by construction: every entry in both lists is a `unit_key(unit,
legacy)` built from the SAME `unit` argument, so grading `kept` grades the
same namespace decision `moved` does. A correct call site's `kept` entries
sit under a roster name and pass; a wrong one cannot launder its namespace by
having already written it. `migrate_unit_keys()` passes `roster=None` and
returns before the loop, so it is untouched.
2. test_maintenance.py part 9c - THE CHECK THAT WAS MISSING. Two starts, SAME
wrong unit, ONE store: the marker is still withheld on the second, the
refusal names the same roster, the flat history is still there to recover
from, and a third start with the CORRECTED name still gets a run (which a
stamped marker would have made impossible). Its PRECONDITION asserts the
SHAPE of the second report - `moved` empty, `kept` full - so it cannot
quietly revert to grading 9b's path. Counterfactual beside it: the same two
calls with the right name are accepted, then skipped as `already at schema`.
3. test_maintenance.py part 9d - THE OTHER GUARD ON THE SAME LINE, and a
survivor nothing in the repository could see. `if rep.ok:` is
`not lost and not misdirected`; every check that reached the marker did so on
a store whose `kept` was empty, so
if rep.ok: -> if rep.ok or rep.kept: (+12 B)
stamped the marker on a migration that LOST A MONTH OF HISTORY - defeating
the older, settled `lost` guard as well as the new one - and ALL 19 SUITES
WERE GREEN on it (measured at 65cddf3, purged, :ro). 9d's fixture is the one
shape that separates the guards: two keys already namespaced (`kept`
non-empty, the mutant's `or` fires) and two whose write the store drops
(`lost` non-empty), `misdirected` empty throughout.
4. FOUND HERE AND CLOSED: THE SAME MUTATION ONE FUNCTION UP. `migrate_unit_keys()`
- SAFETY-02's LATCH migration - gates its own marker the same way, and every
check that reached it ran on a store with an empty `kept`. `if rep.ok or
rep.kept:` at store.py:307 SURVIVED ALL 19 FILES. It stamps `schema_version`
on a migration that DROPPED THE LATCH: the guard is off, the file still reads
`sign_tripped: true`, and the store now says the migration finished, so the
next start skips the one thing that would re-arm it. test_inverter.py part 10
now drops the `sign_tripped` write BESIDE an already-namespaced
`sign_reason`, with the accepted-baseline counterfactual. No source change -
the shipped gate was right; nothing could see it. Mutation table 34 -> 35.
5. DECISIONS/MAINT-05 §2 CORRECTED. The paragraph that stated the false
guarantee now states what was measured, why grading `moved` alone could not
hold, and why the union is sound. §7 records the marker-gate hole found in
`migrate_unit_keys()` and that it was closed. MUTATION.md gains habit 9 -
"exercise a refusal a SECOND time with the SAME wrong input, not the
corrected one" - and two survey rows.
MUTATION LEDGER - 11 mutations, ALL RED on the final tree, every run on a fresh
copy with the bytecode cache purged (entry count printed before and after) and
the tree mounted :ro so none could be written. Two were survivors BEFORE this
commit and both are recorded as such. Full transcript on the PR.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01BwRLw7eKYj2byVdwB6kbjU
This commit is contained in:
@@ -806,6 +806,148 @@ check("...and a roster of ONE still returns before any of this, so the "
|
||||
is False)
|
||||
|
||||
|
||||
# --------------------------------------------------------------------------- #
|
||||
print()
|
||||
print("9c. THE REFUSAL HAS TO SURVIVE THE NEXT START: the same wrong call "
|
||||
"site, twice, over ONE store")
|
||||
|
||||
# ⚠️ WHY 9b WAS NOT ENOUGH, AND IT IS THIS FILE'S OWN RECURRING DEFECT ONE
|
||||
# LEVEL UP. 9b's recovery check re-runs the migration with `ROSTER[0]` - the
|
||||
# CORRECTED name - so it measures recovery along the one path where the
|
||||
# operator has ALREADY fixed the call site. The real failure is a call site that
|
||||
# is STILL WRONG on the next start, and until this section nothing in the 19
|
||||
# files called `migrate_maint_keys()` twice with the SAME wrong `unit`. 9b was
|
||||
# true and passed for the wrong reason.
|
||||
#
|
||||
# WHAT THAT HID. Measured at Controller level over one persisted store, roster
|
||||
# ["garage", "shed"], flat `last_completed` 2026-08-07, call site handing
|
||||
# `inverter-a` on both starts:
|
||||
#
|
||||
# construction 1: ok=False misdirected=4 moved=4 kept=0 marker=<absent>
|
||||
# construction 2: ok=True misdirected=0 moved=0 kept=4 marker=1
|
||||
#
|
||||
# `_verify_moves()` graded only `rep.moved`. On start 2 the wrong call site
|
||||
# finds the keys it wrote already present, rule 1 routes all four to `rep.kept`,
|
||||
# `rep.moved` is EMPTY, the roster loop iterates over nothing, `misdirected` is
|
||||
# empty and `ok` is True - so the marker is stamped and start 3 takes the
|
||||
# `from_version >= MAINT_SCHEMA_VERSION` early return FOREVER, including after
|
||||
# the call site is fixed. Loud-and-recoverable became silent-and-permanent after
|
||||
# ONE restart. The fix grades `set(rep.moved) | set(rep.kept)`.
|
||||
_m7 = flat_store()
|
||||
_rep7a = migrate_maint_keys(_m7, UNIT_A, ROSTER)
|
||||
_rep7b = migrate_maint_keys(_m7, UNIT_A, ROSTER)
|
||||
print(f" start 1: ok={_rep7a.ok} misdirected={len(_rep7a.misdirected)} "
|
||||
f"moved={len(_rep7a.moved)} kept={len(_rep7a.kept)} marker="
|
||||
f"{_m7.data.get(MAINT_SCHEMA_KEY, '<<absent>>')!r}")
|
||||
print(f" start 2: ok={_rep7b.ok} misdirected={len(_rep7b.misdirected)} "
|
||||
f"moved={len(_rep7b.moved)} kept={len(_rep7b.kept)} marker="
|
||||
f"{_m7.data.get(MAINT_SCHEMA_KEY, '<<absent>>')!r}")
|
||||
check("PRECONDITION, SO THIS SECTION CANNOT PASS FOR THE WRONG REASON: start 2 "
|
||||
"goes down the KEPT path, which is the path no other check in this file "
|
||||
"reaches. Not one key is written a second time - all four are already "
|
||||
"there from start 1, so `moved` is EMPTY and `kept` holds every one of "
|
||||
"them. If a later edit makes start 2 re-WRITE them, this goes red rather "
|
||||
"than the claim below quietly reverting to 9b's",
|
||||
_rep7b.ran and _rep7b.moved == {}
|
||||
and sorted(_rep7b.kept) == sorted(unit_key(UNIT_A, k)
|
||||
for k in MAINT_UNIT_KEYS))
|
||||
check("⚠️ THE MARKER IS STILL WITHHELD ON THE SECOND START. This is the whole "
|
||||
"section: a refusal that lasts exactly one start is not a refusal, it is "
|
||||
"a delay - the next start stamps the marker on a migration that has "
|
||||
"reached no readable key, and every start after that skips the migration "
|
||||
"entirely",
|
||||
MAINT_SCHEMA_KEY not in _m7.data)
|
||||
check("...and it is refused for the SAME reason as the first time, graded "
|
||||
"against the same roster: four keys under a namespace nothing on this "
|
||||
"site reads. `ok` False, `misdirected` full, `lost` empty - the caller "
|
||||
"was wrong, the store was not",
|
||||
not _rep7b.ok and not _rep7b.verified and not _rep7b.lost
|
||||
and len(_rep7b.misdirected) == len(MAINT_UNIT_KEYS)
|
||||
and repr(ROSTER) in _rep7b.explain())
|
||||
check("...and the history is still THERE to recover: rule 2 left every flat key "
|
||||
"in the file across both starts, and the roster's first pack still reads "
|
||||
"nothing - which is what makes this loud rather than lost",
|
||||
all(_m7.data[k] is not None for k in MAINT_UNIT_KEYS)
|
||||
and _m7.data["last_completed"] == "2026-08-07T12:00:00+00:00"
|
||||
and unit_key(ROSTER[0], "last_completed") not in _m7.data)
|
||||
_rep7c = migrate_maint_keys(_m7, ROSTER[0], ROSTER)
|
||||
print(f" start 3, call site FIXED: {_rep7c.explain()}")
|
||||
check("⚠️ AND BECAUSE THE MARKER WAS NEVER STAMPED, THE FIXED CALL SITE STILL "
|
||||
"GETS A RUN. A stamped marker would have made this an early return "
|
||||
"forever - the operator fixes the bug and the migration never happens "
|
||||
"again. Here the third start migrates the month into `garage` and stamps",
|
||||
_rep7c.ran and _rep7c.ok
|
||||
and _m7.data.get(unit_key(ROSTER[0], "last_completed"))
|
||||
== "2026-08-07T12:00:00+00:00"
|
||||
and _m7.data[MAINT_SCHEMA_KEY] == MAINT_SCHEMA_VERSION)
|
||||
|
||||
# The counterfactual, so this is not a check satisfied by a validator that
|
||||
# refuses every second call: the same two calls with the RIGHT name.
|
||||
_m7ok = flat_store()
|
||||
_rep7ok_a = migrate_maint_keys(_m7ok, ROSTER[0], ROSTER)
|
||||
_rep7ok_b = migrate_maint_keys(_m7ok, ROSTER[0], ROSTER)
|
||||
check("...and the counterfactual: the SAME two calls with the roster's own "
|
||||
"first name are accepted - stamped on the first, and the second is the "
|
||||
"`already at schema` early return, not a refusal. So 9c is about the "
|
||||
"NAME surviving into the second start, not about second calls",
|
||||
_rep7ok_a.ok and _m7ok.data[MAINT_SCHEMA_KEY] == MAINT_SCHEMA_VERSION
|
||||
and _rep7ok_b.ran is False and "already at schema" in _rep7ok_b.explain())
|
||||
|
||||
|
||||
# --------------------------------------------------------------------------- #
|
||||
print()
|
||||
print("9d. THE OTHER GUARD ON THE SAME LINE: a migration that LOST STATE is "
|
||||
"not stamped either, even when some keys were already in place")
|
||||
|
||||
# ⚠️ WHAT THIS PINS, AND IT IS A SURVIVOR THE SECTIONS ABOVE CANNOT SEE.
|
||||
# `migrate_maint_keys()` gates the marker on `rep.ok`, which is BOTH guards:
|
||||
# `not lost and not misdirected`. Every check in this file that reaches the
|
||||
# marker reaches it through `misdirected` (9b, 9c) or through a store where
|
||||
# NOTHING was already namespaced (part 9's `LosesTheHistory`, whose `kept` is
|
||||
# empty). So the mutation
|
||||
#
|
||||
# if rep.ok: -> if rep.ok or rep.kept:
|
||||
#
|
||||
# stamped the marker on a migration that lost a month of history - defeating the
|
||||
# OLDER, settled `lost` guard as well as the new `misdirected` one - and all 19
|
||||
# suites stayed green on it. Measured differential on this exact fixture:
|
||||
# shipped -> marker absent; mutant -> marker 1, both reporting ok=False lost=2.
|
||||
#
|
||||
# The fixture is the one shape that separates them: TWO keys already namespaced
|
||||
# (so `kept` is non-empty and the mutant's `or` fires) and TWO keys whose write
|
||||
# the store drops (so `lost` is non-empty and `ok` is False). `misdirected` is
|
||||
# empty throughout - the unit handed in IS the roster's first name - so this
|
||||
# section cannot pass on the `misdirected` guard by accident.
|
||||
_m8 = LosesTheHistory(dict(flat_store(**{
|
||||
unit_key(ROSTER[0], "phase"): CHARGE,
|
||||
unit_key(ROSTER[0], "phase_started"): "2026-09-03T22:00:00+00:00"}).data))
|
||||
_rep8 = migrate_maint_keys(_m8, ROSTER[0], ROSTER)
|
||||
print(f" two keys already namespaced, two dropped on write: {_rep8.explain()}")
|
||||
print(f" ok={_rep8.ok} lost={len(_rep8.lost)} kept={len(_rep8.kept)} "
|
||||
f"misdirected={len(_rep8.misdirected)}; marker "
|
||||
f"{_m8.data.get(MAINT_SCHEMA_KEY, '<<absent>>')!r}")
|
||||
check("PRECONDITION: this fixture reaches the marker through the `lost` guard "
|
||||
"and ONLY that one - two keys in `kept`, two in `lost`, `misdirected` "
|
||||
"empty. If it ever stops having a non-empty `kept` the mutation below "
|
||||
"goes invisible again, so the shape is asserted rather than assumed",
|
||||
_rep8.ran and len(_rep8.kept) == 2 and len(_rep8.lost) == 2
|
||||
and not _rep8.misdirected and not _rep8.ok)
|
||||
check("⚠️ THE MARKER IS NOT STAMPED ON A MIGRATION THAT LOST A MONTH OF "
|
||||
"HISTORY, and the two keys that DID land do not buy it one. `rep.ok` is "
|
||||
"the gate and nothing weaker: stamping here would tell the next start a "
|
||||
"migration finished that dropped half of what it was moving",
|
||||
MAINT_SCHEMA_KEY not in _m8.data)
|
||||
check("...and the counterfactual, one property different: the SAME fixture on a "
|
||||
"store that does not drop writes IS stamped. So the refusal above is "
|
||||
"about the state that was lost, not about `kept` being non-empty",
|
||||
migrate_maint_keys(
|
||||
MemStore(dict(flat_store(**{
|
||||
unit_key(ROSTER[0], "phase"): CHARGE,
|
||||
unit_key(ROSTER[0], "phase_started"):
|
||||
"2026-09-03T22:00:00+00:00"}).data)),
|
||||
ROSTER[0], ROSTER).ok is True)
|
||||
|
||||
|
||||
|
||||
# --------------------------------------------------------------------------- #
|
||||
print()
|
||||
|
||||
Reference in New Issue
Block a user