Skip to content

fix(hub): the Dashboard can filter by shared reads, not just human and agent (BEA-62) - #117

Merged
ssowonny merged 2 commits into
mainfrom
bea-62-ph-scan-bug-dashboard-read-type-filter-chips-omit-shared
Aug 5, 2026
Merged

fix(hub): the Dashboard can filter by shared reads, not just human and agent (BEA-62)#117
ssowonny merged 2 commits into
mainfrom
bea-62-ph-scan-bug-dashboard-read-type-filter-chips-omit-shared

Conversation

@ssowonny

@ssowonny ssowonny commented Aug 5, 2026

Copy link
Copy Markdown
Contributor

TL;DR

  • The Dashboard named three kinds of read and let you filter two — the missing one was shared, the traffic from links you minted yourself.
  • Adds a fourth chip. Everything downstream already spoke "share", so the treemap, the scatter and the counts came along for free.
  • One spot needed real thought: the Hot path bar branched agent-vs-human, so share reads would have been painted as somebody else's traffic.
  • The e2e seed had zero share reads, so the lens was unassertable — it gains one, on a path nothing else counts.
  • Known gap kept as-is: under the Shared lens the Agent coverage matrix still shows device folders (device-scoped, no share equivalent — out of scope per the plan).

Closes BEA-62.

The hole

The page's own vocabulary, across the three places it appears:

read type Hot path legend file header count filter chip
human yes yes yes
agent yes yes yes
share yes yes no

So the one category a project owner most wants to isolate was the one with no
way to isolate it.

Before After
chips before chips after

What changed

type Lens was a three-value union while every heat entry already carried
share: heatTotal, heatText and hotPathSplit all handle it, and /heat
returns it per path. Widening the union makes e[lens] resolve e.share, so
the treemap, the scatter, the orphan footnote and the Hot path arithmetic are
correct without touching any of them.

Two small refactors came with it, both to stop a nested ternary growing a
fourth arm:

  • LENS_ORDER + LENS_LABEL replace the inline l === "all" ? … : … chain in the chip row.
  • PURE — a lookup from lens to bar split — replaces the agent/human ternary at the Hot path bar. This is the only line that decided anything: without a share entry the bar falls through to the real split and paints share-only reads in agent's or human's colour.

No Go change beyond the seed. No API change: /heat already returned these
numbers, and nothing in this diff adds an actor identity to any response — the
chip is a count filter, not a reader list.

The new lens, end to end

whole project, All reads (unchanged) the same project, Shared reads
dashboard all dashboard share

And the bar, which is the part that could have been wrong — one row, painted in
the share swatch rather than agent's orange or human's blue:

hot path under the share lens

Two deviations from the reviewed plan

Both in the tests, neither in the behavior.

  1. The plan asserted "Hot path holds exactly one row" under the share lens. It doesn't. The Playwright suite shares one mutable hub, and browse.spec.ts and sec12.spec.ts mint share links and open them — which records real share reads on guide.md, index.md and pages/sec12-tab.html. The count came back 3, and would move again the next time someone adds a share spec. The test now asserts the invariant instead: notes/deep/topic.md present with its 3 reads and a share-coloured bar, and two files with reads but no share reads (archive/retired-spec.md, scratch.md) absent — the lens filters, it doesn't merely re-sort.
  2. 0.0% isn't in the DOM. The plan's bar assertion read the style attribute; the browser serializes width: 0.0% down to width: 0%. It checks computed CSS (toHaveCSS("width", "0px")) instead, which is what the assertion meant anyway.

The seed row landed where the plan put it — notes/deep/topic.md, deliberately a
path with no existing assertions. notes/deep does now carry a heat dot in its
folder listing; browse.spec.ts:50 and layout.spec.ts:158 both survive it
(one names a different file, the other counts dots dynamically), verified by
running the full suite rather than reasoning about it.

Worth a look before approving

At 360px the four chips fit with no horizontal scroll and nothing clipped, but
each label now wraps to two lines where three chips sat on one. .in-lens has
no flex-wrap, so this is squeeze rather than wrap. It reads fine to me and
adding flex-wrap: wrap would change the layout at every width, so I left it —
but it's a judgement call and it's yours:

chips at 360px

What was run

  • go test ./... — green (full suite, including internal/webapp).
  • go vet ./... — clean.
  • npm run e2e148 passed, 1 skipped (the skip is the pre-existing sec14fe.spec.ts:300). Baseline was 146; the two new specs are the delta.
  • npm test (frontend units) — 53 passed.
  • frontend/check-dist.shinternal/webapp/static is fresh, rebuilt assets committed.
  • UI driven for real against the seeded hub at :8993 — every screenshot above is from that run, at 1280×900 and at 360/390/430px.

No architecture diagram change: architecture/webapp-frontend.md already lists
Insights and hotPathSplit, and no type or relationship it draws moved.

Build session

cd $(git worktree list | grep bea-62 | awk '{print $1}') && claude --resume 78d4f200-e6d5-4149-86e2-f9911b24aac4

(Only works on the machine this ran on.)

…d agent

The page named three read types and let you filter two. The missing chip was
share — traffic from public links an owner minted, which is the category they
most want to isolate.

Everything but the lens already spoke "share": heatTotal, heatText and
hotPathSplit all carry it, and /heat returns it per path. So widening the
union makes the treemap, the scatter and the Hot path arithmetic correct for
free. The one place that decided anything was the Hot path bar, which
branched agent-vs-human and would have painted shared reads in somebody
else's colour; it now looks the pure lens up in a table instead.

The e2e seed had no share reads at all, so the lens could not be asserted.
It gains one on notes/deep/topic.md — a path no other assertion counts, so
nothing else's totals move.

BEA-62
# Conflicts:
#	internal/webapp/static/assets/index-BMdHuKLj.js
#	internal/webapp/static/assets/index-BhUNiSiq.css
#	internal/webapp/static/assets/index-C09zb-Gt.js
#	internal/webapp/static/assets/index-Cj99Pu7j.js
#	internal/webapp/static/index.html
@ssowonny
ssowonny merged commit 00581f2 into main Aug 5, 2026
2 checks passed
@ssowonny
ssowonny deleted the bea-62-ph-scan-bug-dashboard-read-type-filter-chips-omit-shared branch August 5, 2026 07:19
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.

1 participant