Skip to content

docs(checklist): rule 47 — a mutation has to be reached by the arm's own trace - #2036

Merged
lilyshen0722 merged 1 commit into
mainfrom
kai/rule-46-mutation-reachability
Sep 30, 2026
Merged

lilyshen0722 merged 1 commit into
mainfrom
kai/rule-46-mutation-reachability

Conversation

@lilyshen0722

@lilyshen0722 lilyshen0722 commented Sep 30, 2026 •

Copy link
Copy Markdown
Contributor

Docs-only: one rule appended to docs/development/review-checklist.md, cut from 03c17da6. The head also carries the fix from rhea's 75696 hold — the same commit, one file.

Rule 47 — a mutation has to be sited in a statement the arm's own trace reaches.

Rule 45 asks where an edit landed and pins it with file, line and enclosing symbol. It passes on a mutation that landed in code nothing executes, and the resulting green is indistinguishable from an unpinned arm — so the mutant is recorded as a survivor, and a survivor recorded as an equivalence is a false claim about the code. Rule 47 adds the half rule 45 cannot see: the edit must sit on the path the named arm takes, so the arm's trace reaches it. Print the site and confirm the arm's path includes it.

The consequence for equivalence claims is the load-bearing half: "nothing died because nothing ran" is not an equivalence, and an equivalence is a measured statement about the code — so a survivor stays unclassified until it is investigated. Three outcomes, not two.

  • INSTRUMENT DEFECT — the edit cannot run on the arm's path (a statement after a return, a value nothing reads). The reachability that was missing goes in the record.
  • A test gap — the edit runs, changes the result the arm's path computes, and the suite stays green anyway: the arm's assertion is weaker than the behaviour it names. result = n + 1 mutated to n + 2 under an assert(result > 1) executes, changes the value, and passes both ways — nothing about that mutant is unreachable or inert, and filing it as an instrument defect disposes of a finding against the code.
  • A proven equivalence — only the third outcome, and it needs the most evidence: the mutant shown reached and shown semantically unchanged.

A ledger's own anchor-count assertion catches none of this: the anchors match, which is why this is a sibling of 45 rather than a rider on the mutation-discipline rules — every check those send you to run passes here.

Earned: 2026-09-29, TASK-172 §10 step 6 (#2035 at a48fdfbe). The first cut of the arm asserting that a failed provider revoke is reported as a failed removal appended its mutation after the return that had already answered the question, and the first cut of the arm asserting that unreadable material refuses rather than deletes appended void 0;. Both then sat in a 20-mutant ledger as survivors, and both passed rule 45's site check, which printed connectionRemovalService.ts:226 in export const removeConnection for work that could not run. Rewritten to change the value the branch returns and to hoist the read above its guard, both died on the arm that names them. Nothing distinguished the two greens from a genuinely unpinned arm — including the honest reading that a survivor is a question rather than an equivalence, which saved this case only because the survivor was asked about.

Numbering. #2034 landed its own rule 46 (an arm's verdict is its total against BASE, not the word failed) under the new heading ## Reading a mutation's result while this was in gate, so this rebased from abe19fe0 onto 03c17da6 and renumbered 46 → 47, sitting below theirs under its own heading ## Reaching a mutation's site — numbers ascend in file order, so a rename alone would have filed this rule under the other one's subject.

Guard at the current head: ✓ docs/development/review-checklist.md: 47 rules, numbers 1..47 ascending with no gap, 42 citation(s) all resolve, and no rule changed its number or its name.

@samxu01
samxu01 force-pushed the kai/rule-46-mutation-reachability branch from cb599cd to 76a47e3 Compare September 30, 2026 01:09
@lilyshen0722 lilyshen0722 changed the title docs(checklist): rule 46 — a mutation has to be reached by the arm's own trace docs(checklist): rule 47 — a mutation has to be reached by the arm's own trace Sep 30, 2026
…own trace (TASK-172)

Rule 45 asks WHERE a mutation landed; this asks whether the arm can reach it.
A mutant that applies, passes the site check, and sits on a statement the arm's
trace never executes greens for a reason that reads as "this arm is unpinned" —
a finding filed against a correct arm. A zero-kill mutant is an INSTRUMENT
DEFECT until it is shown to be reached and semantically unchanged; "nothing died
because nothing ran" is not an equivalence.

Renumbered from 46 to 47: #2034 landed its own rule 46 (an arm's verdict is its
total against BASE) under a new heading, so this one sits below it with its own
heading. Numbers ascend in file order — a rename alone would have filed this
rule under the other one's subject.

Earned 2026-09-29, TASK-172 §10 step 6 (#2035 at a48fdfb).

Rhea's gate (75696) found a misclassification: a reached, non-equivalent
survivor caused by weak assertions is not an instrument defect. The rule now
keeps a survivor unclassified until it is investigated and names three outcomes
— proven equivalent, instrument defect, test gap — with n + 1 -> n + 2 under
assert(result > 1) as the test-gap counterexample: it executes, changes the
result, and passes both ways.
@samxu01
samxu01 force-pushed the kai/rule-46-mutation-reachability branch from 76a47e3 to 75737e4 Compare September 30, 2026 01:11

@lilyshen0722 lilyshen0722 left a comment

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

DOCS GATE: PASS @ 75737e4a (rule 47, TASK-172). One file, +4/−0, append-only with a new ## Reaching a mutation's site heading. Merge base 03c17da6.

The guard, and the half of it that does not do what its message says

node scripts/verify-numbered-rules.js --file docs/development/review-checklist.md --previous <main's copy>
✓ 47 rules, numbers 1..47 ascending with no gap, 42 citation(s) all resolve,
  and no rule changed its number or its name.

I checked that this discriminates rather than trusting the tick — three arms:

arm result
renumber 47. → 48. 1 numbering problem
change rule 46's lead (an existing rule's name) 1 numbering problem
change #2035 → #9999 in your earned-parenthetical ✓ … 42 citation(s) all resolve

The third one matters and it is not a defect in your PR. "42 citations all resolve" is about rule N / rules N–M cross-references inside the file (the script's own header says so at line 21). It does not validate PR numbers, shas, file paths or line numbers, so a reader who sees that tick and infers the provenance was checked will be wrong. Which is why I checked yours by hand.

Provenance, verified by hand because nothing else does it

  • a48fdfbe resolves on the remote — a48fdfbe0b6c, committed 2026-09-30T00:00:08Z, "TASK-172 §10 step 6: one removal sequence, and a revoke that names its kind".
  • At that sha, backend/services/connectionRemovalService.ts:226 is the line return { — literally the return the entry says the mutation was appended after.
  • The enclosing symbol is right too: export const removeConnection = async (options: { opens at line 158, so 226 is inside it. Your printed site connectionRemovalService.ts:226 in export const removeConnection is accurate in all three parts.

The argument, checked rather than accepted

Rule 41's test holds, and the entry states it correctly: 45 asks where the edit landed, 47 asks whether the arm's path reaches it, and each passes while the other fails. That is a genuine independence rather than a rhetorical one — 45's site check printed a correct file, line and enclosing symbol for work that could not execute, which is your own incident and it is the cleanest possible demonstration.

The three-outcome refinement is the load-bearing part and it is right. The distinction between unreachable (instrument defect) and reached, changes the value, still green (test gap) is exactly the one that gets collapsed, and collapsing it the wrong way "disposes of a finding against the code" — your phrase, and it is the cost that makes the rule worth its number. The result = n + 1 → n + 2 under assert(result > 1) example carries it: it executes, it changes the value, and it passes both ways, so nothing about it is inert.

It composes with rule 46 rather than overlapping it, which is worth saying because they arrived hours apart on the same subject: 46 is about the aggregate (Tests: total vs BASE, and what an unexplained drop can be), 47 is about an individual mutant (a survivor is a question until investigated). Neither subsumes the other.

One thing that is not yours to fix, and one drafting note

git merge-tree --write-tree on this head and #2039's df67e927 exits 1 with CONFLICT (content): Merge conflict in docs/development/review-checklist.md. Both edit the file's tail — you append 47 after 46, #2039 rewrites 46's own line — so whichever lands second needs a rebase. Neither is wrong and no renumbering is at risk in either order. I own the miss that let two PRs sit on this file at once: my collision scan swallowed a failed gh pr diff and reported the file free while yours was already open. Corrected on TASK-209 and TASK-214.

Drafting note, take it or leave it: the entry uses "three" for two different trichotomies a few lines apart — three measured shapes of unreachable mutation, then three outcomes for a survivor. Both are correct; a reader skimming for "the three" will find the wrong one.

Checks at this head: 13 pass / 2 skipping, Tests success, CLEAN / MERGEABLE. Nothing pending, nothing red.

@lilyshen0722

Copy link
Copy Markdown
Contributor Author

Not pressing this yet. It conflicts with #2039 in review-checklist.md (git merge-tree 3f0c6e0b 75737e4a exits 1), and #2039 is in the queue first, as sprint-review suggested. Once #2039 lands, rebase this append onto main. The re-gate is a carry if the rule text is unchanged. Then post the press ask and I will queue it.

Merged via the queue into main with commit cb53184 Sep 30, 2026
23 checks passed
samxu01 pushed a commit that referenced this pull request Sep 30, 2026
…ASK-214)

Rebased onto main after #2036 landed rule 47 as cb53184, which took the
press ahead of this PR and left it DIRTY. Rule 47 is preserved untouched;
only rule 46's line moves, and no renumbering is needed — main runs
45, 46, 47.

Collapses the branch's three commits into one, because each rewrote the
same single line and the last one already contained all three:

1. The remedy is two steps, not one. As shipped, rule 46 said to treat a
   Tests-total mismatch as "a broken instrument rather than a result".
   Too strong: on #2038 at 7271de4 an arm renaming
   `@media (max-width: 680px)` to 681px moved the total 981 -> 978, and
   the cause was a GENUINE red — landingAnchorInsets.test.ts builds its
   fixture at module scope with a private helper that throws when the
   at-rule is absent, so the suite failed to collect and its three tests
   left the total. A module-scope throw fails to collect for the same
   reason a syntax error does, so the `Tests:` line cannot separate a
   corrupted tree from a real collection-time failure. Flag, then find
   which suites' counts moved, before reporting a green OR a defect.

2. Two things the summary hides, from sprint-impl's independent run at the
   same head: the SUITE total does not move (88 -> 88; only the Tests
   total drops), and the comparator is the TREE, not the branch name —
   main 03c17da read 980 where that head read 981.

3. The provenance names both rows. `(#2038 at 7271de4, TASK-214)` read
   as if #2038 were TASK-214; it is TASK-213's PR, and TASK-213 appeared
   nowhere in the file.

Guard in CI's mode against main: 47 rules, 1..47 ascending with no gap,
42 citations all resolve, no rule changed its number or its name.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
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