Skip to content

feat(memory): redesign memory workspace with graph, insights, heatmap#185

Merged
senamakel merged 6 commits intotinyhumansai:mainfrom
senamakel:feat/better-memory
Apr 2, 2026
Merged

feat(memory): redesign memory workspace with graph, insights, heatmap#185
senamakel merged 6 commits intotinyhumansai:mainfrom
senamakel:feat/better-memory

Conversation

@senamakel
Copy link
Copy Markdown
Member

@senamakel senamakel commented Apr 2, 2026

Summary

  • Break monolithic MemoryWorkspace into focused sub-components: MemoryStatsBar, MemoryGraphMap, MemoryInsights, MemoryHeatmap
  • Add interactive knowledge graph visualization with force-directed layout and namespace coloring
  • Add intelligent insights panel that categorizes graph relations (facts, preferences, relationships, skills, opinions)
  • Add 8-month fixed-width ingestion activity heatmap (GitHub-style contribution grid) based on document/relation timestamps
  • Fix pre-existing lint errors in MemoryGraphMap (requestAnimationFramewindow.requestAnimationFrame, remove unused useRef)

Test plan

  • Verify Memory page renders all 4 sections (stats bar, graph, insights, heatmap)
  • Verify heatmap displays 8-month range without horizontal scrolling
  • Verify graph nodes are interactive (click to highlight connections)
  • Verify insights panel groups relations into correct categories
  • Verify "Files & Management" collapsible section works
  • Run yarn typecheck — passes clean
  • Run yarn lint — no new errors (1 pre-existing warning in MemoryGraphMap)

🤖 Generated with Claude Code

Summary by CodeRabbit

  • New Features

    • Interactive memory graph with node selection and relationship mapping
    • Activity heatmap showing ingestion patterns over time
    • Insight cards that categorize and summarize relations (expandable)
    • Statistics dashboard presenting storage, counts, and recent activity
  • Changes

    • Workspace UI reorganized to surface new graph/insights/heatmap and collapsible management section
    • Updated headings, empty-state text, and refresh button label behavior

senamakel and others added 5 commits April 1, 2026 17:53
… performance

- Updated the MemoryHeatmap component to track document/relation timestamps over the last 8 months instead of 52 weeks.
- Improved date handling by aligning the start date to the nearest Sunday and counting timestamps within the display range.
- Enhanced grid generation logic to dynamically calculate the number of weeks displayed based on the available data.
- Adjusted SVG dimensions to ensure proper scaling and responsiveness.
- Updated UI text to reflect the new time frame for event tracking.

These changes improve the accuracy and usability of the MemoryHeatmap, providing a clearer view of user activity over time.
Break MemoryWorkspace into focused sub-components (MemoryStatsBar,
MemoryGraphMap, MemoryInsights, MemoryHeatmap). Fix lint errors in
MemoryGraphMap (window.rAF, unused ref). Change heatmap to fixed
8-month range with responsive SVG width.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
@coderabbitai
Copy link
Copy Markdown
Contributor

coderabbitai Bot commented Apr 2, 2026

📝 Walkthrough

Walkthrough

Four new React components—MemoryGraphMap, MemoryHeatmap, MemoryInsights, and MemoryStatsBar—are added to visualize memory data. MemoryWorkspace is refactored to integrate these components, replace inline implementations, change timestamp extraction and storage calculations, and adjust UI/controls.

Changes

Cohort / File(s) Summary
New Visualization Components
app/src/components/intelligence/MemoryGraphMap.tsx, app/src/components/intelligence/MemoryHeatmap.tsx, app/src/components/intelligence/MemoryInsights.tsx, app/src/components/intelligence/MemoryStatsBar.tsx
Added four components: interactive force-simulated graph with selection/highlighting (MemoryGraphMap); 6-month daily activity heatmap with tooltip (MemoryHeatmap); categorized/expandable relation insights (MemoryInsights); top stats/cards with formatters (MemoryStatsBar).
Refactored Parent Component
app/src/components/intelligence/MemoryWorkspace.tsx
Replaced inline graph/insights/heatmap with new components; removed local MemoryNode logic; switched timestamp parsing to extractTimestamp (Unix seconds); added estimateContentSize, oldestTimestamp, newestTimestamp, and heatmapTimestamps; added collapsible Files & Management section and updated refresh UI.
Tests
app/src/components/intelligence/__tests__/MemoryWorkspace.test.tsx
Updated test expectations and labels to reflect new UI strings/sections (heading, stats labels, graph section label, and empty-state message).

Sequence Diagram

sequenceDiagram
    participant W as MemoryWorkspace
    participant G as MemoryGraphMap
    participant H as MemoryHeatmap
    participant I as MemoryInsights
    participant S as MemoryStatsBar

    W->>W: Extract relations, cap/sort edges & nodes
    W->>W: Extract timestamps from docs & relations
    W->>W: Compute storage, oldest/newest timestamps

    W->>G: send relations, loading
    activate G
    G->>G: compute force layout (repel/attract/center)
    G->>G: render SVG edges, nodes, legend
    deactivate G

    W->>H: send heatmapTimestamps, loading
    activate H
    H->>H: aggregate daily counts (6-month window)
    H->>H: render heatmap grid + tooltip
    deactivate H

    W->>I: send relations, loading
    activate I
    I->>I: categorize relations by predicate
    I->>I: render expandable category cards
    deactivate I

    W->>S: send metrics, loading
    activate S
    S->>S: format bytes/dates/numbers
    S->>S: render stats cards grid
    deactivate S
Loading

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~45 minutes

Poem

🐰 In a meadow of nodes I hop and weave,
Lines of memory twine and softly cleave,
Heatmap suns and insights bloom,
Stats keep watch in their tidy room,
A small rabbit cheers the work we achieve. 🥕

🚥 Pre-merge checks | ✅ 2 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 9.09% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (2 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title accurately summarizes the main change: a comprehensive redesign of the memory workspace introducing three new visualization components (graph, insights, heatmap).

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

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests

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

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 (7)
app/src/components/intelligence/MemoryGraphMap.tsx (4)

96-150: Force simulation runs synchronously and may cause UI jank.

The O(n²) simulation with up to 100 nodes and 150 iterations (≈1.5M operations) runs in useMemo on the main thread. While the caps keep it bounded, consider logging a warning or adding performance monitoring for debugging large graphs.

As per coding guidelines, add a namespaced debug log for tracing performance in new flows:

const startTime = performance.now();
const simulated = runSimulation(rawNodes, rawEdges);
console.debug('[MemoryGraphMap] simulation completed', {
  nodes: rawNodes.length,
  edges: rawEdges.length,
  durationMs: performance.now() - startTime,
});
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@app/src/components/intelligence/MemoryGraphMap.tsx` around lines 96 - 150,
The force simulation runSimulation is expensive and runs synchronously (called
from useMemo) which can cause UI jank; wrap the call to runSimulation in a
performance measurement: record start = performance.now(), call
runSimulation(rawNodes, rawEdges), then console.debug('[MemoryGraphMap]
simulation completed', { nodes: rawNodes.length, edges: rawEdges.length,
durationMs: performance.now() - start }); also emit a namespaced console.warn
when rawNodes.length exceeds a threshold (e.g., 50) to aid debugging and
monitoring; place these changes where useMemo invokes runSimulation inside
MemoryGraphMap so the log context and counts are accurate.

55-67: Inconsistent namespace assignment for subjects vs objects.

For subjects (line 60), the namespace is always overwritten with r.namespace, while for objects (line 64), the existing namespace is preserved (existingObj?.namespace ?? r.namespace). This inconsistency means the subject's namespace depends on the last relation processed, which may not be intentional.

♻️ Suggested consistency fix
   for (const r of cappedRelations) {
     const subKey = r.subject.toLowerCase();
     const objKey = r.object.toLowerCase();

     const existing = entitySet.get(subKey);
-    entitySet.set(subKey, { namespace: r.namespace, count: (existing?.count ?? 0) + 1 });
+    entitySet.set(subKey, {
+      namespace: existing?.namespace ?? r.namespace,
+      count: (existing?.count ?? 0) + 1,
+    });

     const existingObj = entitySet.get(objKey);
     entitySet.set(objKey, {
       namespace: existingObj?.namespace ?? r.namespace,
       count: (existingObj?.count ?? 0) + 1,
     });
   }
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@app/src/components/intelligence/MemoryGraphMap.tsx` around lines 55 - 67, The
subject namespace is being overwritten on every iteration while the object
preserves an existing namespace; update the subject handling in the loop over
cappedRelations so entitySet.set(subKey, ...) uses the same preservation logic
as objects (use existing?.namespace ?? r.namespace) instead of always assigning
r.namespace, ensuring both subKey and objKey namespace resolution is consistent;
reference symbols: cappedRelations, r.namespace, subKey, objKey, entitySet,
existing and existingObj.

192-206: Consider memoizing nodeMap and connectedIds computations.

nodeMap (line 192) and connectedIds (lines 199-205) are recomputed on every render, including when only hoveredEdge changes. Since they depend on nodes/edges/selectedNode, consider wrapping them in useMemo for better performance on interaction-heavy renders.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@app/src/components/intelligence/MemoryGraphMap.tsx` around lines 192 - 206,
The nodeMap and connectedIds calculations are recomputed on every render; wrap
them (and centerNodeId which also derives from nodes) in React's useMemo to
avoid unnecessary work: compute nodeMap with useMemo(() => new
Map(nodes.map(...)), [nodes]), compute centerNodeId with useMemo(() =>
nodes.find(...)?.id ?? (nodes.length ? nodes[0].id : null), [nodes]), and
compute connectedIds with useMemo(() => selectedNode ? new
Set(edges.filter(...).flatMap(...)) : null, [edges, selectedNode]); update
references to nodeMap, centerNodeId, and connectedIds in MemoryGraphMap so the
rest of the component uses the memoized values.

177-182: Consider using memo values directly instead of syncing to state.

The useEffect synchronizes memo results to state, but nodes, edges, and namespacePalette don't change interactively—only selectedNode and hoveredEdge do. You could use initialNodes/initialEdges/palette directly from the memo, avoiding the extra render cycle caused by the state sync.

Based on learnings: "In React components, do not perform synchronous setState directly inside useEffect bodies."

♻️ Proposed simplification
-  const [nodes, setNodes] = useState<GraphNode[]>([]);
-  const [edges, setEdges] = useState<GraphEdge[]>([]);
   const [hoveredEdge, setHoveredEdge] = useState<number | null>(null);
   const [selectedNode, setSelectedNode] = useState<string | null>(null);
-  const [namespacePalette, setNamespacePalette] = useState<Map<string, string>>(new Map());

   // Build graph data from relations (synchronous, deterministic)
   const { initialNodes, initialEdges, palette } = useMemo(() => {
     // ... existing logic
   }, [relations]);

-  // Sync memo results into state (needed for interactive selection/hover)
-  useEffect(() => {
-    setNodes(initialNodes);
-    setEdges(initialEdges);
-    setNamespacePalette(palette);
-  }, [initialNodes, initialEdges, palette]);
+
+  // Use memo results directly
+  const nodes = initialNodes;
+  const edges = initialEdges;
+  const namespacePalette = palette;
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@app/src/components/intelligence/MemoryGraphMap.tsx` around lines 177 - 182,
The useEffect is needlessly syncing memoized values into state (setNodes,
setEdges, setNamespacePalette) causing an extra render; instead remove that
effect and use the memo outputs initialNodes, initialEdges and palette directly
where nodes, edges and namespacePalette are used (keeping state only for
interactive values like selectedNode and hoveredEdge). Update references in the
component to read from initialNodes/initialEdges/palette (or rename the memo
outputs to nodes/edges/palette) and delete the useEffect and the corresponding
state setters so only interactive state remains.
app/src/components/intelligence/MemoryWorkspace.tsx (1)

155-198: Graph relations loaded sequentially instead of in parallel.

The memoryGraphQuery() call at lines 167-175 runs after Promise.all completes. Consider including it in the Promise.all for parallel loading to improve initial load performance:

♻️ Proposed parallel loading
     try {
-      const [documentsPayload, namespacesPayload, memoryDirFiles] = await Promise.all([
+      const [documentsPayload, namespacesPayload, memoryDirFiles, relationsResult] = await Promise.all([
         memoryListDocuments(),
         memoryListNamespaces(),
         aiListMemoryFiles('memory'),
+        memoryGraphQuery().catch(() => [] as GraphRelation[]),
       ]);

-      setGraphRelationsLoading(true);
-      try {
-        const relations = await memoryGraphQuery();
-        setGraphRelations(relations);
-      } catch {
-        setGraphRelations([]);
-      } finally {
-        setGraphRelationsLoading(false);
-      }
+      setGraphRelations(relationsResult);

Note: This removes the separate graphRelationsLoading state. If you need distinct loading states, keep the current approach but move the loading state update before Promise.all.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@app/src/components/intelligence/MemoryWorkspace.tsx` around lines 155 - 198,
The graph query is being awaited after Promise.all, causing sequential loads;
update loadWorkspace to include memoryGraphQuery in the initial Promise.all
(alongside memoryListDocuments, memoryListNamespaces, aiListMemoryFiles) so
documents, namespaces, files and relations load in parallel, then call
setGraphRelations with the returned relations; remove or adapt the separate
try/catch around memoryGraphQuery and ensure graphRelationsLoading is handled
(either removed or set before Promise.all) and errors for the graph result are
handled the same way as other payloads in the unified response.
app/src/components/intelligence/MemoryHeatmap.tsx (1)

227-236: Tooltip may overflow viewport edges.

The tooltip is positioned at left: hoveredCell.x with translateX(-50%), which could cause it to overflow the viewport when hovering cells near the left or right edges. Consider adding viewport boundary checks or using a tooltip library.

app/src/components/intelligence/MemoryInsights.tsx (1)

77-87: Fuzzy matching logic may produce false positives.

The bidirectional check normalized.includes(key) || key.includes(normalized) can misclassify predicates. For example, a predicate like "dislike" would match the key "is" (since "dislike".includes("is") is true), incorrectly categorizing it as facts instead of preferences.

Consider removing the key.includes(normalized) part or using word-boundary matching:

♻️ Proposed fix
 function categorize(predicate: string): InsightCategory {
   const normalized = predicate.toLowerCase().replace(/[_-]/g, ' ').trim();
   if (PREDICATE_CATEGORIES[normalized]) return PREDICATE_CATEGORIES[normalized];

   // Fuzzy match: check if predicate contains known keywords
   for (const [key, category] of Object.entries(PREDICATE_CATEGORIES)) {
-    if (normalized.includes(key) || key.includes(normalized)) return category;
+    // Only match if the key appears as a complete word/phrase in the predicate
+    const keyPattern = new RegExp(`\\b${key}\\b`);
+    if (keyPattern.test(normalized)) return category;
   }

   return 'other';
 }
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@app/src/components/intelligence/MemoryInsights.tsx` around lines 77 - 87, The
fuzzy matching in categorize(predicate) is producing false positives because it
checks both normalized.includes(key) and key.includes(normalized); remove the
bidirectional check and implement a safer match: keep only the
predicate-containing-key check but require whole-word matching (use a
word-boundary match or escaped regex) against each key from
PREDICATE_CATEGORIES, so "dislike" won't match "is"; update the loop in
categorize and, if needed, add/use an escapeRegExp helper to safely build the
word-boundary test for keys.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@app/src/components/intelligence/MemoryHeatmap.tsx`:
- Around line 51-58: The inline comment in MemoryHeatmap.tsx inside the useMemo
block incorrectly says "6 months ago" while the MONTHS constant equals 8; update
that comment to accurately describe the window (e.g., "8 months ago through
today" or "MONTHS months ago through today") so it matches the MONTHS constant
used when computing rangeStart in useMemo.

---

Nitpick comments:
In `@app/src/components/intelligence/MemoryGraphMap.tsx`:
- Around line 96-150: The force simulation runSimulation is expensive and runs
synchronously (called from useMemo) which can cause UI jank; wrap the call to
runSimulation in a performance measurement: record start = performance.now(),
call runSimulation(rawNodes, rawEdges), then console.debug('[MemoryGraphMap]
simulation completed', { nodes: rawNodes.length, edges: rawEdges.length,
durationMs: performance.now() - start }); also emit a namespaced console.warn
when rawNodes.length exceeds a threshold (e.g., 50) to aid debugging and
monitoring; place these changes where useMemo invokes runSimulation inside
MemoryGraphMap so the log context and counts are accurate.
- Around line 55-67: The subject namespace is being overwritten on every
iteration while the object preserves an existing namespace; update the subject
handling in the loop over cappedRelations so entitySet.set(subKey, ...) uses the
same preservation logic as objects (use existing?.namespace ?? r.namespace)
instead of always assigning r.namespace, ensuring both subKey and objKey
namespace resolution is consistent; reference symbols: cappedRelations,
r.namespace, subKey, objKey, entitySet, existing and existingObj.
- Around line 192-206: The nodeMap and connectedIds calculations are recomputed
on every render; wrap them (and centerNodeId which also derives from nodes) in
React's useMemo to avoid unnecessary work: compute nodeMap with useMemo(() =>
new Map(nodes.map(...)), [nodes]), compute centerNodeId with useMemo(() =>
nodes.find(...)?.id ?? (nodes.length ? nodes[0].id : null), [nodes]), and
compute connectedIds with useMemo(() => selectedNode ? new
Set(edges.filter(...).flatMap(...)) : null, [edges, selectedNode]); update
references to nodeMap, centerNodeId, and connectedIds in MemoryGraphMap so the
rest of the component uses the memoized values.
- Around line 177-182: The useEffect is needlessly syncing memoized values into
state (setNodes, setEdges, setNamespacePalette) causing an extra render; instead
remove that effect and use the memo outputs initialNodes, initialEdges and
palette directly where nodes, edges and namespacePalette are used (keeping state
only for interactive values like selectedNode and hoveredEdge). Update
references in the component to read from initialNodes/initialEdges/palette (or
rename the memo outputs to nodes/edges/palette) and delete the useEffect and the
corresponding state setters so only interactive state remains.

In `@app/src/components/intelligence/MemoryInsights.tsx`:
- Around line 77-87: The fuzzy matching in categorize(predicate) is producing
false positives because it checks both normalized.includes(key) and
key.includes(normalized); remove the bidirectional check and implement a safer
match: keep only the predicate-containing-key check but require whole-word
matching (use a word-boundary match or escaped regex) against each key from
PREDICATE_CATEGORIES, so "dislike" won't match "is"; update the loop in
categorize and, if needed, add/use an escapeRegExp helper to safely build the
word-boundary test for keys.

In `@app/src/components/intelligence/MemoryWorkspace.tsx`:
- Around line 155-198: The graph query is being awaited after Promise.all,
causing sequential loads; update loadWorkspace to include memoryGraphQuery in
the initial Promise.all (alongside memoryListDocuments, memoryListNamespaces,
aiListMemoryFiles) so documents, namespaces, files and relations load in
parallel, then call setGraphRelations with the returned relations; remove or
adapt the separate try/catch around memoryGraphQuery and ensure
graphRelationsLoading is handled (either removed or set before Promise.all) and
errors for the graph result are handled the same way as other payloads in the
unified response.
🪄 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: defaults

Review profile: CHILL

Plan: Pro

Run ID: b32b2415-7665-4fa3-9033-59088430f198

📥 Commits

Reviewing files that changed from the base of the PR and between 0dd4d1f and 0b5b634.

📒 Files selected for processing (5)
  • app/src/components/intelligence/MemoryGraphMap.tsx
  • app/src/components/intelligence/MemoryHeatmap.tsx
  • app/src/components/intelligence/MemoryInsights.tsx
  • app/src/components/intelligence/MemoryStatsBar.tsx
  • app/src/components/intelligence/MemoryWorkspace.tsx

Comment on lines +51 to +58
const { grid, monthLabels, totalEvents, maxDailyCount, totalWeeks } = useMemo(() => {
// The window: 6 months ago through today
const today = new Date();
today.setHours(0, 0, 0, 0);

const rangeStart = new Date(today);
rangeStart.setMonth(rangeStart.getMonth() - MONTHS);
rangeStart.setDate(1); // start of that month
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

Stale comment: references "6 months" but MONTHS constant is 8.

The comment at line 52 says "6 months ago" but the MONTHS constant at line 9 is set to 8. Update the comment to match the actual behavior.

📝 Fix comment
-    // The window: 6 months ago through today
+    // The window: 8 months ago through today
📝 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
const { grid, monthLabels, totalEvents, maxDailyCount, totalWeeks } = useMemo(() => {
// The window: 6 months ago through today
const today = new Date();
today.setHours(0, 0, 0, 0);
const rangeStart = new Date(today);
rangeStart.setMonth(rangeStart.getMonth() - MONTHS);
rangeStart.setDate(1); // start of that month
const { grid, monthLabels, totalEvents, maxDailyCount, totalWeeks } = useMemo(() => {
// The window: 8 months ago through today
const today = new Date();
today.setHours(0, 0, 0, 0);
const rangeStart = new Date(today);
rangeStart.setMonth(rangeStart.getMonth() - MONTHS);
rangeStart.setDate(1); // start of that month
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@app/src/components/intelligence/MemoryHeatmap.tsx` around lines 51 - 58, The
inline comment in MemoryHeatmap.tsx inside the useMemo block incorrectly says "6
months ago" while the MONTHS constant equals 8; update that comment to
accurately describe the window (e.g., "8 months ago through today" or "MONTHS
months ago through today") so it matches the MONTHS constant used when computing
rangeStart in useMemo.

Align test assertions with the new sub-component structure
(MemoryStatsBar, MemoryGraphMap, MemoryInsights, MemoryHeatmap).

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
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/__tests__/MemoryWorkspace.test.tsx (1)

96-101: Strengthen the Relations stat test to validate the rendered value, not just the label.

Label-only assertion can pass even when the actual relations count regresses. Consider asserting the displayed count derived from mocked graph data as part of this scenario.

As per coding guidelines "Prefer testing behavior over implementation details in Vitest unit tests."

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@app/src/components/intelligence/__tests__/MemoryWorkspace.test.tsx` around
lines 96 - 101, The test 'shows Relations stat in the stats bar' currently only
asserts the "Relations" label; update it to also assert the rendered relations
count derived from the mocked graph data so regressions in the displayed value
are caught. In the MemoryWorkspace test, after
renderWithProviders(<MemoryWorkspace onToast={onToast} />) and waiting for the
label, query for the element that shows the numeric value (e.g., via
screen.getByText or a role/aria label used by the stats UI) and assert it equals
the expected count from your mock graph fixture; reference the MemoryWorkspace
component and the existing onToast/renderWithProviders helpers to locate the
test and the mock data source. Ensure the assertion waits (e.g., inside waitFor)
if the count is rendered asynchronously.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@app/src/components/intelligence/__tests__/MemoryWorkspace.test.tsx`:
- Around line 65-67: Tests in MemoryWorkspace.test.tsx assert text values that
no longer match the current output of the MemoryWorkspace component; update the
assertions to match the component's actual rendered strings. Open the
MemoryWorkspace.test.tsx file and revise the getByText/getByRole expectations
used in the tests referencing MemoryWorkspace (e.g., the 'renders the Memory
heading' test and the other failing blocks) so they match the exact text
produced by MemoryWorkspace (use the component's actual heading and button/label
strings from MemoryWorkspace.tsx), or switch to text-insensitive queries (e.g.,
getByRole with accessible name) if the text can change. Ensure you update all
occurrences indicated by the reviewer (the tests around the heading and the
other failing assertions) so they reflect the component's current render output.

---

Nitpick comments:
In `@app/src/components/intelligence/__tests__/MemoryWorkspace.test.tsx`:
- Around line 96-101: The test 'shows Relations stat in the stats bar' currently
only asserts the "Relations" label; update it to also assert the rendered
relations count derived from the mocked graph data so regressions in the
displayed value are caught. In the MemoryWorkspace test, after
renderWithProviders(<MemoryWorkspace onToast={onToast} />) and waiting for the
label, query for the element that shows the numeric value (e.g., via
screen.getByText or a role/aria label used by the stats UI) and assert it equals
the expected count from your mock graph fixture; reference the MemoryWorkspace
component and the existing onToast/renderWithProviders helpers to locate the
test and the mock data source. Ensure the assertion waits (e.g., inside waitFor)
if the count is rendered asynchronously.
🪄 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: defaults

Review profile: CHILL

Plan: Pro

Run ID: 423859f5-c488-4fa2-8e8c-a281682bcea3

📥 Commits

Reviewing files that changed from the base of the PR and between 0b5b634 and 2a2f29b.

📒 Files selected for processing (1)
  • app/src/components/intelligence/__tests__/MemoryWorkspace.test.tsx

Comment on lines +65 to +67
it('renders the Memory heading', async () => {
renderWithProviders(<MemoryWorkspace onToast={onToast} />);
expect(screen.getByText('Memory Workspace')).toBeInTheDocument();
expect(screen.getByText('Memory')).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 | 🟠 Major

Align updated text assertions with the current MemoryWorkspace render strings.

These expectations no longer match the component output in app/src/components/intelligence/MemoryWorkspace.tsx, so this suite will fail despite valid behavior.

Suggested fix
-  it('renders the Memory heading', async () => {
+  it('renders the Memory Workspace heading', async () => {
     renderWithProviders(<MemoryWorkspace onToast={onToast} />);
-    expect(screen.getByText('Memory')).toBeInTheDocument();
+    expect(screen.getByText('Memory Workspace')).toBeInTheDocument();
   });

-  it('renders the Memory Graph section', async () => {
+  it('renders the Sample Memory Graph section', async () => {
     renderWithProviders(<MemoryWorkspace onToast={onToast} />);

     await waitFor(() => {
-      expect(screen.getByText('Memory Graph')).toBeInTheDocument();
+      expect(screen.getByText('Sample Memory Graph')).toBeInTheDocument();
     });
   });

   it('shows empty-state message when no relations exist', async () => {
@@
     renderWithProviders(<MemoryWorkspace onToast={onToast} />);

     await waitFor(() => {
-      expect(screen.getByText('No memory graph data yet')).toBeInTheDocument();
+      expect(
+        screen.getByText('No relations yet. Ingest documents to populate the graph.')
+      ).toBeInTheDocument();
     });
   });

Also applies to: 105-110, 125-126

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@app/src/components/intelligence/__tests__/MemoryWorkspace.test.tsx` around
lines 65 - 67, Tests in MemoryWorkspace.test.tsx assert text values that no
longer match the current output of the MemoryWorkspace component; update the
assertions to match the component's actual rendered strings. Open the
MemoryWorkspace.test.tsx file and revise the getByText/getByRole expectations
used in the tests referencing MemoryWorkspace (e.g., the 'renders the Memory
heading' test and the other failing blocks) so they match the exact text
produced by MemoryWorkspace (use the component's actual heading and button/label
strings from MemoryWorkspace.tsx), or switch to text-insensitive queries (e.g.,
getByRole with accessible name) if the text can change. Ensure you update all
occurrences indicated by the reviewer (the tests around the heading and the
other failing assertions) so they reflect the component's current render output.

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