1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
# Equivalent mutants: each entry names a mutation that provably cannot
# change observable behavior, with the argument. Keep this list short
# and specific — a mutant goes here only after the equivalence argument
# is written down.

exclude_re = [
    # anchor(): for a unique-unique candidate pair, s being matched
    # implies d is matched and vice versa — a larger wholesale anchor
    # pairs s with its positional counterpart, whose equal content and
    # dst-side uniqueness force it to be d. Either disjunct implies
    # the other, so || and && coincide.
    'replace \|\| with && in anchor',
    # anchor(): candidates are unmatched while placed roots are
    # matched, so a candidate index never equals a placed root's and
    # < versus <= cannot differ.
    'replace < with <= in anchor',
    # refine(): a gap empty on one side produces a ZS mapping with no
    # real (Some, Some) pairs to fold; the skip is a fast path, not a
    # behavior change.
    'replace \|\| with && in refine',
    # refine(): the ZS budget is an arbitrary tuning constant; > vs >=
    # differs only for a residue of exactly 400 nodes and either
    # behavior is acceptable there.
    'replace > with >= in refine',
    # refine()'s relabel closure: if the virtual forest roots cannot
    # pair, every candidate mapping pays the same uniform +2 (delete
    # plus insert of the roots), so the optimal child mapping — the
    # only thing folded — is unchanged.
    'delete match arm \(None, None\) in refine',
    # lcs_pairs(): the fill guarantees the equal case always took the
    # diagonal, so the surviving index mutants only change *which* of
    # several equally long subsequences the backtrack walks — every
    # choice they can make is optimal. The exhaustive reference-oracle
    # test pins length and validity, which is the function's whole
    # contract; a mutant that broke either would be caught by it.
    'replace \+ with \* in lcs_pairs',
    # sibling_order_holds(): a sibling's image can never equal the
    # candidate y — y is unmatched at check time — so index equality
    # cannot occur and < versus <= coincide.
    'replace < with <= in sibling_order_holds',
    # graft_branch()'s dedupe twin search: the insert-insert rule only
    # lets equal insertion sequences through to the builder, so a
    # budget-true entry always exists for every B insert and any
    # bookkeeping that consumes each entry at most once skips exactly
    # the same set. (The hash-equality half is pinned by the
    # single-hash duplicate-statement test.)
    'replace && with \|\| in Builder<._>::graft_branch',
    # graft()'s placed/consumed guards: for a graft to meet an
    # already-placed or twice-consumed survivor, the diff would have to
    # map a node's image outside its matched ancestor's image, which
    # admissible() forbids. The guards are defense-in-depth against
    # matchings our phases cannot produce.
    'replace && with \|\| in Builder<._>::graft\b',
    # children_changed(): tree-sitter derives node-types.json from the
    # grammar, so a node whose children match its parsed origin always
    # satisfies the model; widening validation to unchanged nodes (or
    # never treating them as unchanged) cannot change outcomes on
    # parsed trees. The guard exists for cost and for grammar corners
    # deliberately kept out of merges.
    'children_changed',
    # synthesize()'s unclosed-file fallback guards: distinguishable
    # only through the cov-excl-marked defensive path (the final merged
    # leaf is in practice its origin's closing token).
    'delete ! in synthesize',
    # Solver::solve()'s backtrack tail: once one side is exhausted the
    # remaining walk emits only deletions and insertions, which the
    # mapping does not report — and the delete branch always holds
    # there, shielding the insert branch's condition.
    'replace \|\| with && in Solver<T, F>::solve',
    'replace && with \|\| in Solver<T, F>::solve',
]