Skip to content

feat(intelligence): add Graph Reach (eccentricity / diameter / radius)#2985

Open
aashir-athar wants to merge 2 commits into
tinyhumansai:mainfrom
aashir-athar:feat/graph-reach
Open

feat(intelligence): add Graph Reach (eccentricity / diameter / radius)#2985
aashir-athar wants to merge 2 commits into
tinyhumansai:mainfrom
aashir-athar:feat/graph-reach

Conversation

@aashir-athar
Copy link
Copy Markdown
Contributor

@aashir-athar aashir-athar commented May 29, 2026

Summary

Adds a new read-only "Reach" tab to the Intelligence view: BFS-based eccentricity analysis of the memory knowledge graph. Where #2946's Connection-Path lens answers "is A linked to B, and how far", this lens answers the summary question: "how far is each entity from everything else it can reach". From that fall out three classic shape metrics:

  • Diameter — the longest shortest-path anywhere in the graph,
  • Radius — the smallest eccentricity,
  • Center — the entities that reach the whole cluster in the fewest hops.

The center of your knowledge is not the highest-degree node nor the highest-PageRank node — it's the one that minimises the worst-case distance to everything else, the natural place a traversal or summary should start. Neither degree nor PageRank surfaces it.

Design

  • Pure deterministic engine (lib/memory/graphReach.ts): treats the (subject)-[predicate]->(object) triples as an undirected simple graph (direction dropped, parallel edges collapsed, self-loops dropped) and computes:
    • per-node eccentricity via BFS with an array-backed queue,
    • connected-component labelling (componentId = smallest member index, stable label),
    • per-component diameter & radius,
    • the giant component (size DESC, then smallest componentId for a stable tie-break),
    • per-node isCenter (eccentricity === component's radius — every component has a well-defined center).
    • Vertices are canonically id-sorted before indexing, so output is byte-identical regardless of relation input order. No clock, no RNG, all-integer math.
  • Zero new core surface: composes the already-shipped memoryGraphQuery / memoryListNamespaces JSON-RPC wrappers. Read-only — recomputed live, never persisted.
  • Container/presentational split; the container guards load-on-mount with a monotonic request token. The eccentricity bar in the ranked table is computed against each node's own component's diameter (so a node in a non-giant but longer component never overflows). The summary caption uses a separate singular key when componentCount === 1. i18n across all 13 locales.

Test plan

  • vitest — 25 tests (engine: empty / triangle (uniform center) / path A-B-C-D (diameter 3, radius 2, center {B,C}) / star (hub is sole center) / two-component (giant diameter; small component's local ecc) / giant tie-break by smallest componentId; self-loop drop; parallel-edge & direction collapse; both branches of the malformed-row guard; no case-folding; order-independent output across permutations — plus api facade, panel singular + plural caption variants, center badge, container load/namespace-requery/error)
  • tsc --noEmit — clean
  • eslint — 0 errors
  • prettier --check — clean
  • i18n coverage gate — EXIT 0, no missing/extra/drifted keys across 13 locales

🤖 Generated with Claude Code

Summary by CodeRabbit

  • New Features

    • Added a "Reach" tab in Memory showing graph-reach metrics (entities, diameter, radius), ranked entities with eccentricity bars and center badges, namespace selector, loading/empty/error states and a working retry.
    • Deterministic graph-reach computation with refined single/multi-component captions.
  • Localization

    • Added Graph Reach translations for many locales.
  • Tests

    • New tests covering UI, data-loading API, and graph-reach computation.

Review Change Stack

@aashir-athar aashir-athar requested a review from a team May 29, 2026 21:04
@coderabbitai
Copy link
Copy Markdown
Contributor

coderabbitai Bot commented May 29, 2026

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: 2eb4219f-01b4-43a6-bc2e-0cff350d193b

📥 Commits

Reviewing files that changed from the base of the PR and between 1020361 and 55e0405.

📒 Files selected for processing (23)
  • app/src/components/intelligence/GraphReachPanel.test.tsx
  • app/src/components/intelligence/GraphReachPanel.tsx
  • app/src/components/intelligence/GraphReachTab.test.tsx
  • app/src/components/intelligence/GraphReachTab.tsx
  • app/src/lib/i18n/chunks/ar-1.ts
  • app/src/lib/i18n/chunks/bn-1.ts
  • app/src/lib/i18n/chunks/de-1.ts
  • app/src/lib/i18n/chunks/en-1.ts
  • app/src/lib/i18n/chunks/es-1.ts
  • app/src/lib/i18n/chunks/fr-1.ts
  • app/src/lib/i18n/chunks/hi-1.ts
  • app/src/lib/i18n/chunks/id-1.ts
  • app/src/lib/i18n/chunks/it-1.ts
  • app/src/lib/i18n/chunks/ko-1.ts
  • app/src/lib/i18n/chunks/pt-1.ts
  • app/src/lib/i18n/chunks/ru-1.ts
  • app/src/lib/i18n/chunks/zh-CN-1.ts
  • app/src/lib/i18n/en.ts
  • app/src/lib/memory/graphReach.test.ts
  • app/src/lib/memory/graphReach.ts
  • app/src/pages/Intelligence.tsx
  • app/src/services/api/graphReachApi.test.ts
  • app/src/services/api/graphReachApi.ts
✅ Files skipped from review due to trivial changes (6)
  • app/src/lib/i18n/chunks/bn-1.ts
  • app/src/lib/i18n/chunks/zh-CN-1.ts
  • app/src/lib/i18n/chunks/en-1.ts
  • app/src/lib/i18n/chunks/pt-1.ts
  • app/src/lib/i18n/chunks/it-1.ts
  • app/src/lib/i18n/chunks/id-1.ts
🚧 Files skipped from review as they are similar to previous changes (17)
  • app/src/components/intelligence/GraphReachTab.test.tsx
  • app/src/lib/i18n/en.ts
  • app/src/pages/Intelligence.tsx
  • app/src/lib/i18n/chunks/ru-1.ts
  • app/src/lib/i18n/chunks/es-1.ts
  • app/src/lib/i18n/chunks/de-1.ts
  • app/src/components/intelligence/GraphReachPanel.test.tsx
  • app/src/lib/i18n/chunks/ar-1.ts
  • app/src/lib/memory/graphReach.ts
  • app/src/lib/i18n/chunks/hi-1.ts
  • app/src/services/api/graphReachApi.test.ts
  • app/src/components/intelligence/GraphReachTab.tsx
  • app/src/lib/i18n/chunks/ko-1.ts
  • app/src/components/intelligence/GraphReachPanel.tsx
  • app/src/services/api/graphReachApi.ts
  • app/src/lib/i18n/chunks/fr-1.ts
  • app/src/lib/memory/graphReach.test.ts

📝 Walkthrough

Walkthrough

Adds a deterministic graph-reach engine, an RPC facade, a data-loading tab and a presentational panel for displaying reach metrics, integrates a new "reach" tab in Intelligence, includes tests, and adds translations for multiple locales.

Changes

Graph Reach Centrality Feature

Layer / File(s) Summary
Core Graph Reach Computation Engine
app/src/lib/memory/graphReach.ts, app/src/lib/memory/graphReach.test.ts
Deterministic algorithm computing connected components, per-node eccentricity, component radius/diameter, node isCenter, and stable sorting. Tests cover basic shapes, multi-component behavior, normalization (self-loops, parallel edges), validation, and order-independence.
Graph Reach API Facade
app/src/services/api/graphReachApi.ts, app/src/services/api/graphReachApi.test.ts
RPC wrapper calling memoryGraphQuery/memoryListNamespaces, delegates to computeGraphReach, logs namespace/results, and returns reach results. Tests validate namespace passthrough, empty results, error propagation, and namespace listing.
GraphReachPanel Display Component
app/src/components/intelligence/GraphReachPanel.tsx, app/src/components/intelligence/GraphReachPanel.test.tsx
Presentational component with loading/error/empty branches and results view: metric tiles (entities/diameter/radius), singular/plural captions, and ranked table with eccentricity bars scaled per-component and center badges. Tests cover all render paths and caption variants.
GraphReachTab Data Loading Component
app/src/components/intelligence/GraphReachTab.tsx, app/src/components/intelligence/GraphReachTab.test.tsx
Container that loads reach and namespaces, manages loading/error state, uses a monotonic request id to ignore stale responses, exposes retry, and re-queries on namespace changes. Tests verify mount behavior, namespace-driven reloads, and error rendering.
Intelligence Page Integration & Translations
app/src/pages/Intelligence.tsx, app/src/lib/i18n/en.ts, app/src/lib/i18n/chunks/{ar,bn,de,en,es,fr,hi,id,it,ko,pt,ru,zh-CN}-1.ts
Adds 'reach' tab and mounts GraphReachTab. Adds memory.tab.reach and graphReach.* translation entries across locale chunks for feature title, intro, loading/error/empty states, namespace and metric labels, table headers, center badge text, and summary captions.

Sequence Diagram(s)

sequenceDiagram
  participant User
  participant GraphReachTab
  participant graphReachApi
  participant Backend as RPC Backend
  participant computeGraphReach
  participant GraphReachPanel
  User->>GraphReachTab: mount / select namespace
  GraphReachTab->>graphReachApi: loadNamespaces()
  graphReachApi->>Backend: memoryListNamespaces()
  Backend-->>graphReachApi: namespaces[]
  GraphReachTab->>graphReachApi: loadReach(namespace?)
  graphReachApi->>Backend: memoryGraphQuery(namespace?)
  Backend-->>graphReachApi: relations[]
  graphReachApi->>computeGraphReach: computeGraphReach(relations)
  computeGraphReach-->>graphReachApi: ReachResult
  graphReachApi-->>GraphReachTab: ReachResult
  GraphReachTab->>GraphReachPanel: result + loading + error + onRetry
  GraphReachPanel->>User: render metrics, caption, ranked table
Loading

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~25 minutes

Possibly related PRs

  • tinyhumansai/openhuman#2931: Adds a related Intelligence tab and knowledge-graph UI (centrality) with similar page integration patterns.

Suggested reviewers

  • graycyrus
  • M3gA-Mind

"🐰 I mapped the graph, each node in sight,
Eccentric paths glowing in soft moonlight.
Centers wear badges, metrics gently sing,
Tabs and translations make the whole thing spring.
Hop, retry, and render—reach takes wing!"

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 46.15% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title clearly and concisely summarizes the main change: adding a Graph Reach feature to the intelligence view with specific focus on the graph metrics (eccentricity, diameter, radius). This aligns with the primary objective of introducing a new read-only Reach tab performing BFS-based graph analysis.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

Warning

There were issues while running some tools. Please review the errors and either fix the tool's configuration or disable the tool if it's a critical failure.

🔧 ESLint

If the error stems from missing dependencies, add them to the package.json file. For unrecoverable errors (e.g., due to private dependencies), disable the tool in the CodeRabbit configuration.

ESLint skipped: no ESLint configuration detected in root package.json. To enable, add eslint to devDependencies.


Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

@coderabbitai coderabbitai Bot added feature Net-new user-facing capability or product behavior. memory Memory store, memory tree, recall, summarization, and embeddings in src/openhuman/memory/. working A PR that is being worked on by the team. labels May 29, 2026
Copy link
Copy Markdown
Contributor

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 1

🧹 Nitpick comments (1)
app/src/components/intelligence/GraphReachTab.tsx (1)

40-47: ⚡ Quick win

Use async/await for the bootstrap path and log swallowed namespace failures.

The mount effect still uses a .then().catch() chain and silently drops selector-load errors. Converting this to an inner async function keeps the file consistent with the repo’s TypeScript style and gives you a place to emit the required namespaced debug log when namespaces fail but reach loading continues.

♻️ Proposed refactor
+import debug from 'debug';
 import { useCallback, useEffect, useRef, useState } from 'react';
@@
+const log = debug('graph-reach:tab');
+
 const GraphReachTab = () => {
@@
   useEffect(() => {
-    // Namespaces are optional UI sugar; a failure to list them must not block
-    // the reach view, so swallow that error specifically.
-    loadNamespaces()
-      .then(setNamespaces)
-      .catch(() => setNamespaces([]));
-    void load('');
+    void (async () => {
+      // Namespaces are optional UI sugar; a failure to list them must not block
+      // the reach view, so swallow that error specifically.
+      try {
+        setNamespaces(await loadNamespaces());
+      } catch (err) {
+        log('loadNamespaces failed: %O', err);
+        setNamespaces([]);
+      }
+      await load('');
+    })();
   }, [load]);

As per coding guidelines, "Always use async/await for promises in TypeScript rather than .then() chains" and "verbose logging required on new/changed flows".

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@app/src/components/intelligence/GraphReachTab.tsx` around lines 40 - 47,
Convert the useEffect to call an inner async function that awaits both
loadNamespaces() and load(''), replacing the .then().catch() chain; inside that
async function await loadNamespaces(), call setNamespaces(result) on success,
and in the catch block call setNamespaces([]) but also emit a verbose debug log
(e.g., console.debug or the component logger) with the caught error to record
the swallowed namespace failure; finally await load('') so reach loading always
runs, and invoke the inner async function from useEffect while keeping the
dependency on [load].
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@app/src/lib/i18n/en.ts`:
- Around line 343-344: Add a new i18n key for the singular entity case (e.g.,
'graphReach.summaryCaptionOneEntity') so the copy can be "1 component · 1
entity", and update the UI panel to choose between
'graphReach.summaryCaptionOne' and the new singular key when rendering the
caption by checking the giantComponentSize value (i.e., when component count is
1 use the '...One' key, and when giantComponentSize === 1 use the new singular
key); ensure you reference the existing keys 'graphReach.summaryCaption' and
'graphReach.summaryCaptionOne' when implementing the branch so the caption logic
uses the appropriate key based on giantComponentSize.

---

Nitpick comments:
In `@app/src/components/intelligence/GraphReachTab.tsx`:
- Around line 40-47: Convert the useEffect to call an inner async function that
awaits both loadNamespaces() and load(''), replacing the .then().catch() chain;
inside that async function await loadNamespaces(), call setNamespaces(result) on
success, and in the catch block call setNamespaces([]) but also emit a verbose
debug log (e.g., console.debug or the component logger) with the caught error to
record the swallowed namespace failure; finally await load('') so reach loading
always runs, and invoke the inner async function from useEffect while keeping
the dependency on [load].
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: 8b4794e5-2fc8-4b9d-853f-aac4ca6c9b4e

📥 Commits

Reviewing files that changed from the base of the PR and between 2920e47 and 6c48f2e.

📒 Files selected for processing (23)
  • app/src/components/intelligence/GraphReachPanel.test.tsx
  • app/src/components/intelligence/GraphReachPanel.tsx
  • app/src/components/intelligence/GraphReachTab.test.tsx
  • app/src/components/intelligence/GraphReachTab.tsx
  • app/src/lib/i18n/chunks/ar-1.ts
  • app/src/lib/i18n/chunks/bn-1.ts
  • app/src/lib/i18n/chunks/de-1.ts
  • app/src/lib/i18n/chunks/en-1.ts
  • app/src/lib/i18n/chunks/es-1.ts
  • app/src/lib/i18n/chunks/fr-1.ts
  • app/src/lib/i18n/chunks/hi-1.ts
  • app/src/lib/i18n/chunks/id-1.ts
  • app/src/lib/i18n/chunks/it-1.ts
  • app/src/lib/i18n/chunks/ko-1.ts
  • app/src/lib/i18n/chunks/pt-1.ts
  • app/src/lib/i18n/chunks/ru-1.ts
  • app/src/lib/i18n/chunks/zh-CN-1.ts
  • app/src/lib/i18n/en.ts
  • app/src/lib/memory/graphReach.test.ts
  • app/src/lib/memory/graphReach.ts
  • app/src/pages/Intelligence.tsx
  • app/src/services/api/graphReachApi.test.ts
  • app/src/services/api/graphReachApi.ts

Comment thread app/src/lib/i18n/en.ts
aashir-athar added a commit to aashir-athar/openhuman that referenced this pull request May 29, 2026
…ty caption

Address CodeRabbit review on tinyhumansai#2985:
- buildAdjacency now drops the self-loop EDGE but registers the endpoint as
  a node, matching the sibling Graph Core fix. A user whose only recorded
  fact is "Alice→Alice" now appears as a singleton component (size 1,
  eccentricity 0) instead of vanishing into the empty state.
- Adds graphReach.summaryCaptionOneAndOne ('1 component · 1 entity') and a
  panel branch so the singleton case never renders as the ungrammatical
  "1 component · 1 entities".
- Regression tests for both the engine (Alice→Alice -> singleton) and the
  panel (renders the all-singular caption variant) lock the behaviour.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
aashir-athar and others added 2 commits May 30, 2026 06:29
A new read-only "Reach" tab for the Intelligence view: BFS-based eccentricity
analysis of the memory knowledge graph. Where the Connection-Path lens answers
"is A linked to B, and how far", this lens answers the summary question: "how
far is each entity from everything else it can reach". From that fall out the
DIAMETER (the longest shortest-path), RADIUS (the smallest), and CENTER (the
entities that reach the whole cluster in the fewest hops) — a node neither
degree nor PageRank can surface.

Engine (pure, deterministic — no React/RPC/clock/RNG):
- per-node eccentricity via BFS (with an array-backed queue),
- connected-component labelling,
- per-component diameter & radius,
- giant component (size DESC, then smallest componentId for stable ties),
- per-node isCenter flag (ecc === its component's radius).
Vertices are canonically id-sorted before indexing, so output is byte-identical
regardless of relation input order.

Adds ZERO new core surface: composes the already-shipped memoryGraphQuery /
memoryListNamespaces JSON-RPC wrappers. Container/presentational split with a
monotonic request-token race guard for load-on-mount; i18n across all 13 locales.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
…ty caption

Address CodeRabbit review on tinyhumansai#2985:
- buildAdjacency now drops the self-loop EDGE but registers the endpoint as
  a node, matching the sibling Graph Core fix. A user whose only recorded
  fact is "Alice→Alice" now appears as a singleton component (size 1,
  eccentricity 0) instead of vanishing into the empty state.
- Adds graphReach.summaryCaptionOneAndOne ('1 component · 1 entity') and a
  panel branch so the singleton case never renders as the ungrammatical
  "1 component · 1 entities".
- Regression tests for both the engine (Alice→Alice -> singleton) and the
  panel (renders the all-singular caption variant) lock the behaviour.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

feature Net-new user-facing capability or product behavior. memory Memory store, memory tree, recall, summarization, and embeddings in src/openhuman/memory/. working A PR that is being worked on by the team.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant