Skip to content

Kill mutation survivors in the post-turn quality stop hook (#36, #37, #38, #40) - #50

Merged
leynos merged 8 commits into
mainfrom
kill-mutation-survivors
Sep 9, 2026
Merged

Kill mutation survivors in the post-turn quality stop hook (#36, #37, #38, #40)#50
leynos merged 8 commits into
mainfrom
kill-mutation-survivors

Conversation

@leynos

@leynos leynos commented Jul 13, 2026

Copy link
Copy Markdown
Owner

Closes #37 and #38. Addresses #36 and #40. Issues #39 and #41 are deferred in full.

Survivor-triage PR for the mutation-testing run recorded against main (b850e2f). It adds targeted unit tests for the highest-value surviving mutants in hooks/post-turn-quality-stop-hook.py, and eliminates or suppresses the equivalent mutants identified at triage.

Before/after (full mutmut run, mutmut 3.6.0, CPython 3.14)

Status Before After
Killed 151 461
Survived 235 129
No tests 639 429
Total generated 1025 1019

Six equivalent mutants are no longer generated (pragma suppression and the removal of a redundant argument — see below). The 129 remaining survivors break down as 117 deferred real gaps (71 prepare_run_stop_checks + 10 run_stop_checks#39; 18 repo_root + 18 get_make_targets#36) and 12 newly identified equivalents (7 format_reason, 3 parse_make_targets, 2 truncate — justified below).

Review walkthrough

  • hooks/test_post_turn_quality_stop_hook.py — new test classes for truncate (boundary and exact head/tail split), parse_make_targets and is_missing_makefile (representative make -qp fixture), detect_categories and default_categories (full-dict equality across every extension group), format_reason (exact multi-line rendering, the 60-file elision boundary, missing-key command entries), the full parse_env tuple and parse_max_output fallback, and run() (real subprocess capturing text output, the NotADirectoryError branch, the filename-less FileNotFoundError guard). Existing plumbing tests gain exact argv (call_args_list) assertions, exact error-message equality in place of substring checks, wiring assertions in compush_check, and the ahead-by-exactly-one boundary case.
  • hooks/post-turn-quality-stop-hook.py — equivalence handling only; no behavioural change (the full suite and a fresh mutation run confirm).

Equivalent mutants (category 2)

mutmut 3.6 honours # pragma: no mutate only at statement level (its pragma visitor ignores trailing comments inside call argument lists), so the worklist's four equivalents were handled structurally:

  • parse_env flag defaults ("""XXXX" on POST_TURN_ALWAYS_FETCH/POST_TURN_COMPUSH): hoisted into a single flag_default = "" # pragma: no mutate statement with a justification comment — any mutated default is still non-truthy to parse_bool_env.
  • run() check=Falsecheck=None/dropped: the argument was the subprocess default, so both mutants were equivalent by construction; the redundant argument is removed and a comment records that non-zero return codes are deliberately surfaced via CompletedProcess.returncode.
  • Newly identified during the re-run: the POST_TURN_MAX_OUTPUT_CHARS default ("12000" → non-numeric) falls back to parse_max_output's own 12000 default — hoisted and suppressed the same way.

Twelve further equivalents remain in the survivor list unsuppressed, because each sits on a line that also carries killable mutants (line-level suppression would shield them):

  • format_reason (7): c.get("exit_code", …) defaults are unreachable — the failures filter guarantees the key is present; c.get("stdout"/"stderr", None/dropped) defaults are filtered identically to "" by the if x comprehension guard.
  • parse_make_targets (3): corrupting one element of the startswith(("#", "\t", " ")) guard is unobservable — the rule regex rejects those lines anyway.
  • truncate (2): <=< at both boundaries converges on the same output through the fall-through slice paths.

Red-green evidence

Each new test was verified against a hand-applied mutant diff (fail) and the reverted source (pass); cycles were run for format_reason, run, default_categories, has_unpushed_commits, and parse_env. Representative transcript:

=== RED: format_reason literal (x_format_reason__mutmut_2)
    ("Post-turn checks failed." -> "XXPost-turn checks failed.XX")
E   AssertionError: unexpected minimal reason: 'XXPost-turn checks failed.XX\n\nError: boom…'
2 failed, 2 passed, 68 deselected in 0.15s
=== GREEN: format_reason literal (reverted)
4 passed, 68 deselected in 0.12s

(Two same-length mutations initially produced misleading transcripts because Python's mtime-plus-size .pyc invalidation served stale bytecode; the cycles were re-run with PYTHONDONTWRITEBYTECODE=1 and clean caches, and both then behaved correctly.)

Deferred work

The 400-line test-budget tolerance for this PR is spent (392 net new test lines). Deferred explicitly:

Validation

  • make ci (check-fmt, lint, typecheck, full pytest suite — 149 tests) green.
  • Full mutmut run re-runs after each commit; scoped mutmut run 'hooks.post-turn-quality-stop-hook.x_format_reason*' confirmed the final residual kill.

Summary by Sourcery

Move the post-turn quality stop hook out of this repository and update project configuration, documentation, and tests to reflect its removal.

Enhancements:

  • Remove the post-turn quality stop hook and its dedicated tests from this repository as the hook moves to its own project.
  • Simplify the test and mutation-testing configuration after removing the hook implementation.
  • Update user and developer documentation to direct users to the standalone post-turn quality stop hook project.

Build:

  • Remove hook-specific test targets and mutation-testing configuration from the project build setup.

CI:

  • Delete the repository mutation-testing workflow.

Documentation:

  • Document the removal and migration of the post-turn quality stop hook, including a link to its standalone project.
  • Update development documentation to reflect that hook files are copied without registering the removed hook in Claude Code settings.

Tests:

  • Remove the hook-specific test suite and workflow contract tests.

@coderabbitai

coderabbitai Bot commented Jul 13, 2026

Copy link
Copy Markdown

Review Change Stack

Note

Reviews paused

It looks like this branch is under active development. To avoid overwhelming you with review comments due to an influx of new commits, CodeRabbit has automatically paused this review. You can configure this behavior by changing the reviews.auto_review.auto_pause_after_reviewed_commits setting.

Use the following commands to manage reviews:

  • @coderabbitai resume to resume automatic reviews.
  • @coderabbitai review to trigger a single review.

Use the checkboxes below for quick actions:

  • ▶️ Resume reviews
  • 🔍 Trigger review

Summary

  • Added targeted unit tests covering mutation survivors across hook parsing, truncation, category detection, formatting, environment handling, git wiring, and subprocess execution.
  • Expanded run() resilience coverage for non-zero commands, missing directories, file-based working directories, and filename-less FileNotFoundError.
  • Removed the redundant check=False argument and refactored environment defaults without changing behaviour.
  • Improved assertions for exact git commands, error messages, fallback fields, and formatted reasons.
  • Mutation results improved from 151 to 461 killed mutants, with survivors reduced from 235 to 129.
  • 149 tests pass and make ci is green.

Walkthrough

The subprocess wrapper was simplified, while tests now verify exact Git commands, error messages, fallback process fields, output handling, formatting, category detection, and environment parsing.

Changes

Quality hook coverage

Layer / File(s) Summary
Subprocess fallback contract
hooks/post-turn-quality-stop-hook.py, hooks/test_post_turn_quality_stop_hook.py
Remove the explicit check=False argument and expand coverage for captured output, missing or invalid working directories, fallback fields, and filename-less FileNotFoundError.
Git and compush decision contracts
hooks/test_post_turn_quality_stop_hook.py
Assert exact Git command wiring, upstream and unpushed-commit boundaries, error strings, helper call arguments, and JSON reasons.
Helper parsing and rendering coverage
hooks/post-turn-quality-stop-hook.py, hooks/test_post_turn_quality_stop_hook.py
Cover truncation, Makefile and category parsing, reason formatting, environment defaults and overrides, and maximum-output parsing.

Possibly related issues

  • #36 — Strengthens tests for the same Git plumbing helpers, command arguments, boundary cases, and exact reasons.

Suggested labels: Issue

🚥 Pre-merge checks | ✅ 19 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Out of Scope Changes check ⚠️ Warning The PR adds broad tests for parse_make_targets, format_reason, category detection and parse_env that are outside #37. Split the non-run() coverage into separate PRs or link the relevant issues, and keep this PR focused on the run() subprocess wrapper survivors.
✅ Passed checks (19 passed)
Check name Status Explanation
Title check ✅ Passed The title matches the mutation-survivor work and includes the linked issue references.
Description check ✅ Passed The description stays on-topic and describes the same mutation-survivor changes.
Linked Issues check ✅ Passed The PR covers #37 by testing real subprocess execution and both fallback branches in run().
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.
Testing (Overall) ✅ Passed The added tests hit real subprocess execution, both OSError fallbacks, full parse/format outputs, and exact wiring, so plausible regressions would fail.
User-Facing Documentation ✅ Passed No user-facing behaviour changed; only internal hook code and tests changed, and docs/users-guide.md was untouched.
Developer Documentation ✅ Passed The PR only refactors hook internals and adds tests; it introduces no new API, architecture, tooling, or build contract needing docs, ADR, or execplan updates.
Module-Level Documentation ✅ Passed Both touched Python modules begin with descriptive docstrings stating purpose, utility, and the test module’s relationship to the hook.
Testing (Unit And Behavioural) ✅ Passed PASS: the PR adds focused unit tests for edge cases plus real-subprocess and OS-error behavioural coverage at the hook boundary.
Testing (Property / Proof) ✅ Passed Do not request property or proof tooling: the PR only tightens unit tests and cleans equivalent-mutant handling; it introduces no new broad invariant or lemma.
Testing (Compile-Time / Ui) ✅ Passed Keep the assertion-based tests; no Rust/TypeScript compile-time path exists, and the hook output checks are focused enough without snapshots.
Unit Architecture ✅ Passed The PR keeps subprocess and env access isolated at explicit boundaries; the new tests and tiny refactors make fallibility clearer, not blurrier.
Domain Architecture ✅ Passed Keep this as infrastructure glue: the PR only tweaks the stop-hook and its tests; it does not pull transport or filesystem concerns into any domain model.
Observability ✅ Passed No new operational behaviour appears; the PR is test-only plus equivalent-mutant refactors, and no observability gaps were introduced.
Security And Privacy ✅ Passed No secrets, auth changes, unsafe sinks, or broadened permissions were added; the hook still uses list argv with no shell, and tests use only fake data and env names.
Performance And Resource Use ✅ Passed No new unbounded loops, repeated I/O, or hot-path allocation regressions appear; runtime scans stay linear and truncation remains fixed at 60 items.
Concurrency And State ✅ Passed PASS: preserve single-threaded, locally owned HookState flow; no async, locks, background tasks, or shared mutable globals were added.
Architectural Complexity And Maintainability ✅ Passed Only direct tests changed; the hook code stays explicit and local, with no new layers, registries, or hidden lifecycle hooks.
Rust Compiler Lint Integrity ✅ Passed This PR only changes hooks/test_post_turn_quality_stop_hook.py; no Rust files, lint suppressions, or clone-heavy ownership changes are present.
✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch kill-mutation-survivors

Tighten each assertion, let exact truths shine,
Capture stdout on every command line.
Guard every fallback, parse each flag,
Keep Git’s reasons neatly on track.
Test, verify, and let quality fly.

Comment @coderabbitai help to get the list of available commands.

@sourcery-ai

sourcery-ai Bot commented Jul 13, 2026

Copy link
Copy Markdown

Reviewer's Guide

This PR adds high-precision tests around the post-turn quality stop hook to kill/suppress surviving mutation-testing mutants, and performs small refactorings in the hook implementation to structurally suppress known equivalent mutants without changing behaviour.

Flow diagram for updated parse_env default handling

flowchart TD
    parse_env[parse_env]
    flag_default["flag_default = ''  (no mutate)"]
    max_output_default["max_output_default = '12000'  (no mutate)"]

    parse_env --> flag_default
    parse_env --> max_output_default

    base_ref_env["os.environ.get POST_TURN_BASE_REF"]
    always_fetch_env["os.environ.get POST_TURN_ALWAYS_FETCH"]
    max_output_env["os.environ.get POST_TURN_MAX_OUTPUT_CHARS"]
    compush_env["os.environ.get POST_TURN_COMPUSH"]

    parse_env --> base_ref_env
    parse_env --> always_fetch_env
    parse_env --> max_output_env
    parse_env --> compush_env

    always_fetch_env --> parse_bool_env
    compush_env --> parse_bool_env
    max_output_env --> parse_max_output

    flag_default --> always_fetch_env
    flag_default --> compush_env
    max_output_default --> max_output_env

    parse_bool_env[parse_bool_env]
    parse_max_output[parse_max_output]

    parse_bool_env --> always_fetch
    parse_bool_env --> compush
    parse_max_output --> max_out

    base_ref_env --> base_ref

    base_ref[base_ref]
    always_fetch[always_fetch]
    max_out[max_out]
    compush[compush]

    base_ref --> result_tuple
    always_fetch --> result_tuple
    max_out --> result_tuple
    compush --> result_tuple

    result_tuple[("(base_ref, always_fetch, max_out, compush)")]
Loading

File-Level Changes

Change Details Files
Strengthen existing git-plumbing and compush-check tests with exact command, error-message, and wiring assertions to better constrain behaviour under mutation.
  • Add unittest.mock.call imports and assert exact call_args_list for git diff/ls-files/rev-parse/rev-list invocations.
  • Replace substring-based error-message checks with exact string equality for git error paths.
  • Add tests for edge conditions such as rev-list count == 1 and empty outputs, and assert compush_check calls its helpers with precise arguments.
hooks/test_post_turn_quality_stop_hook.py
Add focused unit tests for run(), truncate(), parse_make_targets(), is_missing_makefile(), detect_categories(), default_categories(), format_reason(), parse_env(), and parse_max_output to pin down their behaviour and kill surviving mutants.
  • Add round-trip tests for run() covering normal subprocess output capture, NotADirectoryError cwd handling, and filename-less FileNotFoundError fallbacks.
  • Define TRUNCATE_MARKER and parametrized tests that cover truncate() boundaries and exact head/tail splits for truncated text.
  • Add representative make -qp fixture output and verify parse_make_targets() target extraction and is_missing_makefile() case-insensitive detection.
  • Verify default_categories() and detect_categories() mappings across Python/TS, Rust, and Markdown extension groups.
  • Add multi-scenario format_reason() tests for minimal error-only state, full state with commands and targets, file-list truncation at 60/61 files, and treatment of commands missing exit_code.
  • Add parse_env() tests for default tuple and environment-variable overrides, and parse_max_output() tests for valid integers and non-numeric/empty fallbacks to 12000.
hooks/test_post_turn_quality_stop_hook.py
Refactor parse_env() and run() implementation to structurally suppress known equivalent mutants using pragma comments, without altering runtime behaviour.
  • Remove the redundant check=False argument from subprocess.run in run(), documenting that non-zero exit codes are intentionally surfaced via CompletedProcess.returncode.
  • Hoist POST_TURN_ALWAYS_FETCH and POST_TURN_COMPUSH flag defaults into a single flag_default variable annotated with # pragma: no mutate to prevent equivalent mutants of empty-string defaults.
  • Hoist POST_TURN_MAX_OUTPUT_CHARS default into max_output_default annotated with # pragma: no mutate to prevent equivalent non-numeric default mutants, while still letting parse_max_output enforce the 12000 fallback.
hooks/post-turn-quality-stop-hook.py

Assessment against linked issues

Issue Objective Addressed Explanation
#37 Add tests for run() that execute a real subprocess command and assert decoded stdout/stderr and the actual exit code, ensuring text=True, capture_output=True usage and that check=True would raise instead of returning.
#37 Add tests that exercise both error-path fallbacks of run(): the missing-cwd (FileNotFoundError with a non-matching filename) and NotADirectoryError branches, asserting the full fallback CompletedProcess fields (args, returncode, stdout, stderr).
#37 Add a test for the filename-less FileNotFoundError guard in run(), confirming that the cwd fallback is returned rather than re-raised and that args mirrors the command.

Possibly linked issues


Tips and commands

Interacting with Sourcery

  • Trigger a new review: Comment @sourcery-ai review on the pull request.
  • Continue discussions: Reply directly to Sourcery's review comments.
  • Generate a GitHub issue from a review comment: Ask Sourcery to create an
    issue from a review comment by replying to it. You can also reply to a
    review comment with @sourcery-ai issue to create an issue from it.
  • Generate a pull request title: Write @sourcery-ai anywhere in the pull
    request title to generate a title at any time. You can also comment
    @sourcery-ai title on the pull request to (re-)generate the title at any time.
  • Generate a pull request summary: Write @sourcery-ai summary anywhere in
    the pull request body to generate a PR summary at any time exactly where you
    want it. You can also comment @sourcery-ai summary on the pull request to
    (re-)generate the summary at any time.
  • Generate reviewer's guide: Comment @sourcery-ai guide on the pull
    request to (re-)generate the reviewer's guide at any time.
  • Resolve all Sourcery comments: Comment @sourcery-ai resolve on the
    pull request to resolve all Sourcery comments. Useful if you've already
    addressed all the comments and don't want to see them anymore.
  • Dismiss all Sourcery reviews: Comment @sourcery-ai dismiss on the pull
    request to dismiss all existing Sourcery reviews. Especially useful if you
    want to start fresh with a new review - don't forget to comment
    @sourcery-ai review to trigger a new review!

Customizing Your Experience

Access your dashboard to:

  • Enable or disable review features such as the Sourcery-generated pull request
    summary, the reviewer's guide, and others.
  • Change the review language.
  • Add, remove or edit custom review instructions.
  • Adjust other review settings.

Getting Help

@leynos leynos changed the title Kill mutation survivors in the post-turn quality stop hook Kill mutation survivors in the post-turn quality stop hook (#36, #37, #38, #40) Jul 17, 2026
@leynos
leynos marked this pull request as ready for review July 25, 2026 14:53

@sourcery-ai sourcery-ai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Sorry @leynos, you have reached your weekly rate limit of 500000 diff characters.

Please try again later or upgrade to continue using Sourcery

@pandalump

Copy link
Copy Markdown
Collaborator

@coderabbitai review

@coderabbitai

coderabbitai Bot commented Jul 29, 2026

Copy link
Copy Markdown
✅ Action performed

Review finished.

Note: CodeRabbit is an incremental review system and does not re-review already reviewed commits. This command is applicable only when automatic reviews are paused.

@coderabbitai coderabbitai Bot added the Issue label Jul 29, 2026

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 5

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@hooks/post-turn-quality-stop-hook.py`:
- Around line 151-157: Update the subprocess.run call in the hook’s command
execution helper to restore explicit check=False, and add the existing # pragma:
no mutate annotation used by parse_env() to suppress the mutation warning.
Preserve the current controlled-command noqa and non-zero return-code behavior.
- Around line 887-896: Update the max_output_default value used by
parse_max_output in the surrounding configuration setup to an unparsable
sentinel instead of duplicating "12000". Preserve parse_max_output's existing
fallback so it remains the single source of truth for the default maximum
output.

In `@hooks/test_post_turn_quality_stop_hook.py`:
- Around line 533-587: Move test_real_command_captures_text_output,
test_file_as_cwd_returns_error, and
test_filename_less_file_not_found_uses_fallback from TestGetMakeTargets into
TestRunOSError, placing them near test_nonexistent_cwd_returns_error. Preserve
each test’s implementation and assertions unchanged.
- Around line 771-772: Parenthesize the implicit two-part string concatenations
in the list literals at both occurrences, including the entries near the
relevant test messages, so Ruff ISC004 is satisfied and the expected output
remains unchanged.
- Around line 589-593: Split hooks/test_post_turn_quality_stop_hook.py into
focused modules using the existing test_run.py, test_helpers.py,
test_formatting.py, and test_env.py banner sections as boundaries, keeping each
module under 400 logical lines. Move the shared _completed, REPO, and ENV_VARS
setup into conftest.py or a fixtures module, then update imports and references
so all tests retain their current behavior.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: ASSERTIVE

Plan: Pro Plus

Run ID: 63f908cd-e37a-4313-80ea-de6878b440fe

📥 Commits

Reviewing files that changed from the base of the PR and between 8cd59d2 and 97441e9.

📒 Files selected for processing (2)
  • hooks/post-turn-quality-stop-hook.py
  • hooks/test_post_turn_quality_stop_hook.py
🔗 Linked repositories identified

CodeRabbit considers these linked repositories for cross-repo context during reviews:

  • leynos/cuprum (auto-detected)

Comment thread hooks/post-turn-quality-stop-hook.py Outdated
Comment thread hooks/post-turn-quality-stop-hook.py Outdated
Comment thread hooks/test_post_turn_quality_stop_hook.py Outdated
Comment thread hooks/test_post_turn_quality_stop_hook.py Outdated
Comment thread hooks/test_post_turn_quality_stop_hook.py Outdated
@leynos

leynos commented Sep 8, 2026

Copy link
Copy Markdown
Owner Author

@coderabbitai the post turn quality stop hook in this repo is obsolete and has been superseded by https://github.com/leynos/post-turn-quality-stop-hook/

Please provide an agent prompt for removal of the hook, installation scripts and tests, and the addition of a user's guide note directing consumers of the repo to the new hook.

@coderabbitai

coderabbitai Bot commented Sep 8, 2026

Copy link
Copy Markdown

Tip

For best results, initiate chat on the files or code changes.

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
set -euo pipefail

printf '%s\n' '== candidate files =='
fd -HI -t f . | sort | sed -n '1,240p'

printf '%s\n' '== post-turn hook references =='
rg -n -i -C 2 'post[- ]turn|quality[- ]stop|stop hook|POST_TURN' . \
  -g '!**/.git/**' || true

printf '%s\n' '== repository documentation candidates =='
fd -HI -t f '^(README|CONTRIBUTING|USER.*GUIDE|GUIDE|.*install.*|.*hook.*)\.' . \
  -E .git | sort || true

Length of output: 15166


@leynos Use this agent prompt:

Remove the obsolete post-turn quality stop hook from this repository.

Replacement project:
https://github.com/leynos/post-turn-quality-stop-hook

Scope:
1. Delete `hooks/post-turn-quality-stop-hook.py`.
2. Delete `hooks/test_post_turn_quality_stop_hook.py`.
3. Update `install-hooks`.
   - Remove installation, validation, and configuration of `post-turn-quality-stop-hook.py`.
   - Preserve all unrelated hook installation behaviour.
4. Update `Makefile`.
   - Remove the `test-hooks` target if it exists only for `hooks/test_post_turn_quality_stop_hook.py`.
   - Remove obsolete comments and dependencies that refer to the post-turn quality stop hook.
   - Preserve unrelated test and CI targets.
5. Search the repository for all remaining references to:
   - `post-turn-quality-stop-hook`
   - `POST_TURN_`
   - `test-hooks`
   - “post-turn hook”
   - “quality stop hook”
   Remove or update each obsolete reference.
6. Add a concise migration note to the user documentation.
   - Update `docs/users-guide.md`.
   - Add a short note to `README.md` if it lists available hooks or installation features.
   - State that this repository no longer provides the post-turn quality stop hook.
   - Direct users to `https://github.com/leynos/post-turn-quality-stop-hook` for installation, configuration, and support.
   - Do not duplicate the replacement project’s installation instructions.
7. Update repository tests and workflow assertions that expect the removed files, targets, or installer behaviour.
8. Run the applicable formatting, test, and CI checks after the removal.

Acceptance criteria:
- No implementation, dedicated test, installer logic, Make target, workflow contract, or documentation claim remains for the obsolete post-turn quality stop hook.
- User documentation directs consumers to `https://github.com/leynos/post-turn-quality-stop-hook`.
- Unrelated hooks, installers, tests, and CI behaviour remain unchanged.
- The repository validation suite passes.

✏️ Learnings added
Learnt from: leynos
URL: https://github.com/leynos/agent-helper-scripts/pull/50

Timestamp: 2026-09-08T22:27:44.766Z
Learning: In `leynos/agent-helper-scripts`, `hooks/post-turn-quality-stop-hook.py`, its installation logic in `install-hooks`, and its dedicated tests are obsolete. Direct consumers to `https://github.com/leynos/post-turn-quality-stop-hook` for the replacement hook.

Note: Learnings are effective only in the context of similar code segments. To apply general coding guidelines, please configure review instructions. You can manage existing learnings in the app.

You are interacting with an AI system.

leynos and others added 7 commits September 9, 2026 13:06
Add targeted unit tests for the highest-value mutation-testing
survivors reported against the stop hook: exact rendering tests for
format_reason, boundary and split tests for truncate, representative
parsing tests for parse_make_targets and is_missing_makefile,
extension-mapping tests for detect_categories, full-tuple parse_env
and parse_max_output tests, equality tests for default_categories,
real-subprocess and error-branch tests for run(), and argv, wiring,
and exact-message assertions for the git plumbing helpers.

Annotate the four equivalent mutants (subprocess check=False and the
falsy env-var defaults) with pragma no mutate comments, splitting the
affected arguments onto their own lines so the suppression does not
shield killable mutants on the same line.
mutmut 3.6 only honours pragma comments at statement level, so the
argument-level annotations added earlier were ignored. Hoist the
falsy env-var defaults into their own pragma-suppressed statements,
drop the redundant check=False argument from run() (False is the
subprocess default, so both of its mutants were equivalent by
construction), and suppress the max-output default whose mutation
falls back to the same 12000 value.

Also convert the remaining substring assertions on git error
messages to exact equality, cover truncate at max_chars=1, extend
the make -qp fixture with a mid-stream blank line and a mixed
pattern/plain rule, and exercise format_reason with a command entry
lacking cmd/stdout/stderr keys and with a falsy base ref.
Add issue references to the docstrings of the new tests and tightened
assertions in the post-turn quality stop hook suite, so each kill can
be traced back to #36, #37, #38, and #40.
The replacement project lives at
https://github.com/leynos/post-turn-quality-stop-hook.

- Delete hooks/post-turn-quality-stop-hook.py and its test.
- Drop the stop-hook install/check logic from install-hooks.
- Remove the test-hooks Make target and hook-test plumbing.
- Remove the mutation-testing workflow and its contract test.
- Point user docs to the replacement repository.
Archive the VT Code session working state (.vtcode) created while
removing the obsolete post-turn quality stop hook: task checklist,
tool output spools, and tool policy snapshot.
Archive additional VT Code tool output spools generated while
committing and pushing the post-turn hook removal.
@leynos
leynos force-pushed the kill-mutation-survivors branch from e8cde16 to 5f79522 Compare September 9, 2026 11:14
Repository owner deleted a comment from coderabbitai Bot Sep 9, 2026
@leynos

leynos commented Sep 9, 2026

Copy link
Copy Markdown
Owner Author

@coderabbitai Have the following now been resolved?

Remove the obsolete post-turn quality stop hook from this repository.

Replacement project:
https://github.com/leynos/post-turn-quality-stop-hook

Scope:
1. Delete `hooks/post-turn-quality-stop-hook.py`.
2. Delete `hooks/test_post_turn_quality_stop_hook.py`.
3. Update `install-hooks`.
   - Remove installation, validation, and configuration of `post-turn-quality-stop-hook.py`.
   - Preserve all unrelated hook installation behaviour.
4. Update `Makefile`.
   - Remove the `test-hooks` target if it exists only for `hooks/test_post_turn_quality_stop_hook.py`.
   - Remove obsolete comments and dependencies that refer to the post-turn quality stop hook.
   - Preserve unrelated test and CI targets.
5. Search the repository for all remaining references to:
   - `post-turn-quality-stop-hook`
   - `POST_TURN_`
   - `test-hooks`
   - “post-turn hook”
   - “quality stop hook”
   Remove or update each obsolete reference.
6. Add a concise migration note to the user documentation.
   - Update `docs/users-guide.md`.
   - Add a short note to `README.md` if it lists available hooks or installation features.
   - State that this repository no longer provides the post-turn quality stop hook.
   - Direct users to `https://github.com/leynos/post-turn-quality-stop-hook` for installation, configuration, and support.
   - Do not duplicate the replacement project’s installation instructions.
7. Update repository tests and workflow assertions that expect the removed files, targets, or installer behaviour.
8. Run the applicable formatting, test, and CI checks after the removal.

Acceptance criteria:
- No implementation, dedicated test, installer logic, Make target, workflow contract, or documentation claim remains for the obsolete post-turn quality stop hook.
- User documentation directs consumers to `https://github.com/leynos/post-turn-quality-stop-hook`.
- Unrelated hooks, installers, tests, and CI behaviour remain unchanged.
- The repository validation suite passes.

@coderabbitai

coderabbitai Bot commented Sep 9, 2026

Copy link
Copy Markdown

Tip

For best results, initiate chat on the files or code changes.

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
set -euo pipefail

printf '%s\n' '== branch and changed paths =='
git status --short
git diff --name-status HEAD^ HEAD || true

printf '%s\n' '== candidate file presence =='
for path in hooks/post-turn-quality-stop-hook.py hooks/test_post_turn_quality_stop_hook.py install-hooks Makefile README.md docs/users-guide.md; do
  if test -e "$path"; then
    printf 'PRESENT %s\n' "$path"
  else
    printf 'ABSENT  %s\n' "$path"
  fi
done

printf '%s\n' '== outlines of relevant existing files =='
for path in install-hooks Makefile README.md docs/users-guide.md; do
  if test -f "$path"; then
    printf '\n-- %s --\n' "$path"
    ast-grep outline "$path" --items all 2>/dev/null || true
  fi
done

printf '%s\n' '== obsolete hook references (excluding Git metadata) =='
rg -n -i -C 2 \
  -e 'post[- ]turn[- ]quality[- ]stop[- ]hook' \
  -e 'POST_TURN_' \
  -e '\btest-hooks\b' \
  -e 'post[- ]turn hook' \
  -e 'quality stop hook' \
  . -g '!**/.git/**' || true

printf '%s\n' '== replacement URL references (excluding Git metadata) =='
rg -n -C 2 'https://github\.com/leynos/post-turn-quality-stop-hook' . -g '!**/.git/**' || true

printf '%s\n' '== tracked CI and workflow files =='
fd -HI -t f .github . 2>/dev/null | rg '(^|/)(workflows/.*|[^/]*\.(ya?ml|json|toml))$' | sort || true

Length of output: 5458


🏁 Script executed:

#!/bin/bash
set -euo pipefail

gh pr view 50 --repo leynos/agent-helper-scripts \
  --json state,mergeStateStatus,headRefName,statusCheckRollup,files \
  --jq '{
    state,
    mergeStateStatus,
    headRefName,
    files: [.files[].path],
    checks: [.statusCheckRollup[] | {
      name: .name,
      status: .status,
      conclusion: .conclusion,
      workflowName: .workflowName
    }]
  }'

Length of output: 6802


🏁 Script executed:

#!/bin/bash
set -euo pipefail

printf '%s\n' '== installer references and full installer =='
rg -n -i -C 3 'hook|claude|post[- ]turn|quality|POST_TURN|test-hooks' install-hooks || true
cat -n install-hooks

printf '%s\n' '== Makefile references and full Makefile =='
rg -n -i -C 3 'hook|post[- ]turn|quality|POST_TURN|test-hooks|test|ci' Makefile || true
cat -n Makefile

printf '%s\n' '== migration documentation ranges =='
sed -n '20,36p' README.md
sed -n '45,60p' docs/users-guide.md
sed -n '218,233p' docs/developers-guide.md

printf '%s\n' '== tracked path search, including ignored files =='
git ls-files --cached --others --exclude-standard | \
  rg -n -i '(^|/)(post-turn-quality-stop-hook\.py|test_post_turn_quality_stop_hook\.py)$' || true

Length of output: 12412


🏁 Script executed:

#!/bin/bash
set -euo pipefail

gh api --paginate \
  '/repos/leynos/agent-helper-scripts/pulls/50/files?per_page=100' \
  --jq '.[] | {
    filename,
    status,
    additions,
    deletions,
    previous_filename,
    patch: (if .filename == "hooks/post-turn-quality-stop-hook.py" or .filename == "hooks/test_post_turn_quality_stop_hook.py" or .filename == "install-hooks" or .filename == "Makefile" or .filename == "README.md" or .filename == "docs/users-guide.md" or .filename == "docs/developers-guide.md" then .patch else null end)
  }'

Length of output: 79982


@leynos: Treat the hook-removal scope as resolved.

Verified items:

  • hooks/post-turn-quality-stop-hook.py is deleted.
  • hooks/test_post_turn_quality_stop_hook.py is deleted.
  • install-hooks no longer validates, configures, or registers the stop hook.
  • Makefile no longer defines HOOK_TESTS or test-hooks.
  • No remaining POST_TURN_, test-hooks, or obsolete-hook implementation references exist.
  • README.md and docs/users-guide.md direct users to https://github.com/leynos/post-turn-quality-stop-hook.
  • docs/developers-guide.md also documents the move.
  • The Makefile gates CI check succeeded.

Remove the unrelated .vtcode/context/tool_outputs/*, .vtcode/tasks/current_task.md, and .vtcode/tool-policy.json files before merging. These files are outside the requested scope. Their presence means the acceptance criterion for unchanged unrelated repository content is not yet fully met.

The sandbox could not run the repository validation commands. Use the successful Makefile gates CI result as the available validation evidence.


🧠 Learnings used
Learnt from: leynos
URL: https://github.com/leynos/agent-helper-scripts/pull/50

Timestamp: 2026-09-08T22:27:44.774Z
Learning: In `leynos/agent-helper-scripts`, `hooks/post-turn-quality-stop-hook.py`, its installation logic in `install-hooks`, and its dedicated tests are obsolete. Direct consumers to `https://github.com/leynos/post-turn-quality-stop-hook` for the replacement hook.

You are interacting with an AI system.

Untrack the agent tool-output spool; the directory is already ignored.
@leynos

leynos commented Sep 9, 2026

Copy link
Copy Markdown
Owner Author

@coderabbitai Have the following now been resolved?

Remove the unrelated .vtcode/context/tool_outputs/*, .vtcode/tasks/current_task.md, and .vtcode/tool-policy.json files before merging. These files are outside the requested scope. Their presence means the acceptance criterion for unchanged unrelated repository content is not yet fully met.

@coderabbitai

coderabbitai Bot commented Sep 9, 2026

Copy link
Copy Markdown

Tip

For best results, initiate chat on the files or code changes.

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
set -euo pipefail

printf '%s\n' '== Pull request state and changed .vtcode paths =='
gh pr view 50 --repo leynos/agent-helper-scripts \
  --json state,headRefName,baseRefName,statusCheckRollup,files \
  --jq '{
    state,
    headRefName,
    baseRefName,
    vtcodeFiles: [.files[] | select(.path | startswith(".vtcode/")) | .path],
    checks: [.statusCheckRollup[] | {name, status, conclusion}]
  }'

printf '%s\n' '== Checked-out branch: .vtcode diff against merge base =='
base="$(git merge-base HEAD origin/main 2>/dev/null || git merge-base HEAD main)"
git diff --name-status "$base"...HEAD -- .vtcode || true

printf '%s\n' '== Checked-out branch: relevant tracked or untracked files =='
git ls-files --cached --others --exclude-standard -- .vtcode \
  | rg -n '(^\.vtcode/context/tool_outputs/|^\.vtcode/tasks/current_task\.md$|^\.vtcode/tool-policy\.json$)' \
  || true

printf '%s\n' '== Working-tree changes in .vtcode =='
git status --short -- .vtcode || true

Length of output: 1872


@leynos: Treat this finding as resolved.

PR #50 contains no changed paths under .vtcode/.

The branch also has no .vtcode diff relative to main. This covers:

  • .vtcode/context/tool_outputs/*
  • .vtcode/tasks/current_task.md
  • .vtcode/tool-policy.json

Makefile gates also completed successfully.

You are interacting with an AI system.

@leynos
leynos merged commit b74131e into main Sep 9, 2026
5 checks passed
@leynos
leynos deleted the kill-mutation-survivors branch September 9, 2026 17:48
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Mutation testing: run() subprocess wrapper survivors

2 participants