Skip to content

Commit 6953347

Browse files
committed
feat(mcp,vscode): clarify repository health and triage focus semantics
- add compact MCP interpretation fields for health_scope, focus, and new_by_source_kind across summary, production triage, and changed-scope projections - make the VS Code extension explain repository-wide health, production focus, outside-focus debt, and new-finding source-kind attribution more clearly without widening the review flow - bump the preview VS Code extension to 0.2.2 and record the UX clarification pass in its changelog
1 parent 4bbf3bc commit 6953347

File tree

15 files changed

+162
-11
lines changed

15 files changed

+162
-11
lines changed

CHANGELOG.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,8 @@
77
- Bump canonical report schema to `2.4` for `meta.analysis_profile`.
88
- Surface the effective runtime analysis profile (`min_loc`, `min_stmt`, block, and segment thresholds) in canonical
99
report metadata, MCP summary/triage projections, and the HTML Executive Summary subtitle.
10+
- Clarify MCP interpretation with compact `health_scope`, `focus`, and `new_by_source_kind` fields in summary/triage
11+
projections.
1012
- Refresh branch metadata and client docs for the `2.0.0b5` line.
1113
- Update the README repository health badge to `87 (B)`.
1214

README.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -162,6 +162,8 @@ repos:
162162
163163
Optional read-only MCP server for AI agents and IDE clients.
164164
21 tools + 10 resources — never mutates source, baselines, or repo state.
165+
Compact summary and triage payloads make scope explicit: repository-wide health,
166+
current focus, and new-finding source-kind attribution.
165167
166168
```bash
167169
uv tool install --pre "codeclone[mcp]" # or: uv pip install --pre "codeclone[mcp]"

codeclone/mcp_service.py

Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -157,9 +157,15 @@
157157
"changed",
158158
"integrity",
159159
]
160+
HealthScope = Literal["repository"]
161+
SummaryFocus = Literal["repository", "production", "changed_paths"]
160162

161163
_LEGACY_CACHE_PATH = Path("~/.cache/codeclone/cache.json").expanduser()
162164
_REPORT_DUMMY_PATH = Path(".cache/codeclone/report.json")
165+
_HEALTH_SCOPE_REPOSITORY: Final[HealthScope] = "repository"
166+
_FOCUS_REPOSITORY: Final[SummaryFocus] = "repository"
167+
_FOCUS_PRODUCTION: Final[SummaryFocus] = "production"
168+
_FOCUS_CHANGED_PATHS: Final[SummaryFocus] = "changed_paths"
163169
_MCP_CONFIG_KEYS = frozenset(
164170
{
165171
"min_loc",
@@ -1662,11 +1668,20 @@ def get_production_triage(
16621668
]
16631669
payload: dict[str, object] = {
16641670
"run_id": self._short_run_id(record.run_id),
1671+
"focus": _FOCUS_PRODUCTION,
1672+
"health_scope": _HEALTH_SCOPE_REPOSITORY,
16651673
"health": dict(self._summary_health_payload(summary)),
16661674
"cache": dict(self._as_mapping(summary.get("cache"))),
16671675
"findings": {
16681676
"total": len(findings),
16691677
"by_source_kind": findings_breakdown,
1678+
"new_by_source_kind": dict(
1679+
self._as_mapping(
1680+
self._as_mapping(summary.get("findings")).get(
1681+
"new_by_source_kind"
1682+
)
1683+
)
1684+
),
16701685
"outside_focus": len(findings)
16711686
- findings_breakdown[SOURCE_KIND_PRODUCTION],
16721687
},
@@ -3228,13 +3243,19 @@ def _build_changed_projection(
32283243
known_count = sum(
32293244
1 for item in items if str(item.get("novelty", "")) == "known"
32303245
)
3246+
new_by_source_kind = self._source_kind_breakdown(
3247+
item.get("source_kind")
3248+
for item in items
3249+
if str(item.get("novelty", "")) == "new"
3250+
)
32313251
health_delta = self._summary_health_delta(record.summary)
32323252
return {
32333253
"run_id": self._short_run_id(record.run_id),
32343254
"changed_paths": list(record.changed_paths),
32353255
"total": len(items),
32363256
"new": new_count,
32373257
"known": known_count,
3258+
"new_by_source_kind": new_by_source_kind,
32383259
"items": items,
32393260
"health": dict(self._summary_health_payload(record.summary)),
32403261
"health_delta": health_delta,
@@ -3260,6 +3281,8 @@ def _changed_analysis_payload(
32603281
)
32613282
return {
32623283
"run_id": self._short_run_id(record.run_id),
3284+
"focus": _FOCUS_CHANGED_PATHS,
3285+
"health_scope": _HEALTH_SCOPE_REPOSITORY,
32633286
"changed_files": len(record.changed_paths),
32643287
"health": health_payload,
32653288
"analysis_profile": self._summary_analysis_profile_payload(record.summary),
@@ -3270,6 +3293,9 @@ def _changed_analysis_payload(
32703293
),
32713294
"verdict": str(changed_projection.get("verdict", "stable")),
32723295
"new_findings": _as_int(changed_projection.get("new", 0), 0),
3296+
"new_by_source_kind": dict(
3297+
self._as_mapping(changed_projection.get("new_by_source_kind"))
3298+
),
32733299
"resolved_findings": 0,
32743300
"changed_findings": [],
32753301
}
@@ -4003,6 +4029,8 @@ def _summary_payload(
40034029
and not summary.get("baseline")
40044030
):
40054031
return {
4032+
"focus": _FOCUS_REPOSITORY,
4033+
"health_scope": _HEALTH_SCOPE_REPOSITORY,
40064034
"inventory": self._summary_inventory_payload(inventory),
40074035
"health": self._summary_health_payload(summary),
40084036
}
@@ -4011,6 +4039,8 @@ def _summary_payload(
40114039
)
40124040
payload: dict[str, object] = {
40134041
"run_id": self._short_run_id(resolved_run_id) if resolved_run_id else "",
4042+
"focus": _FOCUS_REPOSITORY,
4043+
"health_scope": _HEALTH_SCOPE_REPOSITORY,
40144044
"version": str(summary.get("codeclone_version", __version__)),
40154045
"schema": str(summary.get("report_schema_version", REPORT_SCHEMA_VERSION)),
40164046
"mode": str(summary.get("analysis_mode", "")),
@@ -4149,6 +4179,7 @@ def _summary_findings_payload(
41494179
"known": 0,
41504180
"by_family": {},
41514181
"production": 0,
4182+
"new_by_source_kind": self._source_kind_breakdown(()),
41524183
}
41534184
findings = self._base_findings(record)
41544185
by_family: dict[str, int] = {
@@ -4160,6 +4191,11 @@ def _summary_findings_payload(
41604191
new_count = 0
41614192
known_count = 0
41624193
production_count = 0
4194+
new_by_source_kind = self._source_kind_breakdown(
4195+
self._finding_source_kind(finding)
4196+
for finding in findings
4197+
if str(finding.get("novelty", "")).strip() == "new"
4198+
)
41634199
for finding in findings:
41644200
family = str(finding.get("family", "")).strip()
41654201
family_key = "clones" if family == FAMILY_CLONE else family
@@ -4177,6 +4213,7 @@ def _summary_findings_payload(
41774213
"known": known_count,
41784214
"by_family": {key: value for key, value in by_family.items() if value > 0},
41794215
"production": production_count,
4216+
"new_by_source_kind": new_by_source_kind,
41804217
}
41814218

41824219
def _summary_diff_payload(

docs/book/01-architecture-map.md

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -68,6 +68,9 @@ Refs:
6868
- The same rule applies to summary cache convenience fields such as
6969
`freshness` and to production-first triage projections built from
7070
canonical hotlists/suggestions.
71+
- The same rule also applies to compact interpretation hints such as
72+
`health_scope`, `focus`, and `new_by_source_kind`: they clarify projection
73+
meaning without introducing a second report truth.
7174
- MCP finding lists may also expose short run/finding ids and slimmer relative
7275
location projections, while keeping `get_finding(detail_level="full")` as the
7376
richer per-finding inspection path.

docs/book/14-compatibility-and-versioning.md

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -56,7 +56,8 @@ Version bump rules:
5656
short MCP ids, slim summary locations, or omitting `priority_factors`
5757
outside `detail_level="full"`.
5858
- Additive MCP-only convenience fields/projections such as
59-
`cache.freshness` or production-first triage also do not change
59+
`cache.freshness`, production-first triage, `health_scope`, `focus`, or
60+
`new_by_source_kind` also do not change
6061
`report_schema_version` when they are derived from unchanged canonical report
6162
and summary data.
6263
- The same rule applies to bounded MCP semantic guidance such as

docs/book/20-mcp-interface.md

Lines changed: 8 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -56,17 +56,21 @@ Current server characteristics:
5656
`refresh` is rejected in MCP because the server is read-only.
5757
- summary payload:
5858
- `run_id`, `version`, `schema`, `mode`, compact `analysis_profile`
59+
- `health_scope` explains what the health score covers
60+
- `focus` explains the active summary/triage lens
5961
- `baseline`, `metrics_baseline`, `cache`
6062
- `cache.freshness` classifies summary cache reuse as `fresh`, `mixed`,
6163
or `reused`
6264
- flattened `inventory` (`files`, `lines`, `functions`, `classes`)
63-
- flattened `findings` (`total`, `new`, `known`, `by_family`, `production`)
65+
- flattened `findings` (`total`, `new`, `known`, `by_family`, `production`,
66+
`new_by_source_kind`)
6467
- flattened `diff` (`new_clones`, `health_delta`)
6568
- `warnings`, `failures`
6669
- `analyze_changed_paths` is intentionally more compact than `get_run_summary`:
67-
it returns `changed_files`, `health`, `health_delta`, `verdict`,
68-
`new_findings`, `resolved_findings`, and an empty `changed_findings`
69-
placeholder, while detailed changed payload stays in
70+
it returns `changed_files`, `focus`, `health_scope`, `health`,
71+
`health_delta`, `verdict`, `new_findings`, `new_by_source_kind`,
72+
`resolved_findings`, and an empty `changed_findings` placeholder, while
73+
detailed changed payload stays in
7074
`get_report_section(section="changed")`
7175
- workflow guidance:
7276
- the MCP surface is intentionally agent-guiding rather than list-first

docs/mcp.md

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -118,6 +118,9 @@ run-scoped URI templates.
118118
- `check_*` responses include only the relevant health dimension.
119119
- Finding responses use short MCP IDs and relative paths by default;
120120
`detail_level=full` restores the compatibility payload with URIs.
121+
- Summary and triage projections keep interpretation compact: `health_scope`
122+
explains what the health score covers, `focus` explains the active view, and
123+
`new_by_source_kind` attributes new findings without widening the payload.
121124
- Run IDs are 8-char hex handles; finding IDs are short prefixed forms.
122125
Both accept the full canonical form as input.
123126
- `metrics_detail(family="overloaded_modules")` exposes the report-only

extensions/vscode-codeclone/CHANGELOG.md

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,10 @@
11
# Change Log
22

3+
## 0.2.2
4+
5+
- surface repository-vs-focus semantics more clearly in triage and summary UX
6+
- explain new findings by source kind without widening the review flow
7+
38
## 0.2.1
49

510
- refresh packaged extension metadata for prerelease validation

extensions/vscode-codeclone/package-lock.json

Lines changed: 2 additions & 2 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

extensions/vscode-codeclone/package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22
"name": "codeclone",
33
"displayName": "CodeClone",
44
"description": "Baseline-aware, triage-first structural review for Python, powered by CodeClone MCP.",
5-
"version": "0.2.1",
5+
"version": "0.2.2",
66
"preview": true,
77
"publisher": "orenlab",
88
"license": "MPL-2.0",

0 commit comments

Comments
 (0)