Cover the uncovered mutants in the small directories #1698

Closed
opened 2026-11-11 16:24:24 +00:00 by jared · 2 comments
Owner

Problem

The second mutation pass (2026-11-09) left 50 uncovered mutants in 28 files under lib/os_sdlc/ (agent, artifact_dir, collaborator_pass, detector, dispatch, evidence, expected_constants, fast_gate, gate, git_repositories, handoff, handoff_content, harness_error, process_io, project, retired_test, ticket_shape, tracker, verdict). No test runs the code at these mutants. An uncovered mutant is code that the suite never executes, so a change there goes unseen. Ruling 100 puts a unit test for lib/os_sdlc/<path>.rb at test/os_sdlc/<path>_test.rb.

Observed

The second mutation pass ran bin/os-sdlc-mutation-pass run . on 2026-11-09. .mutineer/pass.json lists 50 mutants in this ticket under no_coverage. A no_coverage mutant is a changed behavior that no test runs. The survivor tickets #1656 to #1664 took only the survived mutants, so no ticket covers these. Each line below gives the file, its uncovered count, and the mutation kinds.

  • lib/os_sdlc/gate/name.rb (6): return_nil 2, statement_removal 2, condition_false 1, condition_true 1
  • lib/os_sdlc/retired_test.rb (4): condition_false 1, condition_true 1, return_nil 1, statement_removal 1
  • lib/os_sdlc/detector/reach_through/parent_answers.rb (3): boolean_literal 1, comparison 1, return_nil 1
  • lib/os_sdlc/git_repositories.rb (3): return_nil 3
  • lib/os_sdlc/harness_error.rb (3): boolean_connector 1, negation_removal 1, return_nil 1
  • lib/os_sdlc/detector/measures.rb (2): return_nil 2
  • lib/os_sdlc/evidence/code_search.rb (2): return_nil 1, statement_removal 1
  • lib/os_sdlc/evidence/fingerprint/method_probes.rb (2): return_nil 2
  • lib/os_sdlc/gate/commands.rb (2): return_nil 2
  • lib/os_sdlc/process_io.rb (2): return_nil 2
  • lib/os_sdlc/project/cli.rb (2): boolean_literal 1, return_nil 1
  • lib/os_sdlc/tracker/issue_source/shell.rb (2): return_nil 1, statement_removal 1
  • lib/os_sdlc/verdict.rb (2): comparison 1, return_nil 1
  • lib/os_sdlc/agent/type.rb (1): return_nil 1
  • lib/os_sdlc/artifact_dir.rb (1): return_nil 1
  • lib/os_sdlc/collaborator_pass/recipe_check.rb (1): return_nil 1
  • lib/os_sdlc/dispatch/rerouting.rb (1): statement_removal 1
  • lib/os_sdlc/dispatch/subagent_start/hook_payload.rb (1): return_nil 1
  • lib/os_sdlc/evidence/fingerprint.rb (1): return_nil 1
  • lib/os_sdlc/evidence/lazy_lsp_session.rb (1): return_nil 1
  • lib/os_sdlc/expected_constants.rb (1): boolean_literal 1
  • lib/os_sdlc/fast_gate/new_offense_report.rb (1): return_nil 1
  • lib/os_sdlc/gate/command_result.rb (1): return_nil 1
  • lib/os_sdlc/handoff.rb (1): return_nil 1
  • lib/os_sdlc/handoff_content.rb (1): return_nil 1
  • lib/os_sdlc/project/config_command.rb (1): boolean_literal 1
  • lib/os_sdlc/ticket_shape/fence_stack.rb (1): return_nil 1
  • lib/os_sdlc/tracker/forgejo.rb (1): boolean_literal 1

lib/os_sdlc/boot/inputs/detector_argv.rb had 3 uncovered mutants in the pass. #1646 deleted that file, so this ticket drops those 3 mutants.

lib/os_sdlc/boot/onboarding.rb had 2 uncovered mutants in the pass. That file moved to lib/os_sdlc/project/cli.rb, so this ticket lists them under the new path.

This ticket also takes one survivor, not an uncovered mutant: the Db.bind! freeze mutant at lib/os_sdlc/db.rb:25 (Sequel::Model.freeze_descendants if freeze replaced by nil, statement_removal). The cause is that test/mutation_prelude.rb:9 binds the database once with freeze: false before any mutant runs. Kill it with a test against a separate model root, or rule it equivalent with a reason. See the comment on #1683.

Reproduce

n/a: the uncovered mutants come from a whole pass. Verify with a targeted run: bin/os-sdlc-mutation-pass run <files> --no-matrix.

Approach

For each listed file, write the paired unit test at test/os_sdlc/<lib path>_test.rb (ruling 100). The test must run the uncovered code and kill its mutants. Check the older test locations first (test/cops/, test/daemon/, test/lint/, test/system_model_*). A test there may already cover the file and only need a move or an extension. Where the code calls a process, use an adapter and a recorded fixture (ruling 88). Reuse test/support/process_recording.rb and the recorded_* doubles. No test starts a real process.

When a mutant shows dead code (code no caller reaches), delete the code and write no test for it (ruling 107). When a mutant is equivalent (the mutant has the same behavior), rule it equivalent in a comment on this ticket with the reason. Follow plugins/os-sdlc/references/survivor-loop.md. Then verify with a targeted --no-matrix run over the files of this ticket. Do not run a whole pass.

Required work: none beyond the acceptance criteria.

Acceptance criteria

  1. Given a targeted --no-matrix Mutineer run on the files listed in this ticket, when the run ends, then it reports no uncovered mutant and no survivor, except ones that this ticket deletes or rules equivalent with a reason.
  2. Given a file with deleted unreachable code, when the suite runs, then it is green and no caller of the deleted code remains.

Origin

  • Trigger: #1683 split, 2026-11-11
  • Improvised this session: none
  • Chain: uncovered mutants ← survivor tickets #1656-#1664 took only survived mutants ← the second pass split only survivors into tickets ← DESIGN (docs/research/mutation-testing/2026-11-09-second-pass/)
  • Root candidate: none found; searched uncovered, no_coverage, mutant, gate, evidence, detector, tracker, dispatch, project
  • Where: lib/os_sdlc/ (agent, artifact_dir, collaborator_pass, detector, dispatch, evidence, expected_constants, fast_gate, gate, git_repositories, handoff, handoff_content, harness_error, process_io, project, retired_test, ticket_shape, tracker, verdict)
  • Parent: #1683
  • Session: 974224e0-190b-4ca9-814e-eb971a24f35a
  • Transcript: /home/jared/.claude/projects/-home-jared-dev-cc-os-plugins-os-sdlc/974224e0-190b-4ca9-814e-eb971a24f35a.jsonl

VERDICT: CREATE (ticket-skeptic, 2026-11-11): child of the #1683 required split; no open ticket covers these files.

## Problem The second mutation pass (2026-11-09) left 50 uncovered mutants in 28 files under lib/os_sdlc/ (agent, artifact_dir, collaborator_pass, detector, dispatch, evidence, expected_constants, fast_gate, gate, git_repositories, handoff, handoff_content, harness_error, process_io, project, retired_test, ticket_shape, tracker, verdict). No test runs the code at these mutants. An uncovered mutant is code that the suite never executes, so a change there goes unseen. Ruling 100 puts a unit test for `lib/os_sdlc/<path>.rb` at `test/os_sdlc/<path>_test.rb`. ## Observed The second mutation pass ran `bin/os-sdlc-mutation-pass run .` on 2026-11-09. `.mutineer/pass.json` lists 50 mutants in this ticket under `no_coverage`. A no_coverage mutant is a changed behavior that no test runs. The survivor tickets #1656 to #1664 took only the survived mutants, so no ticket covers these. Each line below gives the file, its uncovered count, and the mutation kinds. - `lib/os_sdlc/gate/name.rb` (6): return_nil 2, statement_removal 2, condition_false 1, condition_true 1 - `lib/os_sdlc/retired_test.rb` (4): condition_false 1, condition_true 1, return_nil 1, statement_removal 1 - `lib/os_sdlc/detector/reach_through/parent_answers.rb` (3): boolean_literal 1, comparison 1, return_nil 1 - `lib/os_sdlc/git_repositories.rb` (3): return_nil 3 - `lib/os_sdlc/harness_error.rb` (3): boolean_connector 1, negation_removal 1, return_nil 1 - `lib/os_sdlc/detector/measures.rb` (2): return_nil 2 - `lib/os_sdlc/evidence/code_search.rb` (2): return_nil 1, statement_removal 1 - `lib/os_sdlc/evidence/fingerprint/method_probes.rb` (2): return_nil 2 - `lib/os_sdlc/gate/commands.rb` (2): return_nil 2 - `lib/os_sdlc/process_io.rb` (2): return_nil 2 - `lib/os_sdlc/project/cli.rb` (2): boolean_literal 1, return_nil 1 - `lib/os_sdlc/tracker/issue_source/shell.rb` (2): return_nil 1, statement_removal 1 - `lib/os_sdlc/verdict.rb` (2): comparison 1, return_nil 1 - `lib/os_sdlc/agent/type.rb` (1): return_nil 1 - `lib/os_sdlc/artifact_dir.rb` (1): return_nil 1 - `lib/os_sdlc/collaborator_pass/recipe_check.rb` (1): return_nil 1 - `lib/os_sdlc/dispatch/rerouting.rb` (1): statement_removal 1 - `lib/os_sdlc/dispatch/subagent_start/hook_payload.rb` (1): return_nil 1 - `lib/os_sdlc/evidence/fingerprint.rb` (1): return_nil 1 - `lib/os_sdlc/evidence/lazy_lsp_session.rb` (1): return_nil 1 - `lib/os_sdlc/expected_constants.rb` (1): boolean_literal 1 - `lib/os_sdlc/fast_gate/new_offense_report.rb` (1): return_nil 1 - `lib/os_sdlc/gate/command_result.rb` (1): return_nil 1 - `lib/os_sdlc/handoff.rb` (1): return_nil 1 - `lib/os_sdlc/handoff_content.rb` (1): return_nil 1 - `lib/os_sdlc/project/config_command.rb` (1): boolean_literal 1 - `lib/os_sdlc/ticket_shape/fence_stack.rb` (1): return_nil 1 - `lib/os_sdlc/tracker/forgejo.rb` (1): boolean_literal 1 `lib/os_sdlc/boot/inputs/detector_argv.rb` had 3 uncovered mutants in the pass. #1646 deleted that file, so this ticket drops those 3 mutants. `lib/os_sdlc/boot/onboarding.rb` had 2 uncovered mutants in the pass. That file moved to `lib/os_sdlc/project/cli.rb`, so this ticket lists them under the new path. This ticket also takes one survivor, not an uncovered mutant: the `Db.bind!` freeze mutant at `lib/os_sdlc/db.rb:25` (`Sequel::Model.freeze_descendants if freeze` replaced by `nil`, statement_removal). The cause is that `test/mutation_prelude.rb:9` binds the database once with `freeze: false` before any mutant runs. Kill it with a test against a separate model root, or rule it equivalent with a reason. See the comment on #1683. ## Reproduce n/a: the uncovered mutants come from a whole pass. Verify with a targeted run: `bin/os-sdlc-mutation-pass run <files> --no-matrix`. ## Approach For each listed file, write the paired unit test at `test/os_sdlc/<lib path>_test.rb` (ruling 100). The test must run the uncovered code and kill its mutants. Check the older test locations first (`test/cops/`, `test/daemon/`, `test/lint/`, `test/system_model_*`). A test there may already cover the file and only need a move or an extension. Where the code calls a process, use an adapter and a recorded fixture (ruling 88). Reuse `test/support/process_recording.rb` and the `recorded_*` doubles. No test starts a real process. When a mutant shows dead code (code no caller reaches), delete the code and write no test for it (ruling 107). When a mutant is equivalent (the mutant has the same behavior), rule it equivalent in a comment on this ticket with the reason. Follow `plugins/os-sdlc/references/survivor-loop.md`. Then verify with a targeted `--no-matrix` run over the files of this ticket. Do not run a whole pass. Required work: none beyond the acceptance criteria. ## Acceptance criteria 1. Given a targeted `--no-matrix` Mutineer run on the files listed in this ticket, when the run ends, then it reports no uncovered mutant and no survivor, except ones that this ticket deletes or rules equivalent with a reason. 2. Given a file with deleted unreachable code, when the suite runs, then it is green and no caller of the deleted code remains. ## Origin - Trigger: #1683 split, 2026-11-11 - Improvised this session: none - Chain: uncovered mutants ← survivor tickets #1656-#1664 took only survived mutants ← the second pass split only `survivors` into tickets ← DESIGN (`docs/research/mutation-testing/2026-11-09-second-pass/`) - Root candidate: none found; searched uncovered, no_coverage, mutant, gate, evidence, detector, tracker, dispatch, project - Where: lib/os_sdlc/ (agent, artifact_dir, collaborator_pass, detector, dispatch, evidence, expected_constants, fast_gate, gate, git_repositories, handoff, handoff_content, harness_error, process_io, project, retired_test, ticket_shape, tracker, verdict) - Parent: #1683 - Session: 974224e0-190b-4ca9-814e-eb971a24f35a - Transcript: /home/jared/.claude/projects/-home-jared-dev-cc-os-plugins-os-sdlc/974224e0-190b-4ca9-814e-eb971a24f35a.jsonl VERDICT: CREATE (ticket-skeptic, 2026-11-11): child of the #1683 required split; no open ticket covers these files.
Author
Owner

Work started on branch ticket-1698 (survivor loop, plugins/os-sdlc/references/survivor-loop.md).

Work started on branch ticket-1698 (survivor loop, plugins/os-sdlc/references/survivor-loop.md).
Author
Owner

Resolution

Done: Survivor loop over the small-directory files in 18 packets; 35 tests added (new paired files gate/name_test, process_io_test, git_repositories_test, detector/measures_test). Ruling 107 deleted 9 methods with no caller in lib, bin, hooks, skills or tests (Agent::Type#qualified, Verdict#reroute?, HarnessError#bootstrappable?, Gate::CommandResult#success?, ProcessIO#loud, Evidence::Fingerprint#probes with MethodProbes#sender/#built_probes, HookPayload#to_h, RecipeCheck#valid?, Project::CLI.exit_on_failure?). Db.bind! freeze mutant killed by DbConnectBangTest#test_connect_bang_freezes_the_model_classes with no production change. 1 equivalent ruling (2d5a6d45be8b, ignored rescue value). detector_argv.rb's 3 mutants dropped: file deleted in #1646.

Evidence: main 90da7388d (merged). Orchestrator re-ran all 18 packets: 0 survivors each. 5 adapter process-call mutants stay visible per ruling 137 (e1453baf79c2 GitRepositories#temporary_checkout; b298a7822ebd, b929cba6a296 Evidence::CodeSearch#capture; e7d42941b0b6, 6d638c75dd48 Tracker::IssueSource::Shell#capture). Three db.rb survivors in the first rerun were false: the packet omitted test/os_sdlc/db_test.rb; with it, 0 survivors of 122. Suite 4971 runs 0 failures; rubocop clean.

Follow-ups: none (adapter mutants recorded on #1683 with ruling 137)

## Resolution **Done:** Survivor loop over the small-directory files in 18 packets; 35 tests added (new paired files gate/name_test, process_io_test, git_repositories_test, detector/measures_test). Ruling 107 deleted 9 methods with no caller in lib, bin, hooks, skills or tests (Agent::Type#qualified, Verdict#reroute?, HarnessError#bootstrappable?, Gate::CommandResult#success?, ProcessIO#loud, Evidence::Fingerprint#probes with MethodProbes#sender/#built_probes, HookPayload#to_h, RecipeCheck#valid?, Project::CLI.exit_on_failure?). Db.bind! freeze mutant killed by DbConnectBangTest#test_connect_bang_freezes_the_model_classes with no production change. 1 equivalent ruling (2d5a6d45be8b, ignored rescue value). detector_argv.rb's 3 mutants dropped: file deleted in #1646. **Evidence:** main 90da7388d (merged). Orchestrator re-ran all 18 packets: 0 survivors each. 5 adapter process-call mutants stay visible per ruling 137 (e1453baf79c2 GitRepositories#temporary_checkout; b298a7822ebd, b929cba6a296 Evidence::CodeSearch#capture; e7d42941b0b6, 6d638c75dd48 Tracker::IssueSource::Shell#capture). Three db.rb survivors in the first rerun were false: the packet omitted test/os_sdlc/db_test.rb; with it, 0 survivors of 122. Suite 4971 runs 0 failures; rubocop clean. **Follow-ups:** none (adapter mutants recorded on #1683 with ruling 137) <!-- os-backlog kind: resolution -->
jared closed this issue 2026-11-11 17:34:35 +00:00
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
jared/cc-os#1698
No description provided.