Skip to content

Fix mutmut baseline crash on cwd-relative tests (#196) - #198

Draft
leynos wants to merge 1 commit into
mainfrom
fix/mutmut-baseline-tmp-path
Draft

Fix mutmut baseline crash on cwd-relative tests (#196)#198
leynos wants to merge 1 commit into
mainfrom
fix/mutmut-baseline-tmp-path

Conversation

@leynos

@leynos leynos commented Jul 21, 2026

Copy link
Copy Markdown
Owner

Summary

  • mutmut's baseline pytest run has never completed for lading: it aborted
    deterministically on test_run_normalises_workspace_root
    (tests/unit/publish/test_run_workspace_config.py) with
    FileNotFoundError, treated as a fatal error by mutmut
    (mutation_mutmut_error=mutmut run failed with exit code 1 (failing baseline?)), so no mutants were ever generated.
  • Root cause (confirmed by reproducing locally with
    uv run --with mutmut==3.6.0 mutmut run): mutmut instruments every mutated
    call with a trampoline that resolves [tool.mutmut] source_paths
    ("lading/") against the current working directory, with
    strict=True, on every hit
    (mutmut/__main__.py::record_trampoline_hit). Five unit tests call
    monkeypatch.chdir(tmp_path) to exercise cwd-relative path resolution
    (workspace-root defaulting, relative build directories). Chdir'ing into a
    bare tmp_path starves that lookup of a "lading" directory and crashes
    the trampoline with FileNotFoundError — not a tmp_path race, as the
    issue's title suggested; the failure is 100% deterministic whenever the
    baseline actually executes one of these tests.
  • Fix: add tests/helpers/cwd.py::chdir_for_test(monkeypatch, path), a
    drop-in replacement for monkeypatch.chdir(path) that pre-creates a
    "lading" placeholder directory so the trampoline's existence check
    succeeds regardless of harness. It is inert under plain pytest, where no
    such instrumentation exists. Routed all five affected call sites through
    it:
    • tests/unit/publish/test_run_workspace_config.py
    • tests/unit/test_bump_manifest_updates.py
    • tests/unit/test_publish_staging.py
    • tests/unit/test_cli.py (two call sites)
  • Also gitignore mutmut's local working copy (/mutants/,
    .mutmut-cache), discovered untracked while reproducing this issue
    locally; cargo-mutants' mutants.out*/ was already ignored but mutmut's
    own directory was not.

Closes #196

Why not exclude the test instead

Excluding test_run_normalises_workspace_root (or disabling the cwd-related
assertion) would have been the easy way out, but the chdir is the point of
the test: it verifies that publish.run (and the equivalent bump/CLI
helpers) resolve relative workspace-root arguments against the process's
current working directory. That is real, load-bearing behaviour. The actual
defect is an incidental interaction between that legitimate test behaviour
and mutmut's own trampoline instrumentation, which is fully addressed by
giving the trampoline the directory it expects, without changing what the
tests assert.

Validation

Reproduced with uv run --with mutmut==3.6.0 mutmut run from a clean
mutants//.mutmut-cache state:

Before (red): baseline stats collection aborts —
FAILED tests/unit/publish/test_run_workspace_config.py::test_run_normalises_workspace_root
with FileNotFoundError: ... /test_run_normalises_workspace_0/lading,
failed to collect stats. runner returned 1.

After (green) for the five originally-crashing call sites: the same
baseline run no longer fails on any of them; mutmut's "Running stats" phase
completes the full suite (718 passed, 6 skipped).

Separate, unrelated finding (not fixed here, not part of #196): mutmut's
baseline additionally re-runs the full suite a second time in the same
process ("Running clean tests"), and Python does not support repeated
in-process pytest.main() invocations cleanly — Hypothesis raises
FailedHealthCheck: differing_executors on the second pass, and a stale
logging handler from the first pass causes an unrelated
test_cmd_mox_passthrough_streams_output assertion to fail. Reproduced this
directly (without mutmut) by calling pytest.main() twice in one process.
This is a distinct, deeper defect in how mutmut's baseline is structured/
configured for Hypothesis-using suites, out of scope for this PR; noted for
the orchestrator to file as a follow-up.

Standard gates (make lint, make check-fmt, make typecheck, make test) run via the project's commit-gate process; see CI status on this PR.

Review walkthrough

mutmut instruments every mutated call with a trampoline that resolves
`[tool.mutmut] source_paths` ("lading/") against the current working
directory, with strict=True, on every hit
(mutmut/__main__.py::record_trampoline_hit). Five unit tests chdir into
a bare tmp_path to exercise cwd-relative path resolution (workspace-root
defaulting, relative build directories); doing so starves that lookup
of a "lading" directory and crashes mutmut's baseline with
FileNotFoundError before any mutants are generated.

Add tests/helpers/cwd.py::chdir_for_test, a drop-in replacement for
monkeypatch.chdir(tmp_path) that pre-creates a "lading" placeholder
directory so the trampoline's existence check succeeds regardless of
harness, and route the five affected call sites through it.

Reproduced locally with `uv run --with mutmut==3.6.0 mutmut run`:
baseline failed deterministically before this change and passes after.

@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

@coderabbitai

coderabbitai Bot commented Jul 21, 2026

Copy link
Copy Markdown

Important

Review skipped

Draft detected.

Please check the settings in the CodeRabbit UI or the .coderabbit.yaml file in this repository. To trigger a single review, invoke the @coderabbitai review command.

⚙️ Run configuration

Configuration used: Organization UI

Review profile: ASSERTIVE

Plan: Pro Plus

Run ID: a09f008b-ca2e-4b88-94de-fedfdaccd485

You can disable this status message by setting the reviews.review_status to false in the CodeRabbit configuration file.

Use the checkbox below for a quick retry:

  • 🔍 Trigger review
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch fix/mutmut-baseline-tmp-path

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

@codescene-access codescene-access 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.

Our agent can fix these. Install it.

Gates Passed
6 Quality Gates Passed

Absence of Expected Change Pattern

  • lading/tests/unit/test_cli.py is usually changed with: lading/lading/cli.py, lading/lading/commands/bump.py

Quality Gate Profile: Pay Down Tech Debt
Install CodeScene MCP: safeguard and uplift AI-generated code. Catch issues early with our IDE extension and CLI tool.

@codescene-access codescene-access 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.

No quality gates enabled for this code.

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.

Fix intermittent tmp_path FileNotFoundError in test_run_normalises_workspace_root

1 participant