fix(dashboard): keep reads for a deleted file on the map (BEA-49) - #100
Merged
ssowonny merged 2 commits intoAug 2, 2026
Merged
Conversation
The Dashboard's file panels built every point by joining the heat map onto the current file tree, so a heat row whose path had left the project was silently dropped — while the agent-coverage panel below, which does no such join, rendered those same reads. One page, one ledger, two answers. The production consequence is the real bug: delete or rename a well-read doc and its whole read history vanishes from the map, which is exactly the signal the Dashboard exists to give. Hot path now ranks orphaned rows alongside tree files, labelled "no longer in the project" and opening that path's History (the file view would land on the not-found page). The two plots stay tree-only — both position by freshness and an orphan has no mtime, so any position would be invented — but each carries a count of what it can't show. "No reads in the window yet" can now only render when the scope genuinely has none. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
This was referenced Jul 31, 2026
Merged
ssowonny
deleted the
bea-49-ph-scan-bug-dashboard-reports-no-reads-while-the-panel
branch
August 2, 2026 23:11
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.
TL;DR
What was wrong
Insights.tsxbuilt every point by left-joining the heat map ontoflatFiles. Map, Reads × freshness and Hot path are all built from that list, so all three inherited the drop; Agent coverage is built straight from the?by=deviceresponse, which does no join at all. Hence one screen saying both "No reads in the window yet" and "seed-agentread(root)andnotes".What changed
lib/heat.tsgainsorphanPaths(heatMap, known)— pure, unit-tested (Insights.tsxcan't be; node's runner doesn't do JSX).Insights.tsxderivesorphansnext topts, respecting the scope filter and the current lens exactly as tree files do. An orphan is never plotted (daysnever reachesstaleColoror the scatter'sX(),dangerstays false) — an invented position is the dishonesty fix(dashboard): make the knowledge treemap honest on a young project #93 was about..in-hp-gonelabel and routes their click/Enter toonOpenHistory;Browser.tsxpasses its existingopenHistoryto both<Insights>sites.orphans > 0, nothing at 0. The count follows the lens, so the footnote can never advertise a row Hot path won't list.Screenshots
Same seeded fixture on both sides:
scratch.mdhas 4 human reads and is deleted by the seed.origin/main)Before: Hot path lists three files totalling 58 reads; the ledger holds 62. The missing 4 are
scratch.md's, dropped silently. After: it's ranked in place, labelled, and the plots say one file's reads aren't on them.Acceptance
go build ./...,go vet ./...,go test ./...— pass.npm test— 43 pass (adds theorphanPathscases).npm run e2e— 99 pass, including two new dashboard specs: the deleted-file row is listed, labelled, footnoted and routes to/<pid>/history/scratch.md; and the footnote follows the lens.?by=devicetotals 41. (Restated from the spec per the plan —?by=deviceisAgentHeat, agent-kind reads only, so it can only reconcile under that lens.)Deviations from the plan
One, small: the plan didn't say what an orphan with zero reads under the current lens should do. Left alone, the footnote counted a file Hot path then refused to list (Hot path filters
reads > 0), which is the same class of disagreement this PR is fixing — so orphans are filtered by lens reads too, and there's an e2e spec pinning it.The plan's line references were stale in one place:
Insightsis rendered fromsrc/apps/Browser.tsx, notsrc/components/Browser.tsx. No behavioral difference.BEA-38 was re-checked as the spec asked: resolved in
01f33c9, different cause (the bar's split arithmetic, now inlib/heat.ts), does not share this join. Nothing to co-ordinate.Land this before BEA-51 — same file, same derivation. BEA-51's empty-state condition has to be
scoped.length === 0 && orphans.length === 0, or it will hide the rows this PR adds.Architecture changes
architecture/webapp-frontend.md— thelibclass listsheat.ts's exports by name, and this adds one (orphanPaths). No new seams, no changed ownership.✅ added · ❌ removed (strikethrough) · unmarked = unchanged
flowchart TB components["components"] lib["<div style='text-align:left'><b>lib</b><br/>+diff.ts splitLines lcsDiff diffText<br/>+runs.ts groupRuns runFileCount<br/>+heat.ts heatFor heatTotal heatText heatLevel hotPathSplit<br/>+heat.ts ageRange isFlatRange ageSpanLabel (treemap scale)<br/><span style='background:#22c55e55;padding:0 4px;border-radius:3px'>✅ +heat.ts orphanPaths (reads whose file left the tree)</span><br/>+sniff.ts sniffBytes BlobText MAX_BYTES<br/>+utils.ts</div>"] components -- "diffText groupRuns hotPathSplit" --> libBuild session
(only works on the machine that ran the build)