Summary
scripts/scenario/mutate_scenario.py flips three operator pairs and no more:
for original, flipped in ((" == ", " != "), (" !~ ", " ~ "), (" ~ ", " !~ ")):
!= is a destination but never a source. So an assertion written
expect ok field X != Y is never mutated at the operator, and its only mutant
is the ok→err kind flip — which is caught by the reply's kind, not by
anything the comparison itself measures. The comparison is, for mutation
purposes, unverified: an != that would pass against literally any value
(because the named field is never equal to the constant, for a reason
unrelated to what the file claims) survives the whole mutation run silently.
The mutator's own docstring names the pairs it flips as
"==↔!=, ~↔!~" — the ↔ says bidirectional, and only one
direction is implemented.
Scope in the shipped corpus
13 assertions across four files, on this branch:
scripts/scenario/scenarios/bookmarks/the-live-model-cap-is-reached.scenario:52:expect ok field @modelId != 0
scripts/scenario/scenarios/bookmarks/the-live-model-cap-is-reached.scenario:816:expect ok field @modelId != 0
scripts/scenario/scenarios/bookmarks/the-live-model-cap-is-reached.scenario:863:expect ok field @modelId != 0
scripts/scenario/scenarios/ledger/bootstrap-a-book-over-the-wire.scenario:82:expect ok field id != $book
scripts/scenario/scenarios/ledger/open-account-transact-report-close.scenario:116:expect ok field status != 2
scripts/scenario/scenarios/ledger/submit-a-report-and-poll-it.scenario:69:expect ok field status != 2
scripts/scenario/scenarios/ledger/submit-a-report-and-poll-it.scenario:73:expect ok field status != 2
scripts/scenario/scenarios/ledger/submit-a-report-and-poll-it.scenario:80:expect ok field status != 2
scripts/scenario/scenarios/ledger/submit-a-report-and-poll-it.scenario:84:expect ok field status != 2
scripts/scenario/scenarios/ledger/submit-a-report-and-poll-it.scenario:99:expect ok field status != 2
scripts/scenario/scenarios/pastebin/wire-kinds-and-typeid-refusals.scenario:39:expect ok field @modelId != 0
scripts/scenario/scenarios/pastebin/wire-kinds-and-typeid-refusals.scenario:56:expect ok field @body != "[]"
Five of the ledger ones are status != 2 (ReportStatus::Failed), which
submit-a-report-and-poll-it.scenario's own header explains was chosen
because status == 0 raced the report runner's timer. Those are the
assertions carrying that file's central claim, and the operator in them is
exactly what nothing checks.
Verification status
Reproduced. Running the mutator over
scenarios/ledger/bootstrap-a-book-over-the-wire.scenario (which has one !=
line, at 82) produces 31 mutants; line 82 contributes exactly one, the kind
flip, and no operator flip:
line 81 kind ok->err caught
line 82 kind ok->err caught
line 85 kind ok->err caught
line 85 op !~->~ caught
Every neighbouring ==/~/!~ line contributes both a kind flip and an
operator flip; line 82 contributes only the kind flip.
Not verified: whether adding the (" != ", " == ") pair leaves the shipped
corpus green. It very likely does not, and that is the point — field status != 2 mutated to field status == 2 would be a survivor if and only if the
job really has reached Failed, which it should never do, so that one should
be caught. @modelId != 0 mutated to @modelId == 0 should also be caught.
I did not run it.
Not verified: whether the same one-directional gap exists for any other
operator the runner supports. morph_scenario.py's compare handles
==, !=, ~, !~ and nothing else, so the set is closed, but I only
checked the mutator's source rather than exhausting the runner's.
What would close this
Add (" != ", " == ") to the pair list, run
python3 scripts/scenario/run_scenarios.py --mutate over every rung, and
either fix or explicitly document any assertion that then survives. A
survivor found this way is the finding, not the failure.
Summary
scripts/scenario/mutate_scenario.pyflips three operator pairs and no more:!=is a destination but never a source. So an assertion writtenexpect ok field X != Yis never mutated at the operator, and its only mutantis the
ok→errkind flip — which is caught by the reply's kind, not byanything the comparison itself measures. The comparison is, for mutation
purposes, unverified: an
!=that would pass against literally any value(because the named field is never equal to the constant, for a reason
unrelated to what the file claims) survives the whole mutation run silently.
The mutator's own docstring names the pairs it flips as
"
==↔!=,~↔!~" — the ↔ says bidirectional, and only onedirection is implemented.
Scope in the shipped corpus
13 assertions across four files, on this branch:
Five of the ledger ones are
status != 2(ReportStatus::Failed), whichsubmit-a-report-and-poll-it.scenario's own header explains was chosenbecause
status == 0raced the report runner's timer. Those are theassertions carrying that file's central claim, and the operator in them is
exactly what nothing checks.
Verification status
Reproduced. Running the mutator over
scenarios/ledger/bootstrap-a-book-over-the-wire.scenario(which has one!=line, at 82) produces 31 mutants; line 82 contributes exactly one, the kind
flip, and no operator flip:
Every neighbouring
==/~/!~line contributes both a kind flip and anoperator flip; line 82 contributes only the kind flip.
Not verified: whether adding the
(" != ", " == ")pair leaves the shippedcorpus green. It very likely does not, and that is the point —
field status != 2mutated tofield status == 2would be a survivor if and only if thejob really has reached
Failed, which it should never do, so that one shouldbe caught.
@modelId != 0mutated to@modelId == 0should also be caught.I did not run it.
Not verified: whether the same one-directional gap exists for any other
operator the runner supports.
morph_scenario.py'scomparehandles==,!=,~,!~and nothing else, so the set is closed, but I onlychecked the mutator's source rather than exhausting the runner's.
What would close this
Add
(" != ", " == ")to the pair list, runpython3 scripts/scenario/run_scenarios.py --mutateover every rung, andeither fix or explicitly document any assertion that then survives. A
survivor found this way is the finding, not the failure.