Skip to content

Mutation testing: uncovered pure helper survivors (no-tests bucket) #40

Description

@leynos

Context

Mutation-testing run against main (b850e2fec11b1966d2b73670ae56b5eff195284e), mutmut 3.6.0, local run 2026-07-10: 1025 mutants, 151 killed, 235 survived, 639 no-tests.

This issue covers the first half of the no-tests bucket: pure or trivially harnessed helpers in hooks/post-turn-quality-stop-hook.py with zero executing tests. These are not untestable boundaries — every function below is deterministic and unit-testable with plain pytest (plus capsys/monkeypatch where noted). 261 no-tests mutants fall in this group.

Uncovered functions (no-tests mutant counts)

  • hooks/post-turn-quality-stop-hook.py:719-786format_reason (146 mutants): the entire blocked-reason renderer, including the 60-file truncation boundary and failure-block formatting.
  • hooks/post-turn-quality-stop-hook.py:167-192truncate (18): head/tail split arithmetic and the max_chars <= 0 / marker-length boundaries.
  • hooks/post-turn-quality-stop-hook.py:579-607parse_make_targets (22): the rule regex, comment/indent skipping, and %-pattern exclusion.
  • hooks/post-turn-quality-stop-hook.py:554-576detect_categories (19): extension-to-category mapping.
  • hooks/post-turn-quality-stop-hook.py:807-833targets_for_categories (13): category expansion and the include filter.
  • hooks/post-turn-quality-stop-hook.py:655-675dedup_preserve_order (6).
  • hooks/post-turn-quality-stop-hook.py:610-624is_missing_makefile (5).
  • hooks/post-turn-quality-stop-hook.py:888-904parse_hook_input (4): stdin JSON parsing (monkeypatch stdin).
  • hooks/post-turn-quality-stop-hook.py:907-930resolve_start_cwd (13): hook-input cwd versus CLAUDE_PROJECT_DIR versus os.getcwd() precedence.
  • hooks/post-turn-quality-stop-hook.py:789-804block_and_print (11): JSON payload shape (capsys).
  • hooks/post-turn-quality-stop-hook.py:933-950fail_state (4): state flagging plus blocked payload (capsys).

Analysis

The co-located suite exercises only the compush family, run()'s missing-cwd branch, get_make_targets's missing-make branch, and parse_env's compush flag; mutmut therefore records every mutant in the functions above as "no tests". These helpers carry real behaviour (output truncation arithmetic, Makefile parsing, category detection, the hook's block-payload contract) and mutations here change what agents see when the hook blocks.

Suggested tests

  1. truncate: boundary cases (max_chars = 0, shorter-than-limit, limit shorter than the marker, and an exact head/tail split assertion).
  2. parse_make_targets: a representative make -qp fixture asserting the exact target set, including %-pattern and comment exclusion; is_missing_makefile truthy/falsy cases.
  3. detect_categories / targets_for_categories / dedup_preserve_order: parametrized equality assertions covering every extension set and the include filter.
  4. format_reason: snapshot-style assertions (syrupy is already a dev dependency) for the error, >60-files, detected-categories, and failed-command variants.
  5. parse_hook_input / resolve_start_cwd: valid JSON, invalid JSON, non-dict JSON; cwd key present, CLAUDE_PROJECT_DIR fallback, bare os.getcwd() fallback.
  6. block_and_print / fail_state: parse the emitted JSON and assert decision == "block" and the reason verbatim.

Full worklist: triage worklist.md; dataset SHA b850e2f.

Metadata

Metadata

Assignees

No one assigned

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions