Skip to content

mutation: 29 @dataclass classes in mcp_server/ carry methods invisible to mutmut (same defect class as issue #262) #282

Description

@cdeust

What

Sweeping the whole repository (not just scripts/) for the dataclass-method
mutation-exclusion defect that issues #262 / this branch's PR fixed for
RepoBadge (scripts/generate_repo_badges.py) and Ranking
(scripts/refresh_mcp_toplist_badge.py) — mutmut's mutation generator
categorically skips the body of any @dataclass-decorated ClassDef
(mutmut/mutation/file_mutation.py:236, confirmed in the installed
source) — surfaces 29 more decorated classes with non-dunder methods,
all in mcp_server/ (the actual runtime package, not the scripts/ gate
family this PR/#262/#280 have been working through):

mcp_server/doctor_mcp.py::McpReport [required_fails, warnings, to_dict]
mcp_server/core/value_learning.py::ValueUpdate [as_dict]
mcp_server/core/sensory_buffer.py::BufferItem [to_dict]
mcp_server/core/goal_maintenance.py::GoalVector [is_active, as_dict]
mcp_server/core/document_model.py::DocumentSection [is_empty]
mcp_server/core/document_model.py::ParsedDocument [is_empty]
mcp_server/core/document_model.py::DocumentProvenance [dedup_tag, source_tag]
mcp_server/core/wiki_coverage.py::DomainCoverage [covered_count, missing_count, coverage_ratio, missing_scopes]
mcp_server/core/wiki_coverage.py::FileCoverage [coverage_ratio]
mcp_server/core/procedural_memory.py::ActionStep [key]
mcp_server/core/procedural_memory.py::ProceduralSkill [is_habitual, length, as_dict]
mcp_server/core/wiki_redirect.py::Redirect [is_id_based]
mcp_server/core/wiki_groomer.py::PageAudit [has_issues]
mcp_server/core/wiki_axis_registry.py::AxisRegistry [values, names, get, has, default_for]
mcp_server/core/ablation.py::AblationConfig [is_enabled, disable, enable, disable_all_except]
mcp_server/core/conflict_monitor.py::ConflictAssessment [as_dict]
mcp_server/core/habituation.py::HabituationOutcome [as_dict]
mcp_server/core/attentional_control.py::AttentionAllocation [as_dict]
mcp_server/core/forward_model.py::ForwardModelState [as_dict]
mcp_server/core/wiki_view_executor.py::CompiledView [ok]
mcp_server/core/source_monitoring.py::SourceJudgement [as_dict]
mcp_server/core/wiki_schema_loader.py::WikiRegistry [known_kind_names]
mcp_server/core/dual_process_retrieval.py::FamiliaritySignal [as_dict]
mcp_server/shared/wiki_classification.py::Classification [validate, to_frontmatter]
mcp_server/core/streaming/backpressure_pipeline.py::BackpressurePipeline [run, _produce, _consume, _build_sink, _write_one, _close]
mcp_server/core/streaming/adaptive_controller.py::AdaptiveBatchController [batch_size, observe]
mcp_server/core/context_assembly/budget.py::AssemblyMetrics [reduction_fraction, was_truncated]
mcp_server/handlers/consolidation/headless_authoring.py::CycleBudget [time_left, exhausted, charge]
fuzz/replay_corpus.py::Harness [module_path, corpus_path, consume, inputs]
benchmarks/lib/verification_report.py::ExpResult [name, threshold, verdict]

(scripts/pip_constraint_sets.py::ConstraintSet is the one additional hit
inside scripts/, already being fixed in PR #280 — not duplicated here.)

Why this is filed rather than fixed in the PR that found it

None of these 29 are in the currently-committed [tool.mutmut] scope
(source_paths = ["mcp_server"], only_mutate = ["mcp_server/shared/json_native.py"]) — so the gate is not silently lying
about them TODAY. They become exposed to this defect only when a future
per-commit change touches one of these files and scripts/mutation_check.sh
repoints only_mutate at it, per §12's own per-change scoping rule. Fixing
all 29 (extract each class's methods to free functions, per the
repo_badge_path/repo_badge_svg / ranking_percentile/ranking_tier_text
/ constraint_path precedent, updating every call site + adding direct unit
tests for the newly-mutation-testable logic) is an unrelated, much larger
body of work than the scripts/-family fix this PR/issue #262 have been
carrying — mixing it in would violate §15.1 by roughly 10x-ing this PR's
blast radius into the runtime package itself.

Reproduction (the sweep command)

import ast, pathlib
for py in pathlib.Path(".").rglob("*.py"):
    # skip .venv/, node_modules/, __pycache__/, mutants/, worktree dirs
    tree = ast.parse(py.read_text(), filename=str(py))
    for node in ast.walk(tree):
        if isinstance(node, ast.ClassDef) and node.decorator_list:
            if any("dataclass" in (getattr(d, "id", "") or getattr(d, "attr", "")
                                    or getattr(getattr(d, "func", None), "id", "")
                                    or getattr(getattr(d, "func", None), "attr", ""))
                   for d in node.decorator_list):
                methods = [n.name for n in node.body if isinstance(n, ast.FunctionDef)
                           and not (n.name.startswith("__") and n.name.endswith("__"))]
                if methods:
                    print(py, node.name, methods)

Acceptance criteria

  • Each of the 29 classes above: either its methods are extracted to
    free functions (data/behavior split, same shape as RepoBadge) with
    call sites updated and the existing test suite passing unchanged, OR
    a written rationale for why the class is never going to be the
    only_mutate target of a scoped mutation run (e.g. truly untested
    dead weight slated for removal).
  • A scoped mutation run on each fixed file attributes real mutants to
    the extracted functions (not zero, matching the RepoBadge
    before/after evidence in this PR).
  • Given the size (29 classes across mcp_server/core,
    mcp_server/handlers, mcp_server/shared, plus fuzz/ and
    benchmarks/), this is expected to be sequenced as several PRs, one
    per module family, not a single diff.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions