Skip to content

feat(intelligence): add Knowledge Gaps#2956

Open
aashir-athar wants to merge 3 commits into
tinyhumansai:mainfrom
aashir-athar:feat/knowledge-gaps
Open

feat(intelligence): add Knowledge Gaps#2956
aashir-athar wants to merge 3 commits into
tinyhumansai:mainfrom
aashir-athar:feat/knowledge-gaps

Conversation

@aashir-athar
Copy link
Copy Markdown
Contributor

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

Summary

Adds a new read-only "Gaps" tab — the inverse of the Knowledge Graph Centrality lens. Instead of the hubs the assistant knows the most about, it surfaces the thin spots: orphan (0-connection) and leaf (1-connection) entities it has barely recorded anything about — the best candidates for the assistant to enrich. Each gap also flags entities that appear only as an object ("mentioned, never described"), an even stronger stub signal.

Design

  • Pure & deterministic (lib/memory/knowledgeGaps.ts): classifies every entity by its distinct undirected neighbour count — orphan (0), leaf (1), connected (2+); self-loops don't count as a connection. Tracks object-only entities and reports orphan/leaf/connected counts plus a gap ratio. No clock, no RNG; gaps sorted orphan-before-leaf then id-asc (stable, relation-order-invariant).
  • Zero new core surface: reuses the already-shipped memoryGraphQuery and memoryListNamespaces wrappers. Read-only — recomputed from the live graph on mount.
  • Container/presentational split; the container guards the load with a monotonic request token; namespace selector; summary tiles + gap-ratio caption + the sparse-entity list with kind badges, a distinct "all connected" state, and a truncation note past 50. i18n across all 13 locales.

Edge cases (tested)

Empty graph, the orphan/leaf/connected classification, self-loop-only entities (orphan, degree 0), object-only detection, well-connected exclusion, order-invariance, and malformed rows dropped.

Test plan

  • vitest — 20 tests (engine classification + object-only + self-loop + order-invariance; api facade; panel states incl. all-connected; container load + selector + error)
  • tsc --noEmit — clean
  • eslint — 0 errors
  • prettier --check — clean
  • i18n coverage gate — EXIT 0, no unused knowledgeGaps.* keys

🤖 Generated with Claude Code

Summary by CodeRabbit

  • New Features

    • Added a Knowledge Gaps tab and panel to surface sparsely connected entities (orphans/leaves) with metrics, truncated lists, namespace filtering, loading/error/empty states, and retry support.
  • API

    • Added read-only endpoints to load namespaces and produce Knowledge Gaps reports.
  • Tests

    • Added comprehensive tests for computation, API calls, tab behavior, and panel rendering states.
  • Internationalization

    • Added Knowledge Gaps translations for multiple languages.

Review Change Stack

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

coderabbitai Bot commented May 29, 2026

Warning

Review limit reached

@aashir-athar, we couldn't start this review because you've reached your PR review rate limit.

More reviews will be available in 4 minutes and 10 seconds. Learn how PR review limits work.

Your organization has run out of usage credits. Purchase more in the billing tab.

⌛ How to resolve this issue?

After more reviews become available, a review can be triggered using the @coderabbitai review command as a PR comment. Alternatively, push new commits to this PR.

We recommend that you space out your commits to avoid hitting the rate limit.

🚦 How do rate limits work?

CodeRabbit enforces hourly rate limits for each developer per organization.

Our paid plans include higher PR review limits than trial, open-source, and free plans. In all cases, reviews become available again over time. During sustained high-volume PR review activity, CodeRabbit may temporarily slow when the next review becomes available.

Please see our Fair Usage Limits Policy for further information.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: 0e7737fe-d53a-43a8-9952-f2475ef59b35

📥 Commits

Reviewing files that changed from the base of the PR and between 6cdf509 and 665f934.

📒 Files selected for processing (2)
  • app/src/components/intelligence/KnowledgeGapsTab.test.tsx
  • app/src/pages/Intelligence.tsx
📝 Walkthrough

Walkthrough

Adds a Knowledge Gaps intelligence feature: computes graph sparsity, exposes a read-only API, adds a namespaced Intelligence tab and presentational panel, integrates translations, and includes unit and UI tests.

Changes

Knowledge Gaps Intelligence Feature

Layer / File(s) Summary
Graph sparsity computation and types
app/src/lib/memory/knowledgeGaps.ts, app/src/lib/memory/knowledgeGaps.test.ts
computeKnowledgeGaps analyzes relations to identify orphans (degree 0) and leaves (degree 1), sorts gaps deterministically, tracks objectOnly, and returns a report with counts and gapRatio. Tests cover empty inputs, classification, order invariance, self-loops, and malformed relations.
API facade for knowledge gaps loading
app/src/services/api/knowledgeGapsApi.ts, app/src/services/api/knowledgeGapsApi.test.ts
knowledgeGapsApi queries relations via memoryGraphQuery (optional namespace), logs relation counts, returns computeKnowledgeGaps(relations), and exposes loadNamespaces(). Tests verify namespace passthrough, default behavior, result mapping, and error propagation.
Knowledge gaps presentational component
app/src/components/intelligence/KnowledgeGapsPanel.tsx, app/src/components/intelligence/KnowledgeGapsPanel.test.tsx
KnowledgeGapsPanel conditionally renders a loading skeleton, error callout with retry, empty state, or populated view with metric tiles (entities/orphans/leaves), gap ratio caption, and a truncated list of sparse entities with kind/object-only badges. Tests cover all UI states and interactions (retry).
Knowledge gaps tab container with namespace filtering
app/src/components/intelligence/KnowledgeGapsTab.tsx, app/src/components/intelligence/KnowledgeGapsTab.test.tsx
KnowledgeGapsTab manages report/loading/error state, loads namespaces and gaps on mount, uses monotonic request IDs to ignore stale responses, renders a namespace selector, and delegates UI to KnowledgeGapsPanel. Tests cover initial load, namespace selection causing reloads, and error display.
Integration into Intelligence page tab system
app/src/pages/Intelligence.tsx
Imports KnowledgeGapsTab, extends IntelligenceTab union with 'gaps', adds a tab entry using t('memory.tab.gaps'), and conditionally renders the tab content when active.
Localized UI strings across multiple language chunks
app/src/lib/i18n/chunks/{ar,bn,de,en,es,fr,hi,id,it,ko,pt,ru,zh-CN}-1.ts, app/src/lib/i18n/en.ts
Adds memory.tab.gaps and knowledgeGaps.* translation entries (title, intro, loading/error/retry/empty states, entity metrics, ratio caption, kind labels, truncation, and namespace labels) for the Knowledge Gaps UI.

Sequence Diagram(s)

sequenceDiagram
  participant User
  participant KnowledgeGapsTab
  participant KnowledgeGapsAPI
  participant memoryGraphQuery
  participant computeKnowledgeGaps
  participant KnowledgeGapsPanel
  User->>KnowledgeGapsTab: open tab / select namespace
  KnowledgeGapsTab->>KnowledgeGapsAPI: loadKnowledgeGaps(namespace)
  KnowledgeGapsAPI->>memoryGraphQuery: memoryGraphQuery(namespace?)
  memoryGraphQuery-->>KnowledgeGapsAPI: GraphRelation[]
  KnowledgeGapsAPI->>computeKnowledgeGaps: computeKnowledgeGaps(relations)
  computeKnowledgeGaps-->>KnowledgeGapsAPI: KnowledgeGapsReport
  KnowledgeGapsAPI-->>KnowledgeGapsTab: KnowledgeGapsReport
  KnowledgeGapsTab->>KnowledgeGapsPanel: render(report, loading, error, onRetry)
  KnowledgeGapsPanel-->>User: UI (skeleton / error / empty / gaps list)
Loading

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~20 minutes

Possibly related PRs

Suggested reviewers

  • graycyrus
  • sanil-23

Poem

A rabbit hops through sparse graphs with glee, 🐰
Counting orphans and leaves beneath each tree,
Namespaces picked, reports neat and bright,
Panels and tests all ready to sight,
Hooray — gaps found, and the UI hums light ✨

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 33.33% 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 PR title 'feat(intelligence): add Knowledge Gaps' clearly and concisely summarizes the main change: adding a new Knowledge Gaps feature to the intelligence/memory UI.
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.


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

🤖 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/components/intelligence/KnowledgeGapsTab.test.tsx`:
- Around line 41-44: The test currently asserts mockLoad was called immediately
after render which can race because loadKnowledgeGaps is invoked in an effect;
change the assertion to be async by awaiting a waitFor that checks mockLoad was
called with undefined (e.g., await waitFor(() =>
expect(mockLoad).toHaveBeenCalledWith(undefined))); keep the subsequent waitFor
for the rendered text and reference KnowledgeGapsTab, mockLoad, and
loadKnowledgeGaps when locating the code to update.
🪄 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: c1717efa-31fb-4cfb-9230-dbe999980b90

📥 Commits

Reviewing files that changed from the base of the PR and between aac6515 and ca861c8.

📒 Files selected for processing (23)
  • app/src/components/intelligence/KnowledgeGapsPanel.test.tsx
  • app/src/components/intelligence/KnowledgeGapsPanel.tsx
  • app/src/components/intelligence/KnowledgeGapsTab.test.tsx
  • app/src/components/intelligence/KnowledgeGapsTab.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/knowledgeGaps.test.ts
  • app/src/lib/memory/knowledgeGaps.ts
  • app/src/pages/Intelligence.tsx
  • app/src/services/api/knowledgeGapsApi.test.ts
  • app/src/services/api/knowledgeGapsApi.ts

Comment on lines +41 to +44
it('loads on mount and renders the gap list', async () => {
render(<KnowledgeGapsTab />);
expect(mockLoad).toHaveBeenCalledWith(undefined);
await waitFor(() => expect(screen.getByText('Sparse entities')).toBeInTheDocument());
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟡 Minor | ⚡ Quick win

Make the mount-call assertion async to avoid timing flakes.

loadKnowledgeGaps is triggered from an effect, so asserting it immediately after render can race in some runs. Wrap it in waitFor.

Suggested fix
   it('loads on mount and renders the gap list', async () => {
     render(<KnowledgeGapsTab />);
-    expect(mockLoad).toHaveBeenCalledWith(undefined);
+    await waitFor(() => expect(mockLoad).toHaveBeenCalledWith(undefined));
     await waitFor(() => expect(screen.getByText('Sparse entities')).toBeInTheDocument());
   });
As per coding guidelines, “keep tests deterministic with no real network calls or time-sensitive flakes.”
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
it('loads on mount and renders the gap list', async () => {
render(<KnowledgeGapsTab />);
expect(mockLoad).toHaveBeenCalledWith(undefined);
await waitFor(() => expect(screen.getByText('Sparse entities')).toBeInTheDocument());
it('loads on mount and renders the gap list', async () => {
render(<KnowledgeGapsTab />);
await waitFor(() => expect(mockLoad).toHaveBeenCalledWith(undefined));
await waitFor(() => expect(screen.getByText('Sparse entities')).toBeInTheDocument());
});
🤖 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/KnowledgeGapsTab.test.tsx` around lines 41 -
44, The test currently asserts mockLoad was called immediately after render
which can race because loadKnowledgeGaps is invoked in an effect; change the
assertion to be async by awaiting a waitFor that checks mockLoad was called with
undefined (e.g., await waitFor(() =>
expect(mockLoad).toHaveBeenCalledWith(undefined))); keep the subsequent waitFor
for the rendered text and reference KnowledgeGapsTab, mockLoad, and
loadKnowledgeGaps when locating the code to update.

@aashir-athar
Copy link
Copy Markdown
Contributor Author

Thanks @coderabbitai — addressed: the mount-call assertion now runs after the waitFor, so it can't race the load effect. Also added the missing knowledgeGaps.namespaceLabel / namespaceAll keys (the namespace selector only renders when namespaces exist). i18n coverage EXIT 0; tests green.

@coderabbitai
Copy link
Copy Markdown
Contributor

coderabbitai Bot commented May 29, 2026

Tip

For best results, initiate chat on the files or code changes.

@aashir-athar Great work on both fixes! Moving the assertion after waitFor cleanly eliminates the race window, and adding namespaceLabel / namespaceAll ensures the selector renders correctly while keeping the i18n coverage gate green. Everything looks solid — thanks for the thorough follow-through! 🐇✨


If you found this review helpful, would you consider giving us a shout-out on X?

Thank you for using CodeRabbit!

@sanil-23 sanil-23 self-assigned this May 29, 2026
aashir-athar and others added 2 commits May 30, 2026 06:53
A new read-only "Gaps" tab — the inverse of the centrality lens. Instead of the
hubs the assistant knows most about, it surfaces the THIN spots: orphan
(0-connection) and leaf (1-connection) entities the assistant has barely
recorded anything about, the best candidates to enrich. Each gap also flags
entities that appear only as an object ("mentioned, never described").

- Pure deterministic engine (lib/memory/knowledgeGaps.ts): classifies every
  entity by distinct undirected neighbour count (orphan/leaf/connected; self-
  loops don't count), tracks object-only entities, and reports counts + gap
  ratio. No clock, no RNG; gaps sorted orphan-before-leaf then id-asc.
- Zero new core surface: reuses memoryGraphQuery + memoryListNamespaces.
  Read-only, recomputed from the live graph.
- Container guards the load with a request token; namespace selector; summary
  tiles + gap-ratio caption + the sparse-entity list with kind badges and an
  "all connected" state, capped with a truncation note. i18n across 13 locales.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
KnowledgeGapsTab references knowledgeGaps.namespaceLabel / namespaceAll but they
were never defined, so the namespace selector would render the raw keys. Add
both to en.ts + the locale chunks. (The selector only renders when namespaces
exist, which is why the empty-namespace tests didn't surface it.)

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
@aashir-athar aashir-athar force-pushed the feat/knowledge-gaps branch from 660b9a2 to 6cdf509 Compare May 30, 2026 01:54
Address CodeRabbit: assert loadKnowledgeGaps was called with undefined only
after the rendered result settles, avoiding any effect-timing flakiness.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
@aashir-athar aashir-athar force-pushed the feat/knowledge-gaps branch from 6cdf509 to 665f934 Compare May 30, 2026 02:07
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.

2 participants