Skip to content

docs(skills): refactor-protocol — two more ways a mutation battery misleads - #518

Merged
JArmandoAnaya merged 1 commit into
mainfrom
docs/mutation-lessons
Aug 10, 2026
Merged

docs(skills): refactor-protocol — two more ways a mutation battery misleads#518
JArmandoAnaya merged 1 commit into
mainfrom
docs/mutation-lessons

Conversation

@JArmandoAnaya

Copy link
Copy Markdown
Contributor

Mutation verification has earned its place in refactor-protocol several times over, and two more of its failure modes have now cost real time. Both are recorded here, in the skill's own voice, beside the three ways a mutation harness already lies.

The harness must not share a failure path with the tests it runs

This joins the existing list, which grows from three ways to four. A mutation is expected to make a command fail, so a battery that chains its steps on success discards its own cleanup at exactly the moment the cleanup matters. The recorded case ran mutate && run && revert with the test output piped through head: head closes the pipe, the runner takes SIGPIPE, pipefail makes the whole pipeline non-zero, and the && short-circuits before the revert ever runs. Four of eight reverts silently never executed, the mutations stacked in the tree, and the next run's red read like a broken implementation rather than a broken harness.

The rules the entry states: every step is its own unconditional statement rather than a link in an && chain; the harness asserts a clean tree before each case and refuses to continue on a dirty one; an empty recorded patch fails loudly instead of passing as a no-op; and test output goes to a file you grep afterwards rather than through anything that can close a pipe underneath the runner.

The first entry in the list — commit the work before the first mutation — gains the same episode as a second example, because it is what made the stacked tree recoverable: with the finished work on a commit, six accumulated mutations cost one git reset --hard HEAD and nothing else. That rule was written for a directory-wide revert eating uncommitted work; it turns out to cover the opposite accident too.

A green mutation is a claim about one spelling, not about the rule

This is a new top-level entry rather than a fourth item in that list, because it is not a way the harness lies — it is a way a correct harness's green result gets read wrong. A guard enforced at more than one site survives any single-site mutation with the suite still green, and the conclusion that reads as honest at that point (this rule is unverifiable, or that test is redundant) is exactly wrong.

The recorded case is a cool-down scrub whose cutoff scoping lived at two sites — a grep deciding whether to rewrite the file at all, and an awk rule deciding which line to remove, both matching the same cutoff. Two single-site mutations came back green before mutating both together finally went red; stopping at the first green would have reported a guard verified that no test could see. The rule: before declaring a rule unverifiable or a test redundant, iterate spellings and mutate every site that enforces the rule.

Sources

Both entries were written from the primary records rather than from a summary. The pipe trap is the harness note in #514's body; the multi-site case is the first finding of the 2026-08-10 overnight report, whose Task 2 shipped as #507. The dispatch that requested this amendment placed the multi-site case in that report's Task 4 — the report itself puts it in Task 2, and the entry follows the report.

Test plan

The diff is one markdown file and there is no automated gate over skill prose, so the full staged check ran to prove the amendment breaks nothing rather than to exercise it.

Stage Result Exit
pytest — architecture, cli, examples, formats, inference, jobs, mcp, packaging, scripts, test_versioning.py 1022 passed, 9 skipped 0
pytest tests/kernel 1445 passed, 4 skipped 0
pytest tests/server 690 passed 0
ruff check . All checks passed 0
ruff format --check . 366 files already formatted 0
mypy src/visionset no issues in 153 source files 0
lint-imports 4 contracts kept, 0 broken 0
check.sh frontend all builds, unit suites and lint gates green 0
check.sh generated no drift in openapi.json or the generated client 0
check.sh browser 250 passed (e2e), 1 passed (cycle) 0

The pytest stages are split by test directory derived from ls tests/ at run time, per the protocol's own staging rule; every directory it listed is covered above.

This PR closes no issue. cf. #360, #362, #507, #514.

…sleads

A harness that chains its steps on success throws away its own cleanup at the
moment the cleanup matters, and a green mutation only ever speaks for the one
site it touched.
@JArmandoAnaya
JArmandoAnaya merged commit 0900d08 into main Aug 10, 2026
14 checks passed
@JArmandoAnaya
JArmandoAnaya deleted the docs/mutation-lessons branch August 10, 2026 16:01
JArmandoAnaya added a commit that referenced this pull request Aug 21, 2026
…sleads (#518)

A harness that chains its steps on success throws away its own cleanup at the
moment the cleanup matters, and a green mutation only ever speaks for the one
site it touched.
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