Cover the uncovered cops mutants #1695
Labels
No labels
P0
P1
P2
P3
bug
category/code-change
category/cross-repo
category/eval-run
category/investigation
category/no-test-target
category/owner-ruling
category/prose-artifact
category/recurring-chore
category/structure
category/umbrella
crc-refactor
create
delete
enhancement
filed-by/agent
filed-by/user
frozen
lint-rule
needs-info
needs-triage
next
plugin/cc-architect
plugin/os
plugin/os-adr
plugin/os-aidd-lint
plugin/os-backlog
plugin/os-context
plugin/os-doc-hygiene
plugin/os-sdlc
plugin/os-vault
project/cc-os
ready-for-agent
ready-for-human
recurring
review
rule-proposal
update
waiting
wayfinder:grilling
wayfinder:map
wayfinder:map
wayfinder:research
wayfinder:task
wayfinder:task
wontfix
worklist/deviations
worklist/lint-rule
worklist/new-implement-build
No milestone
No project
No assignees
1 participant
Notifications
Due date
No due date set.
Dependencies
No dependencies set
Reference
jared/cc-os#1695
Loading…
Reference in a new issue
No description provided.
Delete branch "%!s()"
Deleting a branch is permanent. Although the deleted branch may continue to exist for a short time before it actually gets removed, it CANNOT be undone in most cases. Continue?
Problem
The second mutation pass (2026-11-09) left 33 uncovered mutants in 13 files under lib/os_sdlc/cops/. 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>.rbattest/os_sdlc/<path>_test.rb.Observed
The second mutation pass ran
bin/os-sdlc-mutation-pass run .on 2026-11-09..mutineer/pass.jsonlists 33 mutants in this ticket underno_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/cops/dry/repeated_path_literal/path_value.rb(8): return_nil 3, statement_removal 2, boolean_connector 1, condition_false 1, condition_true 1lib/os_sdlc/cops/require_inside_code.rb(8): arithmetic 2, return_nil 2, comparison 1, condition_false 1, condition_true 1, statement_removal 1lib/os_sdlc/cops/structural/lifecycle_ivar_behind_attr_reader/lifecycle_defs.rb(4): boolean_literal 2, return_nil 1, statement_removal 1lib/os_sdlc/cops/structural/format_validation_raising_in_initialize/match_sends.rb(2): arithmetic 1, return_nil 1lib/os_sdlc/cops/structural/unreachable_branch_after_guard/reassignment.rb(2): return_nil 2lib/os_sdlc/cops/structural/unread_instance_variable/member_generating_call.rb(2): boolean_connector 1, comparison 1lib/os_sdlc/cops/minitest/tautological_assertion/same_subject_calls.rb(1): comparison 1lib/os_sdlc/cops/sequel/ruby_filter_after_all.rb(1): return_nil 1lib/os_sdlc/cops/structural/format_validation_raising_in_initialize/validation_condition.rb(1): return_nil 1lib/os_sdlc/cops/structural/lifecycle_ivar_behind_attr_reader.rb(1): return_nil 1lib/os_sdlc/cops/structural/mutable_collection_leak_via_attr_reader.rb(1): return_nil 1lib/os_sdlc/cops/structural/raw_file_content_assertion/latest_assignment.rb(1): comparison 1lib/os_sdlc/cops/structural/simulated_polymorphism/owned_type.rb(1): boolean_literal 1Reproduce
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). Reusetest/support/process_recording.rband therecorded_*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-matrixrun over the files of this ticket. Do not run a whole pass.Required work: none beyond the acceptance criteria.
Acceptance criteria
--no-matrixMutineer 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.Origin
survivorsinto tickets ← DESIGN (docs/research/mutation-testing/2026-11-09-second-pass/)VERDICT: CREATE (ticket-skeptic, 2026-11-11): child of the #1683 required split; no open ticket covers these files.
Work started on branch ticket-1695 (survivor loop, plugins/os-sdlc/references/survivor-loop.md).
Resolution
Done: Survivor loop over the cops files in 11 packets. 8 tests added under test/cops/. Ruling 107 deleted LifecycleDefs#find's half-pair guard (AttrLifecycleOffense#present? already needs both methods) and Reassignment's op_asgn/masgn branches (each_node(:lvasgn) already yields their targets). 10 mutants ruled equivalent in .sdlc/mutation-rulings.tsv (2b402428c073, aadd18ea98e2, 51509d534c46, bd7f7b44a925, e7754d4f0971, 3e5898e247fe, ef9502f77621, 8283295c8c4e, f65c526dbd5d, 02a385342f4a) with reasons there.
Evidence: main
d1da756a4+dc7f89f7e(merged). Orchestrator re-ran all 11 packets: 0 survivors each; the two ruled continuation-line mutants no longer show afterdc7f89f7e. Suite 4911 runs 0 failures; rubocop clean.Follow-ups: none