Repository navigation
ci: fork mutmut mutants from a fork server, not from the suite's process (ADR-1122) - #906
Merged
Merged
Conversation
…ess (ADR-1122) mutmut's default fork isolation forks every mutant from the process that already ran the suite. On the Linux runner the child then hangs in torch autograd (titans_memory.py loss.backward) until mutmut times it out, and a timeout fails the gate: #877's 26 _resolve_domain mutants all timed out, and #878 was cancelled at the six-hour job limit. Reproduced in an Ubuntu 26.04 container set up as ci.json "unit" on 11 mutants of #878: fork, 5 of the first 7 timed out (py-spy: child idle in backward()); forkserver, 0 of 11 timed out in 71 s. mutmut 3.8.1 documents forkserver for test setups that are not fork-safe (gevent, grpc, torch).
Codex Review SummaryThis comment shows the latest Codex review activity on this pull request.
ℹ️ About Codex in GitHubYour team has set up Codex to review pull requests in this repo. Reviews are triggered when you
Codex reacts with 👀 while any review is running, comments if it has suggestions, and reacts with 👍 once all reviews finish with no findings. |
|
Claude finished @cdeust's task in 4m 16s —— View job Review of PR #906 (1 of 3)
No Blockers. The full review is in this comment.
Verdict: approve |
Review 1 of 3: PR #906I ran five reviews: code quality, documentation accuracy, performance, security and test coverage. No Blockers.
Notes, no action before merge
Verdict: approve |
This was referenced Nov 6, 2026
Merged
github-actions Bot
pushed a commit
that referenced
this pull request
Nov 6, 2026
#906 set process_isolation = "forkserver" for every platform. On macOS that aborts before any mutant runs: the stats run, now in a forked child, imports sentence_transformers, whose torch.backends.mps.is_available() ends in SIGABRT (Child exited with code -6). Local runs on macOS, the autopilot's included, could no longer run the gate. mutation_check.sh now rewrites process_isolation from ci_mutation_scope.py: forkserver on Linux (fork hangs in torch autograd there), fork on macOS (measured again: 11 mutants of #878, 76 s, 0 timeouts). Any other platform stops the gate instead of guessing.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Problem
On the Linux runner the mutation gate reports timeouts instead of verdicts:
_resolve_domainmutants⏰.unitcancelled at the six-hour job limit.recall.pyhad 141⏰out of 272 mutants run;telemetry.pyhad 29 out of 29.ADR-1122 counts a timeout as a mutant not killed, so the gate fails after burning hours.
Root cause
mutmut 3.8.1 defaults to
process_isolation = "fork": each mutant is forked from the main process, which has already run the suite (the stats and clean-test runs). The forked child inherits torch's state and, on Linux, stays idle inloss.backward()(mcp_server/core/titans_memory.py) until mutmut kills it.Evidence
Same 11 mutants (
telemetry.x_publish_record__mutmut_1*, #878 head 64ae942), PostgreSQL 18.6:ci.json"unit" (Python 3.12, extras dev/sqlite/codebase/postgresql)During the hang,
py-spy dumpof the child shows the main thread inTitansMemory.update→loss.backward(), with no CPU used. Between the platforms, one verdict differs:mutmut_17is killed on Linux and survives on macOS.Fix
process_isolation = "forkserver"in[tool.mutmut]. mutmut 3.8.1 documents this mode "for test setups that are not fork-safe (gevent, grpc, torch)": mutants are forked from a dedicated server that has never run a test. There is no timeout calibration, because the limits were not too short; the children were deadlocked.pyproject.toml: the setting, with its source.tests_py/scripts/test_mutation_isolation.py: locks the setting; it fails ifforkcomes back.Checks
ruff check/ruff format --checkclean on the touched files. The 8 E501 left on main predate this PR (2fa3fd6, 98e5f39).python scripts/check_craftsmanship.py: OK.fork.mcp_server/, so its own mutation gate has nothing to run. The fix will show on the next CI runs of fix(remember): keep an explicit domain instead of remapping it by substring (#721, slice 1) #877 and feat(telemetry): carry a per-stage latency breakdown in every telemetry sample (#722, slice 1) #878.