scripts/mutation.sh (morph#405) reports 352 surviving mutants over
include/morph, and morph#431 and morph#432 are written against that list.
The list cannot be read site-by-site. Four survivors, sampled from three
different headers, were applied to the source by hand and every one of them
turns morph_tests red.
Verification status: measured
lane/d-framework at 18c764bc, in the same build tree
(build/mutation-core-forms) and the same configuration the run itself used —
Mull 0.34.0 / mull-ir-frontend-22 / LLVM 22.1.2, clang 22.1.8, -O0 -g,
cxx_all. For each site the mutation Mull describes (cxx_remove_void_call:
delete the call) was applied to the header, the tree rebuilt, and
./tests/morph_tests run. A survivor means the suite passes on the mutant, so
each of these should have stayed green.
| site |
Mull |
hand-applied |
core/remote.hpp:718 + :818 — reply(wire::encode(makeOk(...))) |
Survived |
34 of 1303 cases fail |
forms/forms.hpp:1981 — emitDeclaredBound(property, "minimum", *meta.minimum) |
Survived |
2 cases fail |
core/registry.hpp:709 — holder->attachIdentity(std::string{primary}) |
Survived |
2 cases fail |
Real output, the two remote.hpp reply calls deleted:
/home/yaraslau/repo/morph-wt/340/tests/test_coverage_push95.cpp:572: FAILED:
{Unknown expression after the reported line}
due to unexpected exception with message:
envelope decode failed: index 0: no_read_input
/home/yaraslau/repo/morph-wt/340/tests/test_remote_connection_scope.cpp:389: FAILED:
REQUIRE( regA.await() )
with expansion:
false
test cases: 1303 | 1269 passed | 34 failed
assertions: 21378 | 21343 passed | 35 failed
forms.hpp's and registry.hpp's, in one build together:
/home/yaraslau/repo/morph-wt/340/tests/test_forms_field_bounds.cpp:104: FAILED:
/home/yaraslau/repo/morph-wt/340/tests/test_forms_field_bounds.cpp:148: FAILED:
/home/yaraslau/repo/morph-wt/340/tests/test_registry_extra.cpp:237: FAILED:
/home/yaraslau/repo/morph-wt/340/tests/test_remote_extra.cpp:674: FAILED:
test cases: 1303 | 1299 passed | 4 failed
The clean tree at the same commit is green: All tests passed (21523 assertions in 1303 test cases).
What this costs the two tickets written against the list
morph#431's headline is "twenty places where the framework's response path can
be deleted and morph_tests stays green". It cannot: deleting two of them turns
34 cases red. The premise of that section is false, and it was the section the
ticket said to lead with.
It was tested the long way round first. tests/test_remote_reply_envelopes.cpp
(added on lane/d-framework, 20 cases) reads the full reply envelope for every
control kind dispatchMessage switches on, including both of these sites. The
re-run scored 64.76% and those survivors did not move — which is what
prompted applying the mutation by hand.
Mechanism — inferred, not verified
Every affected site is in a header compiled into many of morph_tests' 105
translation units. Each object carries its own copy of the function and the
linker keeps one. Mull embeds mutants per object (the .mull_mutants section)
and the runner enables one by id; if the copy carrying the enabled mutant is
one the linker discarded, the running program is unmutated and the mutant
scores as a survivor.
That predicts the effect is specific to header-defined code in a multi-TU
binary, which matches where the survivors sit: remote.hpp (126) and
bridge.hpp (85) are 211 of the 352, and cxx_remove_void_call is 148 of
them. It has not been confirmed against Mull's implementation — someone
should read mull-ir-frontend's emission and the runner's patching before this
is treated as understood.
Direction of the error
scripts/mutation.sh's header records a caveat in the other direction —
test_outbox.cpp names a scratch file after a stack address, so concurrent
copies can collide, a collision fails a case, and a failed case reads as a
kill. That remains true and still says the score can be too high.
This one says the score is also too low, and by a larger amount: every
false survivor is a mutant that should have counted as killed. The two are not
in tension — they are different mechanisms — but the second is the one that
decides whether 352 survivors is a backlog or an artefact.
What would change the verdict
- A sampled survivor that leaves the suite green when hand-applied would be a
real gap, and would bound how much of the list is affected. Four out of four
false positives does not prove all 352 are.
- Reproducing the run with
include/morph compiled into a single translation
unit (a one-TU test harness) would isolate the multi-TU hypothesis directly.
- If Mull has an option for this — or if a newer release fixes it — the fix is
a flag in scripts/mutation.sh, not new tests.
Until then, scripts/mutation_survivors.json records the finding next to the
two runs, and morph#431 and morph#432 should be re-scoped: their boundary-shape
findings held up and are closed, their reply(...) shape did not.
🤖 Generated with Claude Code
https://claude.ai/code/session_0154xzWuBMPveLcdeUgydifb
scripts/mutation.sh(morph#405) reports 352 surviving mutants overinclude/morph, and morph#431 and morph#432 are written against that list.The list cannot be read site-by-site. Four survivors, sampled from three
different headers, were applied to the source by hand and every one of them
turns
morph_testsred.Verification status: measured
lane/d-frameworkat18c764bc, in the same build tree(
build/mutation-core-forms) and the same configuration the run itself used —Mull 0.34.0 /
mull-ir-frontend-22/ LLVM 22.1.2, clang 22.1.8,-O0 -g,cxx_all. For each site the mutation Mull describes (cxx_remove_void_call:delete the call) was applied to the header, the tree rebuilt, and
./tests/morph_testsrun. A survivor means the suite passes on the mutant, soeach of these should have stayed green.
core/remote.hpp:718+:818—reply(wire::encode(makeOk(...)))forms/forms.hpp:1981—emitDeclaredBound(property, "minimum", *meta.minimum)core/registry.hpp:709—holder->attachIdentity(std::string{primary})Real output, the two
remote.hppreply calls deleted:forms.hpp's andregistry.hpp's, in one build together:The clean tree at the same commit is green:
All tests passed (21523 assertions in 1303 test cases).What this costs the two tickets written against the list
morph#431's headline is "twenty places where the framework's response path can
be deleted and morph_tests stays green". It cannot: deleting two of them turns
34 cases red. The premise of that section is false, and it was the section the
ticket said to lead with.
It was tested the long way round first.
tests/test_remote_reply_envelopes.cpp(added on
lane/d-framework, 20 cases) reads the full reply envelope for everycontrol kind
dispatchMessageswitches on, including both of these sites. There-run scored 64.76% and those survivors did not move — which is what
prompted applying the mutation by hand.
Mechanism — inferred, not verified
Every affected site is in a header compiled into many of
morph_tests' 105translation units. Each object carries its own copy of the function and the
linker keeps one. Mull embeds mutants per object (the
.mull_mutantssection)and the runner enables one by id; if the copy carrying the enabled mutant is
one the linker discarded, the running program is unmutated and the mutant
scores as a survivor.
That predicts the effect is specific to header-defined code in a multi-TU
binary, which matches where the survivors sit:
remote.hpp(126) andbridge.hpp(85) are 211 of the 352, andcxx_remove_void_callis 148 ofthem. It has not been confirmed against Mull's implementation — someone
should read
mull-ir-frontend's emission and the runner's patching before thisis treated as understood.
Direction of the error
scripts/mutation.sh's header records a caveat in the other direction —test_outbox.cppnames a scratch file after a stack address, so concurrentcopies can collide, a collision fails a case, and a failed case reads as a
kill. That remains true and still says the score can be too high.
This one says the score is also too low, and by a larger amount: every
false survivor is a mutant that should have counted as killed. The two are not
in tension — they are different mechanisms — but the second is the one that
decides whether 352 survivors is a backlog or an artefact.
What would change the verdict
real gap, and would bound how much of the list is affected. Four out of four
false positives does not prove all 352 are.
include/morphcompiled into a single translationunit (a one-TU test harness) would isolate the multi-TU hypothesis directly.
a flag in
scripts/mutation.sh, not new tests.Until then,
scripts/mutation_survivors.jsonrecords the finding next to thetwo runs, and morph#431 and morph#432 should be re-scoped: their boundary-shape
findings held up and are closed, their
reply(...)shape did not.🤖 Generated with Claude Code
https://claude.ai/code/session_0154xzWuBMPveLcdeUgydifb