[Bug] The mutation sweep has a survivor: the checklist-scope predicate is untested or dead #660

Closed
opened 2026-07-22 17:30:46 +00:00 by brenno · 2 comments
Owner

Found while dating the mutation-testing claim for #616 — the sweep was run rather than assumed, and it does not come back clean.

Reproduce: make mutate-parsers

Result (2026-07-22): 26 mutants, one survivor, and the sweep halts there so the remaining five of the seven target files never run.

1 survivor(s) to review (dead or untested predicate):
  lib/services/markdown_service_finding.dart:53  if (content.startsWith('ocideck_checklist_scope:')) {

What a survivor means here. tool/mutation_check.dart negates each String.startsWith/endsWith predicate and reruns the tests. A mutant that survives is a predicate whose two branches no test distinguishes: either it is dead code, or the behaviour behind it has no test. For a Markdown parser predicate that is the second one often enough to be worth checking — ocideck_checklist_scope: is how a checklist slide's scope object round-trips, so a silent break there loses a field on save/load.

Two things to settle:

  1. Is the predicate reachable? If it is dead, remove it. If it is live, add a round-trip test that carries a checklist slide with a scope object through parse and serialise.
  2. The halt-on-first-survivor behaviour means one survivor hides everything after it. Worth considering whether the target should report all seven files and fail at the end, so the picture is complete instead of truncated.

Why this is a good first issue: it is one predicate, one test file, and the tool tells you exactly when you have fixed it. No knowledge of the rest of the codebase required.

Context: #616 now records the real scope and this real result in CONTRIBUTING.md and assurance/CRA-2024-2847-positie.md — the numbers there are not rounded to green, so this issue is what makes them green.

Found while dating the mutation-testing claim for #616 — the sweep was run rather than assumed, and it does not come back clean. **Reproduce:** `make mutate-parsers` **Result** (2026-07-22): 26 mutants, **one survivor**, and the sweep halts there so the remaining five of the seven target files never run. ``` 1 survivor(s) to review (dead or untested predicate): lib/services/markdown_service_finding.dart:53 if (content.startsWith('ocideck_checklist_scope:')) { ``` **What a survivor means here.** `tool/mutation_check.dart` negates each `String.startsWith`/`endsWith` predicate and reruns the tests. A mutant that survives is a predicate whose two branches no test distinguishes: either it is dead code, or the behaviour behind it has no test. For a Markdown parser predicate that is the second one often enough to be worth checking — `ocideck_checklist_scope:` is how a checklist slide's scope object round-trips, so a silent break there loses a field on save/load. **Two things to settle:** 1. Is the predicate reachable? If it is dead, remove it. If it is live, add a round-trip test that carries a checklist slide with a scope object through parse and serialise. 2. The halt-on-first-survivor behaviour means one survivor hides everything after it. Worth considering whether the target should report all seven files and fail at the end, so the picture is complete instead of truncated. **Why this is a good first issue:** it is one predicate, one test file, and the tool tells you exactly when you have fixed it. No knowledge of the rest of the codebase required. Context: #616 now records the real scope and this real result in `CONTRIBUTING.md` and `assurance/CRA-2024-2847-positie.md` — the numbers there are not rounded to green, so this issue is what makes them green.
Author
Owner

Opgepakt. Tak: fix/checklist-scope-mutant-660. Reikwijdte: het mutate-parsers-doel in de Makefile, plus de twee plekken die het oude getal noemen (CONTRIBUTING.md, assurance/CRA-2024-2847-positie.md).

Opgepakt. Tak: `fix/checklist-scope-mutant-660`. Reikwijdte: het `mutate-parsers`-doel in de Makefile, plus de twee plekken die het oude getal noemen (`CONTRIBUTING.md`, `assurance/CRA-2024-2847-positie.md`).
Author
Owner

Opgelost in 75c4d404 (PR #678), op main.

Punt 1 — het predicaat is niet dood. Het is gedekt, door test/checklist_spec_test.dart: dat haalt een checklistdia mét scope-object door generateDeck en parseDeck en toetst dat out.checklistScope er weer uitkomt. Dat bestand stond alleen niet in de lijst tests die de sweep voor dít doel opnieuw draait. De ronde-trip-test die je vroeg bestond dus al; wat ontbrak was dat de sweep ernaar keek. Dat bestand staat nu in de regel voor markdown_service_finding.dart.

Punt 2 was het grotere, en je had gelijk dat het de moeite waard was. Eén make-regel per bestand betekent stoppen bij de eerste fout, dus vijf van de zeven doelen draaiden nooit — en "26 mutanten" was daarmee niet het aantal mutanten maar het aantal dat het tot de eerste stop haalde. Het doel telt nu de mislukkingen op en faalt aan het eind.

Uitkomst: 51 mutanten over zeven doelen, nul overlevers. Dat getal staat in CONTRIBUTING.md en in de CRA-positiebepaling, mét de vermelding dat het vorige getal een artefact was — een sweep die zijn eigen uitkomst afkapt is een sweep waarvan je de uitslag niet kunt geloven, en dat hoort er niet stilzwijgend uit te verdwijnen zodra hij groen staat.

Daarmee zijn de twee cijfers uit #616 groen zonder dat ze zijn afgerond.

Opgelost in `75c4d404` (PR #678), op main. **Punt 1 — het predicaat is niet dood.** Het is gedekt, door `test/checklist_spec_test.dart`: dat haalt een checklistdia mét scope-object door `generateDeck` en `parseDeck` en toetst dat `out.checklistScope` er weer uitkomt. Dat bestand stond alleen niet in de lijst tests die de sweep voor dít doel opnieuw draait. De ronde-trip-test die je vroeg bestond dus al; wat ontbrak was dat de sweep ernaar keek. Dat bestand staat nu in de regel voor `markdown_service_finding.dart`. **Punt 2 was het grotere, en je had gelijk dat het de moeite waard was.** Eén `make`-regel per bestand betekent stoppen bij de eerste fout, dus vijf van de zeven doelen draaiden nooit — en "26 mutanten" was daarmee niet het aantal mutanten maar het aantal dat het tot de eerste stop haalde. Het doel telt nu de mislukkingen op en faalt aan het eind. **Uitkomst: 51 mutanten over zeven doelen, nul overlevers.** Dat getal staat in CONTRIBUTING.md en in de CRA-positiebepaling, mét de vermelding dat het vorige getal een artefact was — een sweep die zijn eigen uitkomst afkapt is een sweep waarvan je de uitslag niet kunt geloven, en dat hoort er niet stilzwijgend uit te verdwijnen zodra hij groen staat. Daarmee zijn de twee cijfers uit #616 groen zonder dat ze zijn afgerond.
Sign in to join this conversation.
No milestone
No project
No assignees
1 participant
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set

Reference
LibreKAT/Ocideck#660
No description provided.