tri gates mutate: the boundary scanner never left the control function (Refs #2161) - #2663
Merged
Conversation
…n (Refs #2161) `--boundary` reported 31 sites for tools/gft_backprop_microcode.py, and an independent tokeniser counted 31 comparisons before `if __name__`. The numbers agreed and the story wrote itself: the operator declines to mutate a file's own self-test. Both numbers were real and the agreement was a coincidence. Asking for the site LINES instead of the count showed the scan ending at 371 -- nine lines before `__main__`, at `def self_check():`. `is_control_fn` sets `in_control` and `boundary_sites` never reset it, so everything from 380 to end of file had silently never been mutated. 31 -> 62 sites, which is the tokeniser's count for the whole file. Three of four site finders already carried this fix (T125). They are line-oriented; this one is byte-oriented, so it had no line to attach to when `--boundary` was added. The motivating file cannot test the other half: `self_check` there holds zero comparisons. A synthetic helper/control/`__main__` source covers all three answers, and reverting the fix makes it fail with `[2]`. Also in this commit: * `_magsub`: assert `sticky == 0` at every tie. The arm below it is the addition rule in the subtraction path and is correct only because it never runs; this makes waking up loud without deciding what the rule should be (that is 30 specs, #2652). Positive control: waking the detector fires it. * `tri pointers`: `(?![\w])` restored -- without it `.v` matched inside `docker/Dockerfile.vivado` and the tool's own first run invented a dead pointer. The guard was in the exploratory version and lost in the rewrite. * `tri pointers`: dead pointers are now split by history into NEVER (no commit ever -- the pointer was wrong when written) and REMOVED (stale, and the history says where it went). 12 and 2. Both REMOVED ones were moved by one docs restructure and are fixed here, taking that class to zero.
Contributor
|
📓 NotebookLM Notebook linked to this PR
This notebook contains session context, decisions, and artifacts for this work. |
Contributor
PR DashboardGenerated at: 2026-08-24 04:25:51 UTC
Summary
Seal Status
|
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
--boundaryreported 31 sites fortools/gft_backprop_microcode.py. An independent tokeniser counted 31 comparisons before theif __name__ == "__main__":block. Two numbers agreed, and the story wrote itself: the operator sensibly declines to mutate a file's own self-test.Both numbers were real. The agreement was a coincidence.
Asking the tool for the site lines instead of the count showed the scan ending at line 371 — nine lines before
__main__, atdef self_check():.is_control_fnsetsin_control, andboundary_sitesnever resets it, so everything from line 380 to the end of the file had silently never been mutated.31 → 62 sites, which is exactly the tokeniser's count for the whole file.
When two measurements agree, check what they agree about
The tokeniser answered "how many comparisons precede
__main__". The tool answered "how many sites did I find before I stopped". Nothing connected the two but an integer.What broke the tie was not a third opinion — it was asking for more structure. A total can coincide; a range cannot lie about where it stopped. Prefer a list over a count, a range over a total, a witness over a verdict.
A bug fixed three times, live in the fourth place
Three of four site finders already carried this, in these words:
assert_sites,mutable_sitesandinvert_sitesare line-oriented and got it.boundary_sitesis byte-oriented — it tracks quotes and comments character by character — so when--boundarywas added the fix had no line to attach to.The motivating file could not test the fix
After the change: 62 sites, none inside
self_check's body — correct. Butself_checkin that file has zero comparisons, so the exclusion half was never exercised by the file that prompted the work. A synthetic helper / control /__main__source covers all three answers, and reverting the fix makes it fail with[2].A regression test written from the motivating file tests only the half that was broken.
Also here
_magsubassertssticky == 0at every tie. The arm below it is the addition rule in the subtraction path, correct only because it never runs. This makes waking up loud without deciding what the rule should be — that is 30 specs and belongs to #2652. Positive control: waking the detector fires it.tri pointersregained(?![\w]). Without it.vmatched insidedocker/Dockerfile.vivado, and the tool's own first run invented a dead pointer to a file nobody had ever named. The guard was in the exploratory version and lost in the rewrite — the cheapest kind of regression and the hardest to see in a diff.Dead pointers are now split by history:
NEVERREMOVEDBoth
REMOVEDrows were moved by a single docs restructure and are fixed here.board/bpseq.v, which occasioned the tool, wasNEVER— and I had read it asREMOVEDwithout checking, which is how it took a decision with it.Prior art, checked and not adopted
mutmutandcosmic-raydo not attempt equivalent-mutant detection at all. Stryker hasdisablecomments carrying a reason string — the same shape as# mutant-equivalent:, and likewise unverified. So refuting the annotation (#2656) is the delta, not catching up.Trivial Compiler Equivalence was measured on this tree rather than assumed: zero among real operator mutants. A first pass reported 95 of 527 until I noticed it was mutating comments, which vanish at compile time and therefore always "compile identically". Not building it; recorded so a later tick does not re-chase.
Refs #2161