Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
11 changes: 7 additions & 4 deletions desloppify/app/commands/show/formatting.py
Original file line number Diff line number Diff line change
Expand Up @@ -31,8 +31,13 @@
]


def format_detail(detail: dict) -> list[str]:
"""Build display parts from a finding's detail dict."""
def format_detail(detail: object) -> list[str]:
"""Build display parts from a finding's detail payload."""
if isinstance(detail, str):
return [f"detail: {detail}"] if detail else []
if not isinstance(detail, dict):
return []

parts = []
for key, label, formatter in DETAIL_DISPLAY:
value = detail.get(key)
Expand Down Expand Up @@ -60,8 +65,6 @@ def format_detail(detail: dict) -> list[str]:

def suppressed_match_estimate(pattern: str, hidden_by_detector: dict[str, int]) -> int:
"""Estimate hidden-match count for a show pattern using detector-level noise totals."""
if not isinstance(pattern, str) or not isinstance(hidden_by_detector, dict):
return 0
Comment on lines -63 to -64
Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Seems there was only one call to make_finding with a string, so this fix was a bit simpler. The mypy config should catch calls with incorrect types to make_finding now.

Copy link
Author

@RyanJarv RyanJarv Mar 3, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

hmm, this isn't backwards compatible. Not sure if that matters for .desloppify/state-go.json?

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

latest commit normalizes the old state now

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I switched this to a draft because I'm not particularly confident this is handled the right way. Besides that though, it works.

detector = pattern.split("::", 1)[0]
return int(hidden_by_detector.get(detector, 0))

Expand Down
3 changes: 2 additions & 1 deletion desloppify/app/commands/show/render.py
Original file line number Diff line number Diff line change
Expand Up @@ -60,7 +60,8 @@ def _print_single_finding(finding: dict, *, show_code: bool) -> None:
if detail_parts:
print(colorize(f" {' · '.join(detail_parts)}", "dim"))
if show_code:
detail = finding.get("detail", {})
detail_raw = finding.get("detail", {})
detail = detail_raw if isinstance(detail_raw, dict) else {}
target_line = (
detail.get("line") or (detail.get("lines", [None]) or [None])[0]
)
Expand Down
6 changes: 5 additions & 1 deletion desloppify/languages/_framework/treesitter/phases.py
Original file line number Diff line number Diff line change
Expand Up @@ -80,7 +80,11 @@ def run(path, lang):
f"{e['component_count']} disconnected function clusters "
f"({e['function_count']} functions) — likely mixed responsibilities"
),
detail=f"Clusters: {families}",
detail={
"cluster_count": e["component_count"],
"family": families,
"families": e["families"],
},
))
if entries:
potentials["responsibility_cohesion"] = len(entries)
Expand Down
7 changes: 7 additions & 0 deletions desloppify/tests/commands/test_cmd_show.py
Original file line number Diff line number Diff line change
Expand Up @@ -118,6 +118,13 @@ def test_outliers_truncated(self):
out_part = [p for p in parts if p.startswith("outliers:")][0]
assert "f" not in out_part # Only first 5

def test_string_detail_is_rendered(self):
parts = format_detail("Clusters: alpha, beta")
assert parts == ["detail: Clusters: alpha, beta"]

def test_non_dict_non_string_detail_is_ignored(self):
assert format_detail(123) == []


# ---------------------------------------------------------------------------
# build_show_payload
Expand Down
2 changes: 2 additions & 0 deletions desloppify/tests/lang/common/test_phase_builders.py
Original file line number Diff line number Diff line change
Expand Up @@ -244,6 +244,8 @@ def test_make_cohesion_phase_run_with_entries():
assert potentials["responsibility_cohesion"] == 1
assert findings[0]["detector"] == "responsibility_cohesion"
assert "disconnected function clusters" in findings[0]["summary"]
assert findings[0]["detail"]["cluster_count"] == 4
assert findings[0]["detail"]["family"] == "network, database, ui, auth"


def test_make_unused_imports_phase_run_with_entries():
Expand Down
5 changes: 5 additions & 0 deletions pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -80,6 +80,7 @@ python_version = "3.11"
warn_unused_configs = true
warn_redundant_casts = true
warn_unreachable = true
check_untyped_defs = true
show_error_codes = true
strict_optional = true
ignore_missing_imports = true
Expand All @@ -97,8 +98,12 @@ files = [
"desloppify/app/commands/scan/scan_reporting_presentation.py",
"desloppify/app/commands/scan/scan_reporting_subjective.py",
"desloppify/app/commands/scan/scan_workflow.py",
"desloppify/app/commands/show/formatting.py",
"desloppify/app/commands/show/render.py",
"desloppify/app/cli_support/parser.py",
"desloppify/app/cli_support/parser_groups.py",
"desloppify/engine/_state/filtering.py",
"desloppify/engine/concerns.py",
"desloppify/languages/_framework/treesitter/phases.py",
"desloppify/languages/_framework/generic.py",
]