diff --git a/loopx/canary/maintainability_ratchet.py b/loopx/canary/maintainability_ratchet.py index b6a79ca04b..8ee74b566a 100644 --- a/loopx/canary/maintainability_ratchet.py +++ b/loopx/canary/maintainability_ratchet.py @@ -788,4 +788,24 @@ def render_control_plane_maintainability_report(payload: Mapping[str, Any]) -> s ) for exception_id in payload.get("invalid_exceptions") or []: lines.append(f"- invalid exception metadata: {exception_id}") + # A module metric budget is settled in the checked-in ledger rather than by + # a reviewed exception, so name that file next to the finding: it is the + # reviewer-visible edit that decides whether the growth is accepted. + if any( + str(finding.get("category") or "") == "module_metric_budget" + for finding in payload.get("findings") or [] + ): + lines.append( + "- module metric debt: refresh the reviewed ceiling in " + f"{_module_metric_baseline_name(payload)} for the growth this review accepts" + ) return "\n".join(lines) + "\n" + + +def _module_metric_baseline_name(payload: Mapping[str, Any]) -> str: + policy = payload.get("policy") + if isinstance(policy, Mapping): + declared = str(policy.get("module_metric_baseline_path") or "").strip() + if declared: + return declared + return MODULE_METRIC_BASELINE_PATH.name diff --git a/loopx/canary/module_metric_baseline.json b/loopx/canary/module_metric_baseline.json index 9ffe5aa7e4..989df62710 100644 --- a/loopx/canary/module_metric_baseline.json +++ b/loopx/canary/module_metric_baseline.json @@ -36,9 +36,9 @@ "lines": 1590 }, "loopx/chat_runtime.py": { - "any_count": 33, + "any_count": 35, "dict_any_count": 0, - "lines": 1502 + "lines": 1560 }, "loopx/chat_server.py": { "any_count": 25, diff --git a/tests/canary/test_maintainability_ratchet.py b/tests/canary/test_maintainability_ratchet.py index 46f6ddea1c..3eb8bcaf09 100644 --- a/tests/canary/test_maintainability_ratchet.py +++ b/tests/canary/test_maintainability_ratchet.py @@ -94,6 +94,55 @@ def test_module_metric_ratchet_rejects_growth_above_checked_in_baseline( assert module_metrics(module_path)["any_count"] == 1 +def test_module_metric_debt_names_the_reviewed_ledger_to_refresh( + tmp_path: Path, +) -> None: + """Module metric growth is settled in the checked-in ledger, not by exception.""" + + module_path = tmp_path / "loopx" / "sample.py" + module_path.parent.mkdir(parents=True) + module_path.write_text("\n".join(["# padding"] * 1501), encoding="utf-8") + + payload = evaluate_maintainability_findings( + collect_module_metric_findings(tmp_path, tracked_paths={module_path}), + reviewed_exceptions={}, + ) + rendered = render_control_plane_maintainability_report( + { + **payload, + "policy": { + "module_metric_baseline_path": "loopx/canary/module_metric_baseline.json" + }, + } + ) + + assert payload["ok"] is False + assert "module metric debt" in rendered + assert "loopx/canary/module_metric_baseline.json" in rendered + + +def test_review_without_module_metric_debt_keeps_the_report_unchanged() -> None: + finding = { + "id": "compatibility_facade:loopx.sample", + "category": "compatibility_facade", + "path": "loopx/sample.py", + } + + rendered = render_control_plane_maintainability_report( + evaluate_maintainability_findings( + [finding], + reviewed_exceptions={ + finding["id"]: { + "reason": "A public compatibility window still exists.", + "retirement_plan": "Delete the edge after the window closes.", + } + }, + ) + ) + + assert "module metric debt" not in rendered + + def test_reviewed_exception_lifecycle_rejects_new_debt_and_stale_entries() -> None: finding = { "id": "dependency_debt:loopx.sample->loopx.presentation",