feat(health): show per-file bug-fix history in the drawer, panel and hover - #948
Merged
Conversation
…hover The fix-event rollup has been computed and stored since #940 but nothing rendered it. Three surfaces now do: - FileSignalsPanel's bug-fix tile gains a "Bug magnet" badge and folds the last-fix age into its caption. - The health file drawer gains a collapsed "Bug history" section listing which symbols the fixes landed in, with the last-fix age on the toggle so the "is this still happening?" question is answered without expanding. - The VS Code file hover gains one line off the same contract, no new API. The magnet badge never renders without the last-fix age beside it. It is a claim about recent fix pressure, so unanchored it would describe a file fixed four times last month and one fixed four times two years ago identically. All three surfaces drop the flag rather than show it bare, and the per-symbol counts are labelled approximate because fixes are matched to symbols by line range and lines move. Also fixes a real serialization bug behind all of this. SQLite's DATETIME bind processor drops tzinfo, so last_fix_at read back naive and isoformat() produced a string with no offset. JS parses that as local time, so west of UTC a fix committed two hours ago landed in the future, tripped formatRelativeTimeOrNull's future-guard, and the age silently vanished from copy required to carry it, worst for the freshest fixes. Fixed once in signals.iso_utc rather than in each consumer.
|
✅ Health: 7.5 (unchanged) 📋 At a glance Files & modules (2)
📌 Before you merge
🗺️ Change map flowchart LR
subgraph PR ["Changed in this PR (4 with dependents)"]
f_packages_core_src_repowise_core_analysis_health_signals_py[".../health/signals.py 🔥"]:::changed
f_packages_ui_src_health_health_file_drawer_tsx[".../health/health-file-drawer.tsx 🔥"]:::changed
f_packages_ui_src_health_file_signals_panel_tsx[".../health/file-signals-panel.tsx"]:::changed
f_packages_vscode_src_features_hovers_ts[".../features/hovers.ts"]:::changed
end
f_packages_server_src_repowise_server_mcp_server_tool_context_enrichment_py[".../tool_context/enrichment.py"]
f_packages_core_src_repowise_core_analysis_health_signals_py --> f_packages_server_src_repowise_server_mcp_server_tool_context_enrichment_py
f_packages_server_src_repowise_server_mcp_server_tool_health_py[".../mcp_server/tool_health.py"]
f_packages_core_src_repowise_core_analysis_health_signals_py --> f_packages_server_src_repowise_server_mcp_server_tool_health_py
f_packages_server_src_repowise_server_routers_code_health_loaders_py[".../code_health/loaders.py"]
f_packages_core_src_repowise_core_analysis_health_signals_py --> f_packages_server_src_repowise_server_routers_code_health_loaders_py
f_packages_server_src_repowise_server_routers_code_health_serializers_py[".../code_health/serializers.py"]
f_packages_core_src_repowise_core_analysis_health_signals_py --> f_packages_server_src_repowise_server_routers_code_health_serializers_py
f_packages_ui_src_health_health_file_drawer_tsx --> f_packages_server_src_repowise_server_mcp_server_tool_health_py
f_packages_types_src_files_ts[".../src/files.ts"]
f_packages_ui_src_health_health_file_drawer_tsx --> f_packages_types_src_files_ts
f_packages_ui_src_files_file_health_tab_tsx[".../files/file-health-tab.tsx"]
f_packages_ui_src_health_health_file_drawer_tsx --> f_packages_ui_src_files_file_health_tab_tsx
f_packages_ui_src_health_biomarker_list_tsx[".../health/biomarker-list.tsx"]
f_packages_ui_src_health_health_file_drawer_tsx --> f_packages_ui_src_health_biomarker_list_tsx
f_packages_ui_src_health_file_signals_panel_tsx --> f_packages_ui_src_files_file_health_tab_tsx
f_packages_ui_src_health_index_ts[".../health/index.ts"]
f_packages_ui_src_health_file_signals_panel_tsx --> f_packages_ui_src_health_index_ts
f_packages_vscode_src_extension_ts[".../src/extension.ts"]
f_packages_vscode_src_features_hovers_ts --> f_packages_vscode_src_extension_ts
more(["+1 more dependent"])
PR --> more
t_tests_unit_server_test_health_badge_py(["✅ .../server/test_health_badge.py"]):::guard
t_tests_unit_server_test_health_badge_py -.-> f_packages_core_src_repowise_core_analysis_health_signals_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
Solid arrows: code that imports the changed files (10 direct dependents, from the last indexed snapshot). Dashed: history/tests.
🩹 Review priority (files here with the most recent bug-fix history — defects cluster, so review these first)
🔎 More signals (1)🔥 Hotspots touched (5)
2 more
📊 Full report · ⭐ Star Repowise · 📥 Install bot · Last updated 2026-07-20 05:26 UTC |
swati510
approved these changes
Jul 20, 2026
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
The fix-event rollup has been computed and stored since #940, and the
FileSignalscontract has carriedbug_magnet/last_fix_at/fix_symbol_countssince then too. Nothing rendered any of it. Three surfaces now do.CollapsibleSectionrather than the drawer-local group component.packages/vscodealready pulls@repowise-dev/types, so the contract reached it for free.The magnet badge never renders alone
types/health.tsstates it plainly:bug_magnetis a recency claim, so any copy showing it must showlast_fix_attoo. Unanchored, the badge would describe a file fixed four times last month and one fixed four times two years ago identically. All three surfaces now drop the flag rather than show it bare.Pre-merge review caught that all three were getting this wrong, and that no test covered the null-timestamp path. There is one now.
A real serialization bug, fixed upstream
SQLite's DATETIME bind processor drops
tzinfo, solast_fix_atreads back naive even though the rollup writes it aware-UTC, and.isoformat()on a naive datetime produces a string with no offset. Per the ES spec, JS parses that as local time.Concretely, for a viewer at UTC-8: a fix committed two hours ago is stored
T-2hUTC, read asT-2hlocal, which isT+6habsolute.formatRelativeTimeOrNull's future-guard catches it and returns the empty fallback, so the age disappears from the caption, the drawer hint and the hover, and with the guard above the magnet badge disappears with it. Worst for the newest fixes, which are exactly the ones worth showing. East of UTC the age is simply wrong by the offset.Fixed once in
signals.iso_utc(renamed from_isonow that a second module reads it) rather than patching four consumers, with a regression test.Hedging
Per-symbol counts are labelled approximate wherever shown: fixes are matched to symbols by line range against current-tree spans, so the mapping is a best effort on any file that has moved since. Nothing here names an inducing commit.
Tests
npm run type-checkclean, UI health suites 42 passed, Python health suite 989 passed, all in isolation on this branch.