Skip to content

fix(explorer): make distance intelligence visible#513

Open
ZohaibHassan16 wants to merge 3 commits intomainfrom
feat/explorer-distance-ui-fix
Open

fix(explorer): make distance intelligence visible#513
ZohaibHassan16 wants to merge 3 commits intomainfrom
feat/explorer-distance-ui-fix

Conversation

@ZohaibHassan16
Copy link
Copy Markdown
Collaborator

Summary

This PR fixes Distance Intelligence in the Explorer UI so distance modes render through the normal Sigma reducer/theme pipeline instead of mutating raw graph attributes.

Distance Intelligence now behaves as a first-class visual state in Full Graph:

  • Ego mode fades/scales nodes by structural distance from the selected anchor
  • Heatmap mode renders a readable sampled local lens instead of painting the whole connected component
  • Structural mode highlights distance-aware context edges without breaking existing edge LOD
  • Semantic mode handles loading/unavailable/error states visibly
  • Trace Path shows distance metrics in the inspector when available

What Changed

  • Added typed distance visual state for Explorer rendering
  • Passed distance state into GraphCanvas/Sigma reducers
  • Replaced raw graph color/size mutation with reducer-driven node and edge styling
  • Added bounded structural BFS snapshots and bucket summaries
  • Added Heatmap render sampling:
    • 1-hop: capped at 120 shown
    • 2-hop: capped at 650 shown
    • 3-hop: capped at 900 shown
    • full truth counts remain visible in the status strip
  • Suppressed Heatmap background edges while preserving selected/path/local-context edges
  • Added Distance Intelligence status strip with active mode, anchor, counts, sampled status, and legend
  • Improved path distance display in the inspector
  • Added graph workspace tests for distance snapshots, heatmap sampling, reducer styling, and edge suppression

Testing

  • npx tsc -b
  • npm run test:graph-workspace

Comment thread explorer/src/workspaces/GraphWorkspace/graphSceneState.ts Fixed
KaifAhmad1 and others added 2 commits April 29, 2026 14:49
- Fix dead `if (anchorNodeId)` conditional in buildHeatmapRenderSnapshot
  (anchor is always truthy past the early-return guard on line 263)
- Replace O(n) array .includes() with WeakMap-cached Set.has() in
  resolveDistanceNodeStyle heatmap path β€” prevents per-node O(n) scan
  during every Sigma reducer pass on large graphs
- Rename GraphDistanceBucketCounts.threeHop β†’ threeHopPlus across
  types.ts, graphSceneState.ts, and GraphWorkspace.tsx so the field
  name reflects that it accumulates distance β‰₯ 3, not exactly 3;
  update status-strip labels to "3+ hop" accordingly
- Restore hasMetrics guard in PathDistanceIntelPanel to suppress the
  empty metric grid <div> when a path result carries no optional metrics

Co-Authored-By: ZohaibHassan16 <zohaib@hawksight.ai>
Co-Authored-By: KaifAhmad1 <mohammadk78600@gmail.com>
Co-Authored-By: ZohaibHassan16 <zohaib@hawksight.ai>
Co-Authored-By: KaifAhmad1 <mohammadk78600@gmail.com>
Copy link
Copy Markdown
Contributor

@KaifAhmad1 KaifAhmad1 left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

PR Review β€” #513: fix(explorer): make distance intelligence visible


Summary

This PR refactors Distance Intelligence in the Explorer UI from imperative graph-attribute mutation into a typed visual state that flows through the standard Sigma reducer/theme pipeline. All four distance modes (Ego, Heatmap, Structural, Semantic) now render as first-class visual states rather than side-effects.


What Was Reviewed

Architecture

  • Shift from raw graph.setNodeAttribute() mutation to a typed GraphDistanceVisualState passed through buildReducerSceneState β†’ Sigma reducers is the right design.
  • The renderer can now be fully described from props with no hidden side-effects on graph attributes.

New Types β€” types.ts

  • GraphDistanceVisualMode, GraphDistanceVisualStatus, GraphDistanceBucketCounts, GraphHeatmapRenderSnapshot, and GraphDistanceVisualState are well-scoped.
  • Integrate cleanly with the existing diagnostics snapshot interfaces.

Core Logic β€” graphSceneState.ts

  • buildStructuralDistanceSnapshot β€” bounded BFS, correct early-return guard, maxHops cap prevents runaway on dense graphs.
  • buildHeatmapRenderSnapshot β€” ring caps (120 / 650 / 900), deterministic sampling via hashString tiebreaker (no render flicker), saturation detection with dual-condition heuristic.
  • resolveDistanceNodeStyle / resolveDistanceEdgeStyle β€” clean per-mode dispatch, correct fallback to {} when mode is "off" or status is not "ready".

GraphCanvas β€” GraphCanvas.tsx

  • distanceVisualStateChanged ref tracking correctly invalidates the full reducer pass on state change.
  • Dependency arrays are accurate.

Inspector Panel β€” GraphInspectorPanel.tsx

  • Band chip, metric cards, and interpretation section are all conditionally rendered β€” no layout noise when fields are absent.

Test Coverage

  • 281 lines added to graphSceneState.display.test.ts covering BFS snapshots, ring capping, deterministic sampling, node style resolution, and edge suppression.
  • Adequate for the surface area changed.

Blockers Fixed β€” Follow-up Commit by @KaifAhmad1

  • Dead conditional (graphSceneState.ts:305) β€” if (anchorNodeId) is always true past the early-return guard at line 263. Removed the wrapper; statements made unconditional.
  • O(n) hot-path lookup (graphSceneState.ts:424) β€” .includes() was called per-node per Sigma render frame, up to ~8M comparisons/frame on large graphs. Added a WeakMap-backed getHeatmapVisibleSet() helper; replaced with O(1) Set.has().
  • Bucket semantic mismatch (types.ts + all callsites) β€” GraphDistanceBucketCounts.threeHop accumulated distance β‰₯ 3, not exactly 3. Renamed to threeHopPlus across types.ts, graphSceneState.ts, and GraphWorkspace.tsx; status strip now reads "3+ hop".
  • Empty metric grid (GraphInspectorPanel.tsx:91) β€” empty <div> rendered when all optional path metric fields are null, causing orphaned whitespace. Restored hasMetrics guard wrapping the grid.

Minor Notes (Non-blocking)

  • getDistanceBandColor: distance <= 3 and distance <= 6 both return "#B0883A" β€” the two branches can be collapsed into distance <= 6. Low risk, cosmetic.
  • void edgeId in buildPreviousRingEdgeScores: use _edgeId parameter name instead β€” idiomatic TS convention.
  • SemanticNeighborhoodResponse type is declared inline in GraphWorkspace.tsx β€” belongs in types.ts for discoverability.
  • Heatmap hard-caps at 3 hops regardless of maxHops (line 272). Intentional for perf but undocumented; worth a comment.

Verdict

Approved. Core architecture is solid. All four blocking issues have been resolved in the follow-up commit. Minor notes above are recommended for a future cleanup pass but do not block merge.

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