Repository navigation
Conversation
…e is `src` Projects whose import package is literally `src` (flat layout: `src/__init__.py`, imports like `from src.calc import ...`) cannot run mutmut 3.8: 1. `get_mutant_name` unconditionally strips a `src.` prefix from module names — correct for the src-layout convention (`src/` is only a container), but for a flat layout the stripped names no longer match the imported modules, so the trampoline routing (`module != decorated_func.__module__`) never applies any mutant, the stats keys diverge (`"collection_queue.x_foo"` recorded as `"src.collection_queue.x_foo"`), and `record_trampoline_hit` asserts out during stats collection. Add a `[tool.mutmut] strip_src_prefix` config (default `true` = current behavior). With `false`, mutant names keep the full `src.`-prefixed module path, which makes routing, stats keys, and the assert all consistent. The sandbox already imports flat layouts correctly (`mutants/` on sys.path), so no other changes are needed. - `configuration.py`: new `strip_src_prefix: bool = True` config field. - `utils/format_utils.py`: `get_mutant_name` strips only when configured. - `mutation/stats.py`: the `src.` assert only fires while stripping is active (and now points flat-layout users at the new knob). - New e2e fixture `e2e_projects/flat_src` (`src` as the import package) with a result snapshot: 11 mutants generated with `src.`-prefixed names, 6 killed / 5 survived — mutants verifiably apply and route, boundary-condition mutants survive as the tests intend. - Unit tests for the config key and both `get_mutant_name` modes. Verified on a real flat-layout project (a ~1.8k-file Telegram engine with `from src.*` imports throughout): stats collection passes for the first time and mutants execute. Co-Authored-By: Claude Code <noreply@anthropic.com>
axisrow
added a commit
to axisrow/tg_content_factory
that referenced
this pull request
Oct 7, 2026
) unblocks mutation runs With the upstream fix (strip_src_prefix knob, our branch fix/strip-src-prefix-knob installed editable) the flat-`src` incompatibility is resolved: enable it and update the pyproject comment + CLAUDE.md note from "blocked upstream" to the patched-locally state. Also records the full also_copy set (adk/ joins at run time — tests/test_adk_app.py loads adk/tg_content_factory/agent.py by path). Co-Authored-By: Claude Code <noreply@anthropic.com>
Owner
|
Projects that do this are broken. Please fix the project. I've closed these issues before, please search closed issues before submitting. |
axisrow
added a commit
to axisrow/tg_content_factory
that referenced
this pull request
Oct 8, 2026
) unblocks mutation runs With the upstream fix (strip_src_prefix knob, our branch fix/strip-src-prefix-knob installed editable) the flat-`src` incompatibility is resolved: enable it and update the pyproject comment + CLAUDE.md note from "blocked upstream" to the patched-locally state. Also records the full also_copy set (adk/ joins at run time — tests/test_adk_app.py loads adk/tg_content_factory/agent.py by path). Co-Authored-By: Claude Code <noreply@anthropic.com>
axisrow
added a commit
to axisrow/tg_content_factory
that referenced
this pull request
Oct 8, 2026
…rc incompatibility (#1501) * fix(tooling): mutmut sandbox copies root conftest.py + scripts; document the flat-src incompatibility Root-caused the standing "mutmut is incompatible with this repo's harness" (BadTestExecutionCommandsException) down to two stacked layers: 1. Sandbox layer (fixed here): mutmut's mutants/ copy included pyproject/src/ tests but NOT the repo-root conftest.py (tests read it by path — test_conftest_xdist.py) nor scripts/ (test_detect_reinvented.py, test_doc_coverage.py load tools from it by path) — stats collection died with FileNotFoundError before mutmut raised its generic exception. [tool.mutmut] now pins source_paths and also_copy for both. 2. Upstream layer (documented, not fixable in-repo): mutmut 3.8 assumes src-layout — it unconditionally strips a `src.` prefix from module names (mutmut/utils/format_utils.py get_mutant_name) and asserts `not name.startswith("src.")` on every trampoline hit (mutmut/stats.py record_trampoline_hit). Our import package IS `src` (flat layout), so every stats run asserts out. Full mutation runs need an upstream fix or a package rename; the per-fix mutation proof stays the documented red→green run. Red→green for layer 1: sandbox collection before the copy list — FileNotFoundError: mutants/conftest.py, then mutants/scripts/detect_reinvented.py (two pytest -q --collect-only runs inside mutants/); after — clean collection, exit 0. mutmut then fails at the documented upstream assert instead. Co-Authored-By: Claude Code <noreply@anthropic.com> * fix(tooling): mutmut sandbox ships run-time root reads (.github, docs, adk); gitignore mutants/ Review follow-up to the sandbox-copy fix: the original green proof covered only --collect-only, while the stats run executes the full suite and tests read repo-root paths at RUN time. Verified by actually running the suite inside a fresh mutants/ sandbox: - before: FileNotFoundError at tests/test_ci_workflow_structure.py (.github/workflows/ci.yml), tests/test_agent_tool_smoke_contract.py + tests/test_cli_agent_parity.py (docs/reference/*.md), tests/test_adk_app.py (adk/tg_content_factory/agent.py) - after (also_copy += ".github", "docs", "adk" — directory entries; nested file paths crash mutmut's copier): 1714 passed, 0 missing-file failures, 141 skipped. Remaining diff vs the real repo: one GC-timing PytestUnraisableExceptionWarning (unclosed sqlite3.Connection) in tests/test_adk_backend.py::test_chat_stream_skips_final_aggregated_text — passes in the real repo (0.18s), not a missing-copy problem. Also: mutants/ is gitignored (same class as .serena/), CLAUDE.md's `mutmut run` entry carries the upstream-blocker caveat, and the pyproject comment states the data/-dir exclusion (live DB) and the rm -rf wipe (mutmut never prunes the sandbox). Refs the flat-src upstream incompatibility documented in the previous commit — full mutation runs still require an upstream fix or a package rename. Co-Authored-By: Claude Code <noreply@anthropic.com> * fix(tooling): enable strip_src_prefix — patched mutmut (boxed/mutmut#593) unblocks mutation runs With the upstream fix (strip_src_prefix knob, our branch fix/strip-src-prefix-knob installed editable) the flat-`src` incompatibility is resolved: enable it and update the pyproject comment + CLAUDE.md note from "blocked upstream" to the patched-locally state. Also records the full also_copy set (adk/ joins at run time — tests/test_adk_app.py loads adk/tg_content_factory/agent.py by path). Co-Authored-By: Claude Code <noreply@anthropic.com> * fix(tooling): mutmut opt-out via mutmut_skip marker; sandbox config finalized Stats-baseline convergence over 6 sandbox runs (8273 green tests at the last failure point): the tests that cannot run under mutmut are now marked, not deselected by stale-prone node-id lists: - new `mutmut_skip` marker (same idiom as `slow`); [tool.mutmut] pytest_add_cli_args shrinks to `-p no:unraisableexception -m 'not mutmut_skip'`; - tagged: 4 repo-contract AST/surface scans (cli_pool_classification, client_pool_decomposition, client_pool_lease_stress, db_access_conventions x2) — in the sandbox they see trampoline-generated copies, and for mutation semantics a scan that fails on any change would false-kill every mutant it touches; test_mcp_server_stdio (both tests spawn the MCP subprocess, which dies on closed stdio fds under the forkserver runner); quality_scoring (known network-flaky family, poison for a stats baseline); - also_copy += mkdocs.yml, config.yaml, docker-compose.yml (tests read them from the repo root at run time); - unraisable-plugin disable stays run-wide: the serial stats run GC-finalizes leaky leftovers from earlier tests and the plugin attributes them to random tests (observed at 1713 and 3673 green tests). The normal suite keeps full strictness — every opt-out lives only in the mutmut invocation. Co-Authored-By: Claude Code <noreply@anthropic.com> * fix(tooling): review fixes for mutmut config — per-test mutmut_skip, threadexception off, sandbox narrowing --------- Co-authored-by: axisrow <axisrow@users.noreply.github.com> Co-authored-by: Claude Code <noreply@anthropic.com>
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
Projects whose import package is literally
src(flat layout:src/__init__.py, imports likefrom src.calc import ...) cannot run mutmut 3.8 at all — stats collection dies during the first trampoline hit:The root cause is that mutant naming assumes the src-layout convention, where
src/is only a container directory:get_mutant_name(utils/format_utils.py) unconditionally strips asrc.prefix. For a flat layout the stripped name (collection_queue.x_foo__mutmut_1) no longer matches the imported module (src.collection_queue).mutation/trampoline.py(module != decorated_func.__module__never matches → mutants silently never apply), the stats mapping (tests_by_mangled_function_namelookups miss), and finallyrecord_trampoline_hit(mutation/stats.py) asserts on thesrc.-prefixed recorded name — killing the whole stats run.Sandbox importability itself already works for flat layouts (
setup_source_pathsputsmutants/onsys.path, sofrom src...resolves to the mutated copy) — only the name shaping is broken.Fix
New config
[tool.mutmut] strip_src_prefix(defaulttrue= current behavior, so src-layout projects are unaffected):false:get_mutant_namekeeps the fullsrc.-prefixed module path — routing, stats keys, and the assert all become consistent;record_trampoline_hitasserts only while stripping is active, and its message now points flat-layout users at the knob;get_mutant_namemodes;e2e_projects/flat_src(srcas the import package) with a result snapshot: 11 mutants generated withsrc.-prefixed names, 6 killed / 5 survived — i.e. mutants verifiably apply and route, while boundary-condition mutants (clampatvalue == low) survive exactly as the fixture's tests intend.Verification
test_e2e_type_checking×2 — type-checker version drift,test_safe_setproctitle— macOS CoreFoundation fork) reproduce on a clean checkout without this patch.from src.*imports throughout): with the knob, stats collection completes for the first time and mutants execute; stock 3.8 asserts out at the same point.🤖 Generated with Claude Code