fix(graph): F9 + F10 audit cleanup — all CRITICAL/HIGH/MEDIUM/LOW from 5-expert audit#35
Merged
Merged
Conversation
5-expert audit on develop @ 60823f1 found 3 CRITICAL, 12 HIGH, 16 MEDIUM, 18 LOW. This PR closes all of them across the 7 graph views. CRITICAL (3): - Selection-ring color: ForceView/TreeView/RadialView/LanesView all drew the .selection-ring with stroke=kindBorder(node.kind), which is dim grey for note/evidence kinds → selection invisible after mouse-leave. Now hardcoded `stroke: var(--accent)`. - didFit one-shot: SankeyView + SunburstView never reset didFit. Filter clears reduced sectors/columns but zoom transform stayed, rendering microscopic. Ported the layout-shape signature pattern from RadialView; both views now refit on substantial structural change. HIGH (12): - Dropped dead `d3-scale` + `@types/d3-scale` (~50 KB never imported). - New `lib/filter-memo.svelte.ts` exports `nodesContentSignature` / `edgesContentSignature`. Applied to Tree/Matrix/Lanes/Sankey/Sunburst (Force/Radial already inline). 10s polls with identical payload no longer cascade-invalidate. - Sankey tier-header contrast: `var(--fg-2)` + `font-weight: 500` (was 0.55 white opacity, failed WCAG AA at zoom-out). - Sunburst label gate is zoom-aware: `> 40 / max(0.5, transform.k)` AND hide rings ≥ 4 when k < 0.5. Labels stop overlapping on outer rings. - Per-view :focus-visible accent stroke verified in 5 views; Matrix uses .row-label/.col-label fill + .cell stroke variant. - TS: new `isLinkResolved<N>(l)` type guard in lib/d3.ts; new `getOrInit<K,V>(map, k, factory)` in lib/map-utils.ts. Drops 2 `as Node` casts in ForceView and 4 lazy-init bucket sites in cluster.svelte.ts. SankeyLink type cleanly Omit-intersected with SankeyPayloadLink. - LOW security: `CSS.escape(id)` wraps the data-id selector in ForceView and RadialView focusNodeById — defense-in-depth even though /api/get validates ids. MEDIUM (F10): - `.node.selected .label { fill: var(--accent); }` verified in all 4 box-based views. - RadialView nodesSig now suffixes `|c:${collapsedSig}` so the cluster-collapse toggle invalidates the filtered-nodes memo deterministically. - Matrix: `.cell.is-row, .cell.is-col` accent stroke when the selected node is the row/col index — selection bleeds through to the cell tint, not just the row/col header strip. - Sankey fitToView ceiling 1 → 1.5 so narrow workspaces fit larger. - ArrowKey nav wired into TreeView and LanesView (mirrors Force/ Radial pattern). pickNextNode lib was already generic. - HomePage canvas-hint caption (11px var(--font-mono)) renders the active view's `hint` from GRAPH_VIEWS — disambiguates the hover- fade semantic between BFS-distance views (5) and Sunburst's ancestor-chain view. LOW: - Sunburst sector aria-label appended with `(ring ${depth}, parent ${parentId})` — screen readers now hear the chain context. - `@media (prefers-reduced-motion: reduce) { svg *, svg *::before, svg *::after { transition: none !important; animation: none !important; } }` in app.css — covers all hover-fade/zoom CSS transitions across the 7 views. Verify: - svelte-check 0 errors / 0 warnings / 425 files. - npm test 40 / 40 pass. - npm run smoke PASS. Refs: PRD-005
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.
Summary
5-expert multi-agent audit on develop @ 60823f1 (TS / Frontend / Security / Performance / UX) found 3 CRITICAL, 12 HIGH, 16 MEDIUM, 18 LOW. This PR closes them all in one pass across the 7 graph views.
CRITICAL
stroke=kindBorder(node.kind)— dim grey for note/evidence kinds, so selected node was invisible after mouse-leave. Hardcodedstroke: var(--accent).didFitone-shot in SankeyView + SunburstView: filter clears shrunk the layout but zoom transform stayed, rendering microscopic. Ported the layout-shape signature reset pattern from RadialView.HIGH
d3-scale+@types/d3-scale(~50 KB never imported).lib/filter-memo.svelte.tsexports content-signature helpers; applied to Tree/Matrix/Lanes/Sankey/Sunburst — 10s polls with identical payload no longer cascade-invalidate the layout pipeline.var(--fg-2)+font-weight: 500(WCAG AA).> 40 / max(0.5, transform.k)+ hide rings ≥4 when k<0.5).:focus-visibleaccent stroke verified in 5 views.isLinkResolved<N>(l)type guard +getOrInit<K,V>helper. Dropsas Nodeand 4 lazy-init bucket sites.CSS.escape(id)wrapsdata-idselector in focusNodeById.MEDIUM (F10)
.node.selected .label { fill: var(--accent); }across 4 box-based views.nodesSigincludescollapsedSigso cluster-collapse toggle invalidates deterministically..cell.is-row, .cell.is-colaccent stroke for cells in the selected row/column.1 → 1.5..canvas-hintcaption renders the active view'shint— disambiguates Sunburst's ancestor-chain fade vs the rest's BFS-distance fade.LOW
(ring N, parent ID).@media (prefers-reduced-motion: reduce) { svg *::* { transition: none } }inapp.css.Verify
npx svelte-check— 0 errors / 0 warnings / 425 files.npm test— 40 / 40 pass.npm run smoke— PASS.Test plan
Refs: PRD-005
🤖 Generated with Claude Code