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 second half of the no-tests bucket: the git ref-management workflow and check-execution paths in hooks/post-turn-quality-stop-hook.py, plus the main() composition root. 378 no-tests mutants fall in this group. All bar main() are category-1 gaps testable with the suite's existing mocked-run pattern; none of them requires a new seam.
Uncovered functions (no-tests mutant counts)
hooks/post-turn-quality-stop-hook.py:953-1010 — evaluate_changes (75): category detection wiring, target filtering against the Makefile, code/markdown command grouping, and the block-on-failure decision.
hooks/post-turn-quality-stop-hook.py:678-716 — run_make (65): empty-target early return, make argv, missing-make fallback (exit 127), and output truncation wiring.
hooks/post-turn-quality-stop-hook.py:426-465 — changed_files (46): the three git commands (diff, cached diff, ls-files), line stripping, and result merging.
hooks/post-turn-quality-stop-hook.py:331-368 — ensure_origin_main_ref (39): always-fetch versus fetch-if-missing branching and the "still missing after fetch" path.
hooks/post-turn-quality-stop-hook.py:258-278 — ref_exists (24): the 0/1/other returncode trichotomy.
hooks/post-turn-quality-stop-hook.py:302-328 — ensure_origin_main (22); :239-255 — fetch_origin_main (20); :218-236 — ensure_origin_remote (20); :281-299 — verify_ref (17); :371-399 — ensure_base_ref (18): the remainder of the base-ref pipeline, including the non-origin/main base-ref branch.
hooks/post-turn-quality-stop-hook.py:402-423 — merge_base (18).
hooks/post-turn-quality-stop-hook.py:1167-1184 — main (14): see below.
Analysis
Nothing in the suite executes the base-ref pipeline or the check-execution layer, so mutmut records every mutant there as "no tests". These paths decide whether the hook fetches, what diff base it uses, which make targets run, and whether a stop is blocked — the core of the hook's contract. All of them are deterministic functions over run() results and are directly testable with the mocked-run pattern already used for has_uncommitted_changes, or against a temporary git repository for higher fidelity.
main() (14 mutants) is assessed as an accepted composition-root boundary rather than a unit-test target: it only composes parse_hook_input, resolve_start_cwd, parse_env, and run_stop_checks. The proposed seam is one end-to-end subprocess test — run the script in a temporary git repository with hook JSON on stdin and assert the exit code and stdout — which covers main() incidentally without unit-testing it.
Suggested tests
ref_exists / verify_ref / fetch_origin_main / ensure_origin_remote: mocked-run cases for each returncode branch, asserting argv and the exact error strings.
ensure_origin_main_ref / ensure_origin_main / ensure_base_ref: parametrized cases for always-fetch, ref-already-present, fetch-then-present, fetch-then-still-missing, and the non-default base-ref branch, asserting the (ok, err, fetched) triples exactly.
merge_base / changed_files: mocked-run success and failure cases; assert the merged, sorted file list including untracked entries.
evaluate_changes: cases for no categories, targets missing from the Makefile (skipped), code and markdown groupings running separately, and a failing command producing a block payload (assert JSON via capsys and the populated HookState).
run_make: empty targets, successful run, failing run (assert truncation applied), and the FileNotFoundError fallback with exit_code == 127.
- End-to-end subprocess test of the script itself in a temporary git repository (covers
main(), exit code, and the silent-success contract).
Full worklist: triage worklist.md; dataset SHA b850e2f.
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 second half of the no-tests bucket: the git ref-management workflow and check-execution paths in
hooks/post-turn-quality-stop-hook.py, plus themain()composition root. 378 no-tests mutants fall in this group. All barmain()are category-1 gaps testable with the suite's existing mocked-runpattern; none of them requires a new seam.Uncovered functions (no-tests mutant counts)
hooks/post-turn-quality-stop-hook.py:953-1010—evaluate_changes(75): category detection wiring, target filtering against the Makefile, code/markdown command grouping, and the block-on-failure decision.hooks/post-turn-quality-stop-hook.py:678-716—run_make(65): empty-target early return,makeargv, missing-make fallback (exit 127), and output truncation wiring.hooks/post-turn-quality-stop-hook.py:426-465—changed_files(46): the three git commands (diff, cached diff, ls-files), line stripping, and result merging.hooks/post-turn-quality-stop-hook.py:331-368—ensure_origin_main_ref(39): always-fetch versus fetch-if-missing branching and the "still missing after fetch" path.hooks/post-turn-quality-stop-hook.py:258-278—ref_exists(24): the 0/1/other returncode trichotomy.hooks/post-turn-quality-stop-hook.py:302-328—ensure_origin_main(22);:239-255—fetch_origin_main(20);:218-236—ensure_origin_remote(20);:281-299—verify_ref(17);:371-399—ensure_base_ref(18): the remainder of the base-ref pipeline, including the non-origin/mainbase-ref branch.hooks/post-turn-quality-stop-hook.py:402-423—merge_base(18).hooks/post-turn-quality-stop-hook.py:1167-1184—main(14): see below.Analysis
Nothing in the suite executes the base-ref pipeline or the check-execution layer, so mutmut records every mutant there as "no tests". These paths decide whether the hook fetches, what diff base it uses, which make targets run, and whether a stop is blocked — the core of the hook's contract. All of them are deterministic functions over
run()results and are directly testable with the mocked-runpattern already used forhas_uncommitted_changes, or against a temporary git repository for higher fidelity.main()(14 mutants) is assessed as an accepted composition-root boundary rather than a unit-test target: it only composesparse_hook_input,resolve_start_cwd,parse_env, andrun_stop_checks. The proposed seam is one end-to-end subprocess test — run the script in a temporary git repository with hook JSON on stdin and assert the exit code and stdout — which coversmain()incidentally without unit-testing it.Suggested tests
ref_exists/verify_ref/fetch_origin_main/ensure_origin_remote: mocked-runcases for each returncode branch, asserting argv and the exact error strings.ensure_origin_main_ref/ensure_origin_main/ensure_base_ref: parametrized cases for always-fetch, ref-already-present, fetch-then-present, fetch-then-still-missing, and the non-default base-ref branch, asserting the(ok, err, fetched)triples exactly.merge_base/changed_files: mocked-runsuccess and failure cases; assert the merged, sorted file list including untracked entries.evaluate_changes: cases for no categories, targets missing from the Makefile (skipped), code and markdown groupings running separately, and a failing command producing a block payload (assert JSON via capsys and the populatedHookState).run_make: empty targets, successful run, failing run (assert truncation applied), and theFileNotFoundErrorfallback withexit_code == 127.main(), exit code, and the silent-success contract).Full worklist: triage
worklist.md; dataset SHAb850e2f.