Skip to content

feat(mcp): surface counted bug-fix history on get_risk and get_change_risk#946

Merged
RaghavChamadiya merged 1 commit into
mainfrom
feat/risk-defect-profile
Jul 20, 2026
Merged

feat(mcp): surface counted bug-fix history on get_risk and get_change_risk#946
RaghavChamadiya merged 1 commit into
mainfrom
feat/risk-defect-profile

Conversation

@RaghavChamadiya

Copy link
Copy Markdown
Member

The fix-event data layer has been computed and stored since #939/#940, and until now nothing read it. This is the agent-facing half.

get_risk: defect_profile

Per file, when it has counted fixes: how many landed in the trailing 6 months, how long ago the last one was, a bug_magnet flag for sustained recent pressure, and the top symbols the fixes clustered in. Built from the GitMetadata row _assess_one_target already loads, so no second query.

get_change_risk: prior_fixes

Per changed file: how many past bug-fix commits touched it, and how many of the change's lines fall inside the ranges one of those fixes replaced. changed_lines is now read once and shared with impacted_tests rather than shelling out to git twice.

Neither block names a commit

File-level SZZ measured 74.5% precision against the frozen judgments. That is enough to count fixes honestly and not enough to accuse one commit of causing them. Both blocks are aggregate, and both are absent entirely on a repo with no fix history, so nothing grows a noise block.

Behaviour change worth flagging in review

risk_type="bug-prone" now reads counted fix history instead of scanning commit subjects for fix|bug|patch|.... The old regex matched doc and test commits, had no recency at all, and disagreed with the count every other surface shows.

Because bug-prone returns before the other classifications, this reclassifies some files: one with 3 fixes across 200 commits now reads bug-prone where it read churn-heavy, and a sole-maintainer hotspot with 3 fixes stops reading bus-factor-risk. That is the intended direction, but it is a silent change to existing output.

Token budget

Measured over all 803 dogfood files with a counted fix: mean 46 tokens, max 80, against a 150-token ceiling. The measurement changed the design once. The first draft carried an approximate, symbol spans are current-tree string on every row, ~13 tokens per target of identical text. That caveat now lives in the tool docstring, and the fuller explanation in docs/MCP_TOOLS.md.

Tests

test_defect_profile.py and test_prior_fixes.py. Both blocks are asserted silent without fix data. The prior_fixes test seeds events across two files and asserts aggregation, overlap ranking, most-recent-wins age, and the code_fix shape filter.

Pre-merge review caught three things fixed here: total_fixes counted rows rather than distinct commits (one commit touching three changed files reported "3 fixes"), bug_magnet could render without the age that anchors it, and _overlap_count had an int() outside its guard.

…_risk

get_risk gains a per-file `defect_profile`: how many bug fixes landed in the
trailing 6 months, how long ago the last one was, a `bug_magnet` flag for
sustained recent fix pressure, and the symbols the fixes clustered in. Built
from the GitMetadata row the assessment already loads, so no extra query.

get_change_risk gains `prior_fixes`: per changed file, how many past bug-fix
commits touched it and how many of the change's lines fall inside the ranges
one of those fixes replaced. `changed_lines` is now read once and shared with
`impacted_tests` instead of shelling out to git twice.

Both blocks are aggregate and neither names an inducing commit. File-level SZZ
measured 74.5% precision against the frozen judgments, which counts fixes
honestly and accuses a commit dishonestly. Both are silent on a repo with no
fix history, so nothing grows a noise block.

`risk_type="bug-prone"` now reads that counted history instead of scanning
commit subjects for "fix". The old regex matched doc and test commits, had no
recency, and disagreed with the count every other surface shows. Note this
reclassifies: bug-prone returns first, so a file with 3 fixes in 200 commits
now reports bug-prone where it reported churn-heavy.

`bug_magnet` only renders alongside the last-fix age. It is a claim about
recent pressure, so without a timestamp it would describe a file fixed four
times last month and one fixed four times two years ago identically.

The defect_profile block measures at 80 tokens worst case over the 803 dogfood
files with a counted fix, against a 150-token budget. The approximation caveat
on top_symbols lives in the tool docstring rather than repeating on every row.
@repowise-bot

repowise-bot Bot commented Jul 20, 2026

Copy link
Copy Markdown

✅ Health: 7.5 (unchanged)

📋 At a glance
3 hotspots touched · 1 new finding introduced · 2 files with recent fix history. Scoped to packages.

📌 Before you merge

  • Run .../mcp/test_change_risk.py: they depend on the changed files

🗺️ Change map

flowchart LR
  subgraph PR ["Changed in this PR (3 with dependents)"]
    f_packages_server_src_repowise_server_mcp_server_tool_change_risk_py[".../mcp_server/tool_change_risk.py 🔥"]:::changed
    f_packages_server_src_repowise_server_mcp_server_tool_risk_assessment_py[".../tool_risk/assessment.py 🔥"]:::changed
    f_packages_server_src_repowise_server_mcp_server_tool_risk_get_risk_py[".../tool_risk/get_risk.py 🔥"]:::changed
  end
  f_packages_server_src_repowise_server_mcp_server___init___py[".../mcp_server/__init__.py"]
  f_packages_server_src_repowise_server_mcp_server_tool_change_risk_py --> f_packages_server_src_repowise_server_mcp_server___init___py
  f_packages_server_src_repowise_server_mcp_server_tool_risk___init___py[".../tool_risk/__init__.py"]
  f_packages_server_src_repowise_server_mcp_server_tool_risk_assessment_py --> f_packages_server_src_repowise_server_mcp_server_tool_risk___init___py
  f_packages_server_src_repowise_server_mcp_server_tool_risk_get_risk_py --> f_packages_server_src_repowise_server_mcp_server___init___py
  f_packages_server_src_repowise_server_mcp_server_tool_risk_get_risk_py --> f_packages_server_src_repowise_server_mcp_server_tool_risk___init___py
  t_tests_unit_server_mcp_test_change_risk_py(["✅ .../mcp/test_change_risk.py"]):::guard
  t_tests_unit_server_mcp_test_change_risk_py -.-> f_packages_server_src_repowise_server_mcp_server_tool_change_risk_py
  classDef changed fill:#dbeafe,stroke:#1d4ed8,color:#1e3a5f
  classDef warn fill:#fef3c7,stroke:#b45309,color:#78350f
  classDef guard fill:#dcfce7,stroke:#15803d,color:#14532d
Loading

Solid arrows: code that imports the changed files (2 direct dependents, from the last indexed snapshot). Dashed: history/tests.

🚨 Change risk: high (riskier than 68% of this repo's commits)
This change's risk is driven by:

  • more lines added than baseline
  • more scattered than baseline

🩹 Review priority (files here with the most recent bug-fix history — defects cluster, so review these first)

🔎 More signals (1)

🔥 Hotspots touched (3)

  • .../tool_risk/assessment.py — 2 commits/90d, 2 dependents
  • .../tool_risk/get_risk.py — 5 commits/90d, 2 dependents
  • .../mcp_server/tool_change_risk.py — 3 commits/90d, 2 dependents

📊 Full report · ⭐ Star Repowise · 📥 Install bot · Last updated 2026-07-20 05:25 UTC
Silence on a single PR with [skip repowise] in the title · Per-repo toggle on repowise.dev/settings?tab=bot

@RaghavChamadiya
RaghavChamadiya merged commit 87e65d2 into main Jul 20, 2026
5 of 7 checks passed
@RaghavChamadiya
RaghavChamadiya deleted the feat/risk-defect-profile branch July 20, 2026 05:28
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants