Skip to content

mutation gate: kill the holes mutmut 3.8.0 exposed, and take #673 by hand - #674

Merged
LetsGetToWorkBro merged 4 commits into
mainfrom
claude/brain-retention-lifecycle-jp7nzv
Sep 17, 2026
Merged

LetsGetToWorkBro merged 4 commits into
mainfrom
claude/brain-retention-lifecycle-jp7nzv

Conversation

@LetsGetToWorkBro

Copy link
Copy Markdown
Owner

two things from the post-vacation sweep: the last dependabot item, and the mutation gate the triage loop flagged in #637.

the mutation gate went red on unchanged code, and it was right to

#637 caught it: mutation.yml failed 09-14 against the same commit that passed 09-07, and since that job isn't a PR gate every PR since showed a full row of green.

mutmut 3.8.0 (released 09-12) is the whole explanation. it fixed "methods of decorated classes are not mutated" and added ternary-condition mutation, so the net widened by 37 mutants. reproduced both versions locally before touching a ceiling — 3.7.0 gives exactly the documented 229/15/1, 3.8.0 gives 245/22/1.

the 23 new survivors were 20 dataclass __str__ mutants and 3 ternary ones. seven came back no tests — never executed by anything. the reason is CLAUDE.md #1 wearing a new hat:

assert isinstance(rep, FlashReport) and rep.ok, str(rep)

that's the only str(rep) in the killer suites, and it's an assert message — python evaluates it only when the assert fails. on every green run it never ran. so FlashReport.__str__, which renders "FLASH-SAFE" if self.ok else "FLASH RISK" — the eye-safety verdict a human reads — had no guard at all.

21 of the 23 are killed, not accommodated:

  • test_report_strings.py executes all three __str__ methods and asserts both directions of every verdict. heads pinned with startswith and violation lines by equality, not in — an in check passes on [XXFLASH-SAFEXX] and on a report joined with "XX\nXX".
  • the third ternary mutant was a real hole: (t.target == SELF) or True collapses every timeout hop into a self-loop, and a ring of equal scenes can't see it (2 emits/2s reads like 1 emit/1s). an asymmetric cycle can — one fast emitting scene + one slow silent one sustains 1 emit per 10.1s, under the 1/s budget, while the fast scene alone as a self-loop is 10/s. the mutant invents a flood in a figment that has none. mutation-verified per CLAUDE.md feat(reality-compiler): NL → Halo behavior pipeline (intent parser, codegen, emulator, validator) #2: committed first, applied it, confirmed exactly that test fails, restored from the repo root.

so flash_safety returns to its original 15 and budgets lands at 231, not 245. the two accepted are itemized in place with why each is equivalent.

also corrected: privacy's ceiling had been passing on PrivacyGate.__init__'s _incognito = None while the comment named set_incognito's bool(on) — right reasoning, wrong line.

ran the workflow's own gate logic against the measured results: all-OK, exit 0.

#673: insightface 2.0

dependabot couldn't relock, so the lock-freshness gate blocked it as designed. the bump needed no proving because CI had already proved it unnoticed: real-models.yml installed insightface unpinned while the face extra capped it at <2, so when 2.0 shipped 09-08 the weekly job silently began exercising a forbidden version — run 34837133098 installed insightface-2.0, ran every real_model test with zero skips against the real buffalo_l model, and passed.

read the 2.0 wheel to confirm the adapter survives: providers is no longer a named param of FaceAnalysis.__init__ but is still honoured via **kwargs; prepare()/get() unchanged.

every entry on that install line now carries its bound — the comment above it has claimed "with the project's own bounds" all along and insightface was the one entry with none. the lock takes 2.0 so bound, lock and tested version finally agree, and it shrinks the graph: easydict and prettytable drop out, the duplicate albumentations/albucore forks collapse, 473 → 469 packages.


ruff + mypy clean (843 files). local suite has 42 failures from missing optional wheels in this container (c2pa, keyring, zeroconf) — verified identical on origin/main with these commits absent, so they're environmental, not from this change. CI has the full set.


Generated by Claude Code

…d them

mutmut 3.8.0 (2026-09-12) fixed a bug where methods of decorated classes
were never mutated. That made __str__ on FlashReport, BudgetReport and
Violation mutable for the first time and turned the weekly mutation job
red on unchanged code — 20 new survivors, 7 of them "no tests", meaning
no selected test had ever executed those lines.

The reason is CLAUDE.md #1 in a new disguise. test_flash_safety.py has
always contained

    assert isinstance(rep, FlashReport) and rep.ok, str(rep)

which reads like coverage of __str__ and is not: Python evaluates an
assert's message only when the assertion FAILS, so on every green run
that str(rep) never ran. The one apparent reader never read.

What that left unguarded is not cosmetic. FlashReport.__str__ renders
"FLASH-SAFE" if self.ok else "FLASH RISK" — the eye-safety verdict, in
the words a human reads — so a mutant inverting it prints FLASH-SAFE
over a figment the analyzer rejected. BudgetReport.__str__ has the same
conditional head plus the lines enumerating the violations.

test_report_strings.py executes all three for real and asserts both
directions of every verdict. The heads are pinned with startswith and
the violation lines by equality, not "in": an "in" check passes on a
head mutmut has wrapped to [XXFLASH-SAFEXX] and on a report joined with
"XX\nXX". It is listed in [tool.mutmut] because a killer suite mutmut is
not told to run cannot kill anything.

Signed-off-by: LetsGetToWorkBro <info@labyrinth.vision>
mutmut 3.8.0 also added "Mutate the condition of ternary expressions",
and one of the conditions it reached was the SELF rewrite in
_cycle_analysis:

    target = sid if t.target == SELF else t.target

Mutated to "(t.target == SELF) or True", every timeout hop collapses
into a self-loop — and it survived every test in the file. A ring of
equal scenes cannot see it: s0 to s1 to s0 at 2 emits / 2 s reads
exactly like s0 to s0 at 1 emit / 1 s.

An asymmetric cycle sees it at once. One fast emitting scene and one
slow silent one sustain 1 emit per 10.1 s, well under the 1/s budget,
while the fast scene read alone as a self-loop is 10 emits/s — so the
mutant invents a flood in a figment that has none, which on the
wearer's side is a Repertoire refusing to compile something safe.

Mutation-verified per CLAUDE.md #2: committed first, applied the
mutation, confirmed exactly this test fails (rate 10/s against the
expected 0.0990), restored from the repository root.

Signed-off-by: LetsGetToWorkBro <info@labyrinth.vision>
The weekly job went red on 2026-09-14 against a commit that was green on
09-07, with no diff between them. mutmut 3.8.0 (released 09-12) is the
whole explanation: it fixed "methods of decorated classes are not
mutated" and added ternary-condition mutation, so the net widened by 37
mutants and 23 more survived.

Reproduced both versions locally before touching anything: 3.7.0 gives
exactly the documented 229/15/1, 3.8.0 gives 245/22/1. The delta is 20
dataclass __str__ mutants (7 of them never executed by any test) plus 3
ternary-condition ones.

Twenty-one of the twenty-three are now KILLED rather than accommodated
(test_report_strings.py, and the asymmetric-cycle test in
test_budgets_cycle_math.py), which is why flash_safety returns to its
original 15 and budgets lands at 231 rather than 245. The two that are
accepted are itemized in place, with the reason each is equivalent.

Also corrected: privacy's single documented survivor is
PrivacyGate.__init__ setting _incognito to None, not set_incognito's
bool(on) coercion — right reasoning, wrong line, and the ceiling had
been passing on a mutant the comment did not name.

The header now says what to do when this goes red with no code change,
since the bound on mutmut stays wide on purpose: a wider net finding
untested code is the gate working, and raising a ceiling to match it
without reading the new survivors is how a gate gets muted.

Signed-off-by: LetsGetToWorkBro <info@labyrinth.vision>
Dependabot proposed widening the face extra to insightface <3 and could
not relock, so the lock-freshness gate blocked it exactly as designed.
Taken here with the relock.

The bump needed no proving, because CI had already proved it without
anyone noticing. real-models.yml installed insightface UNPINNED while
the face extra capped it at <2, so when 2.0 shipped on 2026-09-08 the
weekly job silently began exercising a version the project forbade —
run 34837133098 (09-14) installed insightface-2.0, ran every real_model
test with zero skips against the real buffalo_l model, and passed.

Read the 2.0 wheel to confirm the adapter's surface survives: providers
is no longer a named parameter of FaceAnalysis.__init__ but is still
honoured through **kwargs, and prepare()/get() keep their signatures.

So every entry on that install line now carries its bound. The comment
above it has claimed "with the project's own bounds" all along, and
insightface was the one entry with none — a job that tests what nobody
can install is testing the wrong thing, in either direction.

The lock takes 2.0 rather than keeping 0.7.3, so the declared bound, the
lock and the version CI exercises finally agree. It also shrinks the
graph: easydict and prettytable drop out and the duplicate
albumentations/albucore forks collapse, 473 packages to 469.

Signed-off-by: LetsGetToWorkBro <info@labyrinth.vision>
@LetsGetToWorkBro
LetsGetToWorkBro merged commit 964f899 into main Sep 17, 2026
15 checks passed
@LetsGetToWorkBro
LetsGetToWorkBro deleted the claude/brain-retention-lifecycle-jp7nzv branch September 17, 2026 05:37
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant