Skip to content

[codex] Isolate mutation test runs - #1682

Merged
stefan-burke merged 8 commits into
mainfrom
codex/isolate-mutation-runs
Jul 10, 2026
Merged

[codex] Isolate mutation test runs#1682
stefan-burke merged 8 commits into
mainfrom
codex/isolate-mutation-runs

Conversation

@stefan-burke

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

Copy link
Copy Markdown
Member

What changed

Mutation tests now run inside a copied checkout at .mutation-runs/<id>/work, so the live working tree is not mutated while the existing mutation engine still works in place inside the copy.

Each isolated run records its status and child PID in .mutation-runs/<id>/run.json. The mutation command can now list runs, kill live runs, and clean finished or stale runs.

The review follow-up tightened the run management paths: live checks no longer depend on /proc, reused PIDs are treated as stale unless the per-run lock is held, cleanup uses the current .mutation-runs/<id> directory instead of trusting stale JSON paths, and active copying/running snapshots are skipped by cleanup.

The precommit mutation gate uses the same isolated runner as manual mutation commands.

Why

Mutation testing used to write directly into live files and could leave hard-to-identify subprocesses running. This makes mutation runs visible, removable, and much less likely to interfere with normal work.

Checks

  • deno task typecheck
  • deno task test:files test/scripts/mutation-isolation.test.ts test/scripts/mutation-isolation-supervisor.test.ts
  • deno task lint:ci
  • deno task cpd
  • deno task test:coverage
  • GitHub PR checks: test, CodeRabbit, and both deploy checks passed

Full deno task precommit was not rerun, per request.

@coderabbitai

coderabbitai Bot commented Jul 9, 2026

Copy link
Copy Markdown
Contributor

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
📝 Walkthrough

Walkthrough

Adds isolated mutation-run execution in a copied working checkout with persisted run records and CLI controls, updates the mutation entrypoints to use it, and expands tests and docs. Also adds a shared filesystem existence helper and adjusts stripe-mock test timing.

Changes

Mutation isolation runner

Layer / File(s) Summary
Run record and snapshot copy state module
scripts/mutation/isolation-state.ts
Defines isolation constants, snapshot-copy filtering, run record types, path helpers, persistence, argument rewriting, CLI parsing, lock handling, and formatting helpers.
Isolated run supervisor and CLI commands
scripts/mutation/isolation.ts
Implements process liveness checks, run signaling, snapshot child environment setup, isolated run execution, and the list/kill/clean/help dispatcher.
Mutation script and precommit wiring
scripts/mutation.ts, scripts/precommit-mutation.ts
Routes the mutation CLI through isolated execution, loads the runner dynamically, and converts precommit mutation inputs into argv-style arguments for snapshot runs.
Isolation tests and docs
test/scripts/mutation-isolation.test.ts, test/scripts/mutation-isolation-helpers.ts, test/scripts/mutation-isolation-supervisor.test.ts, .gitignore, AGENTS.md
Adds tests for snapshot copying, run records, command parsing, list formatting, environment matching, and documents the isolated mutation workflow.

Test utility and stripe-mock test adjustments

Layer / File(s) Summary
pathExists helper and coverage tests
test/test-utils/files.ts, test/scripts/test-coverage.test.ts
Adds a shared pathExists helper and uses it in coverage tests with additional filesystem assertions.
Stripe-mock test updates
test/lib/stripe-mock/install.test.ts, test/lib/stripe-mock/ports.test.ts
Changes the install test to write a pending binary before renaming it, and relaxes shutdown timing in the unresponsive mock stop test.

Sequence Diagram(s)

sequenceDiagram
  participant DenoTask as deno task mutation
  participant IsolationCLI as scripts/mutation.ts
  participant Supervisor as scripts/mutation/isolation.ts
  participant SnapshotRun as scripts/mutation.ts child
  participant RunState as scripts/mutation/isolation-state.ts

  DenoTask->>IsolationCLI: start with mutation args
  IsolationCLI->>Supervisor: runIsolatedMutationCommand(Deno.args)
  Supervisor->>RunState: createRunId, newRunRecord, copyMutationSnapshot
  Supervisor->>SnapshotRun: spawn with MUTATION_* env vars and rewritten args
  SnapshotRun->>RunState: withMutationRunLock / read and write run.json
  SnapshotRun->>Supervisor: exit code and status
  Supervisor->>RunState: markFinished / markInterrupted
Loading

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

🚥 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 is concise and accurately summarizes the main change: isolating mutation test runs.
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch codex/isolate-mutation-runs

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

@stefan-burke
stefan-burke marked this pull request as ready for review July 9, 2026 14:35

@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: 27bc9a0552

ℹ️ 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-state.ts Outdated
Comment thread scripts/mutation/isolation-state.ts
Comment thread scripts/mutation/isolation.ts Outdated
@stefan-burke
stefan-burke force-pushed the codex/isolate-mutation-runs branch from 32c67ae to ac81824 Compare July 9, 2026 17:28

@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: 1

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
scripts/mutation/isolation.ts (1)

167-175: 🎯 Functional Correctness | 🟡 Minor | ⚡ Quick win

Record interrupted runs as interrupted in scripts/mutation/isolation.ts:167-175. In the post-spawn path, child.status.code will usually be the signal exit code (typically 143 for SIGTERM), so markFinished(record, status.code) stores failed; the catch branch already maps 130 to interrupted.

🤖 Prompt for 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.

In `@scripts/mutation/isolation.ts` around lines 167 - 175, The post-spawn
completion path in the isolation runner is treating signal-based exits as failed
instead of interrupted. Update the `child.status` handling in
`scripts/mutation/isolation.ts` so `markFinished` uses the same interruption
mapping as the `catch` branch, and ensure `writeRunRecord` persists
`interrupted` for signal exits such as SIGTERM rather than storing the raw
status code. Refer to the `child.status`, `markFinished`, and `writeRunRecord`
flow when making the fix.
🤖 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.test.ts`:
- Around line 234-262: The test combines multiple concerns in one body, making
failures hard to attribute to a specific unit. Split the assertions in
mutation-isolation.test.ts into separate tests: keep one focused on selectedRuns
filtering using the minimal record fixtures needed, and move
visibleStatus/formatRunList coverage into its own test with only the fixtures
required. Use the existing helpers newRunRecord, markRunning, markFinished, and
markInterrupted only where they are necessary for each specific behavior.

---

Outside diff comments:
In `@scripts/mutation/isolation.ts`:
- Around line 167-175: The post-spawn completion path in the isolation runner is
treating signal-based exits as failed instead of interrupted. Update the
`child.status` handling in `scripts/mutation/isolation.ts` so `markFinished`
uses the same interruption mapping as the `catch` branch, and ensure
`writeRunRecord` persists `interrupted` for signal exits such as SIGTERM rather
than storing the raw status code. Refer to the `child.status`, `markFinished`,
and `writeRunRecord` flow when making the fix.
🪄 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: 7bb82122-c119-4cfb-a15a-5b308056b931

📥 Commits

Reviewing files that changed from the base of the PR and between 27bc9a0 and 32c67ae.

📒 Files selected for processing (3)
  • scripts/mutation/isolation-state.ts
  • scripts/mutation/isolation.ts
  • test/scripts/mutation-isolation.test.ts

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

@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: ac81824e93

ℹ️ 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 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 `@scripts/mutation/isolation.ts`:
- Line 32: The re-export of MUTATION_SNAPSHOT_CHILD_ENV in isolation.ts is
unnecessary because it only forwards the constant unchanged. Remove that alias
export and update scripts/mutation.ts to import MUTATION_SNAPSHOT_CHILD_ENV
directly from isolation-state.ts, keeping runIsolatedMutationCommand unchanged
and avoiding the extra forwarding layer.
- Around line 43-62: The liveness check in processBelongsToRun relies on
processEnv reading /proc/<pid>/environ, which is Linux-only and breaks non-Linux
behavior. Update the processBelongsToRun/processEnv flow to avoid
unconditionally reading /proc: either gate the /proc-based logic behind a
Linux-only check or replace it with a cross-platform way to verify the mutation
run identity, so --list, --kill, and cleanup paths can still recognize running
workers on macOS.
🪄 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: 9c04aade-234f-4a36-873c-a751940deb0f

📥 Commits

Reviewing files that changed from the base of the PR and between 32c67ae and ac81824.

📒 Files selected for processing (11)
  • .gitignore
  • AGENTS.md
  • scripts/mutation.ts
  • scripts/mutation/isolation-state.ts
  • scripts/mutation/isolation.ts
  • scripts/precommit-mutation.ts
  • test/lib/stripe-mock/install.test.ts
  • test/lib/stripe-mock/ports.test.ts
  • test/scripts/mutation-isolation.test.ts
  • test/scripts/test-coverage.test.ts
  • test/test-utils/files.ts

Comment thread scripts/mutation/isolation.ts Outdated
Comment thread scripts/mutation/isolation.ts Outdated
@stefan-burke
stefan-burke force-pushed the codex/isolate-mutation-runs branch from ac81824 to dbc2cde Compare July 9, 2026 17:49

@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: dbc2cde694

ℹ️ 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 Outdated
Comment thread scripts/mutation/isolation.ts Outdated
@stefan-burke
stefan-burke force-pushed the codex/isolate-mutation-runs branch from dbc2cde to f6acf04 Compare July 9, 2026 18:07
@stefan-burke
stefan-burke force-pushed the codex/isolate-mutation-runs branch from f6acf04 to 442cf62 Compare July 9, 2026 19:15

@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-supervisor.test.ts`:
- Line 245: `readRunRecords(root)` can return an empty array, so the repeated
`const [record] = await readRunRecords(root);` destructures in
`mutation-isolation-supervisor.test.ts` leave `record` possibly undefined and
fail typechecking when accessing its fields. Add a shared narrowing helper in
`mutation-isolation-helpers.ts` (for example, a first-record accessor that calls
`readRunRecords` and throws if no record exists), then replace each destructure
with that helper in the affected test cases so `record.status`,
`record.exitCode`, and similar accesses are always on a defined value.
- Around line 172-175: The `calls` and `killCalls` arrays in the `Deno.kill`
stubs are using an optional `signal?: Deno.Signal` shape, but the stub records
`signal` as `Deno.Signal | undefined`, which breaks under
`exactOptionalPropertyTypes`. Update the recorded type in the relevant test
helpers (`stub(Deno, "kill")` and the `killCalls` collector) so `signal`
explicitly allows `undefined`, or otherwise avoid pushing an explicit
`undefined` value for that property; keep the shape consistent wherever the
kill-call objects are created.
🪄 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: 7e274c6e-db9a-42d2-8a7e-d0986d66359f

📥 Commits

Reviewing files that changed from the base of the PR and between f6acf04 and 442cf62.

📒 Files selected for processing (6)
  • scripts/mutation.ts
  • scripts/mutation/isolation-state.ts
  • scripts/mutation/isolation.ts
  • test/scripts/mutation-isolation-helpers.ts
  • test/scripts/mutation-isolation-supervisor.test.ts
  • test/scripts/mutation-isolation.test.ts

Comment thread test/scripts/mutation-isolation-supervisor.test.ts Outdated
Comment thread test/scripts/mutation-isolation-supervisor.test.ts Outdated

@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: 454102c22e

ℹ️ 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 Outdated

@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: 01dce176c4

ℹ️ 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 scripts/mutation/isolation.ts Outdated
Comment thread scripts/mutation/isolation.ts Outdated
Comment thread scripts/mutation/isolation.ts Outdated
@stefan-burke

Copy link
Copy Markdown
Member Author

Re: Stop the child when recording its PID fails

Addressed in 4023986. If writeRunRecord throws after the child has spawned inside withMutationRunLock (lines 183-205), the catch block at line 215-223 calls stopProcess(child, 250) to terminate and reap the child before marking the run failed. Covered by the stops the child when recording the running pid fails regression test.

@stefan-burke

Copy link
Copy Markdown
Member Author

Re: Allow stale copying runs to be cleaned (scripts/mutation/isolation.ts:94)

Addressed in 4023986. The copyingRunStillActive predicate (lines 42-45) now requires runLockIsHeld(record) to be true, not just status === "copying". If the supervisor dies mid-copy, the OS releases the advisory flock, so runLockIsHeld returns false and the orphaned copying record becomes cleanable. The lock probe runs in a short-lived child process so a timed-out probe does not leak pending file-lock operations. Covered by the removes stale copying runs regression test in mutation-isolation-supervisor.test.ts.

@stefan-burke

Copy link
Copy Markdown
Member Author

Re: Use a portable liveness probe

Addressed in 4023986. The /proc environ check and the kill -0 external command were both removed. processExists (scripts/process.ts:18-25) now uses Node's process.kill(pid, 0), which is a portable signal-0 existence check working on Linux, macOS, and Windows — no external executable required. Covered by test/scripts/process.test.ts.

@stefan-burke

Copy link
Copy Markdown
Member Author

Re: Do not report failed cleanup as removed

Addressed in 4023986. removeRun (lines 70-82) only suppresses Deno.errors.NotFound; every other error returns { error, removed: false }. cleanRuns (lines 286-298) then prints Failed to remove <id>: <error> to stderr for each failure and returns exit code 1 when any removal failed. Covered by the reports removal failures instead of claiming success regression test.

@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: 402398666f

ℹ️ 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 Outdated
runningProcessStillExists now requires the run lock to be held OR the
record to be within a 30s startup grace, so a stale running record
whose PID was reused by an unrelated process becomes cleanable once
the grace expires. Fixes the last outstanding Codex review comment.

@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: 14c856fd49

ℹ️ 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

@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: e313e9af04

ℹ️ 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/precommit/mutation-step.ts
Comment thread scripts/mutation/isolation-state.ts
Comment thread test/scripts/mutation-isolation-supervisor.test.ts
Restructure the stopProcess call in the catch block to avoid an
unreachable defensive catch (stopProcess already handles kill errors
internally). Fix the test stub to target the running-status write
specifically rather than counting global writeTextFile calls, which
was misfiring because writeFakeMutationScript also uses writeTextFile.
@stefan-burke
stefan-burke enabled auto-merge July 10, 2026 01:05
@stefan-burke
stefan-burke added this pull request to the merge queue Jul 10, 2026
Merged via the queue into main with commit b8053eb Jul 10, 2026
3 checks passed
@stefan-burke
stefan-burke deleted the codex/isolate-mutation-runs branch July 10, 2026 01:19

@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: 4d74f54cc1

ℹ️ 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
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.

1 participant