Skip to content

Fully test the isolated mutation runner - #1951

Merged
stefan-burke merged 7 commits into
mainfrom
claude/mutation-check-isolation
Jul 27, 2026
Merged

Fully test the isolated mutation runner#1951
stefan-burke merged 7 commits into
mainfrom
claude/mutation-check-isolation

Conversation

@stefan-burke

@stefan-burke stefan-burke commented Jul 27, 2026

Copy link
Copy Markdown
Member

This is the next chunk of the work started in #1944: taking one scripts/ file at a time up to a full mutation score, so its tests really would catch a change to it.

What changed

scripts/mutation/isolation.ts now scores 100% — 155 of 155 mutants caught, up from 68.6%.

The biggest reason it scored badly was not missing tests but misplaced ones. The mutation gate only looks at tests kept in a folder that mirrors the source file's path, and one whole test file sat outside that folder, so it was never run. Moving it into place lifted the score to 95.5% before a single new test was written.

The same problem turned out to be hiding a second one, which a reviewer spotted: a file of tests for isolation-state.ts sat in the folder mirroring isolation.ts, so those assertions never ran against isolation-state mutants either. Moving them takes that file from 65.5% to 78.3%, again without writing anything new.

Along the way:

  • Split the oversized test files. The tests for this area were two long files; they are now six focused ones, each well under the 400-line limit, sharing one helpers file. Smaller files also make mutation runs much faster.
  • Made a matching test folder for isolation-state.ts, which had none at all, so the gate can now see its tests too.
  • Fixed a real gap in how a run records itself. A run writes its record to disk, then queues for a lock. A cleanup running in that gap sees a run whose lock is not yet held, treats it as abandoned, and deletes the record — leaving the snapshot it then makes belonging to no run anyone could list or stop. The run now writes its record again once it holds the lock, so it puts itself back. Two tests cover it, and both fail without the fix.
  • New tests for the things nothing checked before: that the child is told it is running inside a snapshot, that the record lands on disk before the run queues, that a child which stops politely is never force-killed, that a finished run is not signalled even when its recorded pid is still alive, and that listing a stale run never shells anything out.
  • Stopped two tests starting real child processes. They ran a real mutation child inside a temporary folder that was then deleted, which broke the coverage report. They now use a stand-in command, and check more as a result.
  • One mutant is recorded as impossible to catch, with a written explanation: an initial exit code that every path overwrites before it is returned.

Left for later

There is a narrower version of the cleanup problem this does not fix: a cleanup that decides a run is abandoned and only then removes it can still delete a run that took the lock in between. No amount of rewriting the record can fix that one — the cleanup has to hold the run's lock across both steps, which is a behaviour change with its own design to think through. It is written up in TODO.md.

scripts/mutation/isolation-state.ts is the next chunk, now at 78.3%.

claude added 2 commits July 27, 2026 07:44
Its supervisor tests were sitting in a file the gate could not match to it,
so more than half of what they check was invisible: moving them into the
mirror folder alone took the score from 68.6% to 95.5%.

The rest are new checks — that the child is told it is running in a snapshot,
that its pid is printed, that the run record is written before the wait for
the lock, that a finished run is never signalled however alive its pid looks,
and that a stopping child gets its moment to end before being forced. Drops a
second write of the same record that the write above it had already done.

The isolation-state tests move to their own mirror folder as well, which is
where they belonged; that file can now be mutation-checked too.
Two tests started a real mutation child inside a temporary folder that was
then deleted, so the coverage report pointed at files that no longer existed
and failed with "No coverage data found". Both now use a stand-in command,
which also lets them check exactly how the child was started.

Also folds the two record waiters onto one shared loop and drops the unused
branches the coverage run flagged in the test helpers.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01EJqdnQoBuuQkQCFVcQHcVn
@coderabbitai

coderabbitai Bot commented Jul 27, 2026

Copy link
Copy Markdown
Contributor

Review Change Stack

Warning

Review limit reached

You’ve reached a temporary PR review limit under our Fair Usage Limits Policy.

Your recent review volume is higher than typical usage, so adaptive limits are currently applied.

Next review available in: 2 minutes

Enable usage-based reviews in Billing to review now. Otherwise, wait until the next included review is available.
You're only billed for reviews past your plan's rate limits ($0.25/file).

How can I continue?

After more reviews become available, a review can be triggered using the @coderabbitai review command as a PR comment. Alternatively, push new commits to this PR.

To avoid repeated limits, reduce automatic review volume by pausing incremental auto-reviews earlier, using label-based review opt-in, excluding WIP or generated PR titles, or requesting reviews manually when the PR is ready. If your team needs uninterrupted high-volume reviews, an organization admin can enable usage-based reviews.

How do review limits work?

CodeRabbit enforces per-developer PR review limits for each organization. Most developers receive the normal plan review availability.

For paid Pro and Pro+ PR reviews, CodeRabbit uses adaptive limits for sustained high-volume activity. When a developer's recent PR review activity reaches the 95th percentile or higher among CodeRabbit users, additional reviews become available more gradually as earlier reviews age out of the rolling window.

Please refer docs for additional details.

Review details
⚙️ Run configuration

Configuration used: Organization UI

Review profile: ASSERTIVE

Plan: Pro Plus

Run ID: 81d31ce9-a313-47ad-8388-6aa70f64c37f

📥 Commits

Reviewing files that changed from the base of the PR and between 3997c2b and fe18f73.

📒 Files selected for processing (5)
  • TODO.md
  • test/scripts/mutation/isolation-state/commands.test.ts
  • test/scripts/mutation/isolation/commands.test.ts
  • test/scripts/mutation/isolation/helpers.ts
  • test/scripts/mutation/isolation/snapshot-runs.test.ts
📝 Walkthrough

Walkthrough

Changes

Mutation isolation

Layer / File(s) Summary
Isolation state coverage
test/scripts/mutation/isolation-state/*, test/scripts/mutation/isolation/commands.test.ts
Adds coverage for snapshot paths, argument rewriting, run-record lifecycle and persistence, timestamps, lock state, and reorganizes command tests.
Isolation test harness
test/scripts/mutation/isolation/helpers.ts
Adds reusable helpers for record polling, failure injection, signal capture, command stubbing, clean-race simulation, and controlled child processes.
Command and snapshot-run coverage
test/scripts/mutation/isolation/list-and-kill.test.ts, test/scripts/mutation/isolation/snapshot-runs.test.ts, scripts/mutation/isolation.ts, scripts/mutation/equivalent-mutants.txt
Tests listing, signalling, cleaning, snapshot execution, interruption, termination, and startup failures; documents lock-record rewriting and an equivalent mutant.

Estimated code review effort: 4 (Complex) | ~45 minutes

Possibly related PRs

🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title clearly reflects the main change: adding comprehensive tests for the isolated mutation runner.
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch claude/mutation-check-isolation
✨ Simplify code
  • Create PR with simplified code
  • Commit simplified code in branch claude/mutation-check-isolation

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

@chatgpt-codex-connector chatgpt-codex-connector 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.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 7502371dc8

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread scripts/mutation/isolation.ts
Comment thread test/scripts/mutation/isolation/snapshot-runs.test.ts Outdated
Comment thread test/scripts/mutation/isolation/helpers.ts Outdated
Comment thread test/scripts/mutation/isolation/helpers.ts Outdated
Comment thread test/scripts/mutation/isolation/helpers.ts Outdated
Comment thread test/scripts/mutation/isolation/helpers.ts Outdated
Puts back the run record write inside the lock. It is not a duplicate of the
one before it: a clean sweeping the folder in the gap between them sees a run
whose lock is not yet held, treats it as abandoned, and removes it. Writing
again once the lock is held puts the record back, so the snapshot about to be
made still belongs to a run that can be listed and stopped. Two tests cover
this — one for the record landing before the run queues, one for it being
written again after a clean takes it away.

Also replaces the exported Deno alias with a helper that does the stubbing,
gives every exported test helper a return type, uses Promise.withResolvers
instead of an uninitialised resolver, and drops helpers nothing calls.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01EJqdnQoBuuQkQCFVcQHcVn

@chatgpt-codex-connector chatgpt-codex-connector 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.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 3997c2bde2

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread test/scripts/mutation/isolation/helpers.ts Outdated

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Actionable comments posted: 2

🤖 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 `@test/scripts/mutation/isolation/helpers.ts`:
- Around line 36-64: Consolidate failTextFileWrites and failRunningStatusWrite
into a single writeTextFile failure-injector helper that accepts a write
predicate, reusing one shared stub implementation. Make failRunningStatusWrite
delegate to that helper with its existing running-status data predicate,
preserving both current failure behaviors and error messages.

In `@test/scripts/mutation/isolation/snapshot-runs.test.ts`:
- Around line 44-52: Update the pid assertion in the mutation run test to check
for the exact interpolated string directly, replacing the RegExp construction
inside run.logs.some. Preserve the existing full-line match behavior using
record.pid.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: ASSERTIVE

Plan: Pro Plus

Run ID: 0d14f244-bca9-41dc-8443-4427d7157fbd

📥 Commits

Reviewing files that changed from the base of the PR and between 8ad91c8 and 3997c2b.

📒 Files selected for processing (9)
  • scripts/mutation/equivalent-mutants.txt
  • scripts/mutation/isolation.ts
  • test/scripts/mutation/isolation-state/paths.test.ts
  • test/scripts/mutation/isolation-state/records.test.ts
  • test/scripts/mutation/isolation-supervisor.test.ts
  • test/scripts/mutation/isolation/commands.test.ts
  • test/scripts/mutation/isolation/helpers.ts
  • test/scripts/mutation/isolation/list-and-kill.test.ts
  • test/scripts/mutation/isolation/snapshot-runs.test.ts
💤 Files with no reviewable changes (2)
  • test/scripts/mutation/isolation-supervisor.test.ts
  • test/scripts/mutation/isolation/commands.test.ts

Comment thread test/scripts/mutation/isolation/helpers.ts Outdated
Comment thread test/scripts/mutation/isolation/snapshot-runs.test.ts Outdated
A real clean removes the run's entire folder, not just its record, so the
stand-in now does the same and lets the lock's own mkdir put the folder back.
That is the ordering the run has to survive.

Also folds the two write-failure stand-ins into one, and asserts the pid line
directly instead of building a regular expression for it.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01EJqdnQoBuuQkQCFVcQHcVn

@chatgpt-codex-connector chatgpt-codex-connector 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.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 5d65ab351c

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread scripts/mutation/isolation.ts
Comment thread test/scripts/mutation/isolation/commands.test.ts Outdated
claude added 2 commits July 27, 2026 09:29
The tests for parsing a command, picking runs by target, and formatting the
run list all check isolation-state.ts, but they sat in the folder mirroring
isolation.ts. The mutation gate only runs a source's own mirrored folder, so
those assertions never ran against isolation-state mutants. Moving them takes
that file from 65.5% to 78.3% without a single new test. The clean-command
tests stay where they are, since they go through isolation.ts.

Also records the remaining clean race in TODO.md: a clean that decides a run is
abandoned and only then removes it can still delete a run that took the lock in
between. No record write can close that window — the clean has to hold the lock
across both steps.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01EJqdnQoBuuQkQCFVcQHcVn

@chatgpt-codex-connector chatgpt-codex-connector 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.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: f1d629f610

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread test/scripts/mutation/isolation/helpers.ts Outdated
Neither is used outside the helpers file, so exporting them offered a shared
API nothing shares.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01EJqdnQoBuuQkQCFVcQHcVn
@stefan-burke
stefan-burke added this pull request to the merge queue Jul 27, 2026
Merged via the queue into main with commit e383011 Jul 27, 2026
3 checks passed
@stefan-burke
stefan-burke deleted the claude/mutation-check-isolation branch July 27, 2026 10:05
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants