Improve memory graph playground readability#973
Conversation
|
Claude finished @Dhravya's task in 2m 12s —— View job Review Complete
Summary: Reviewed 1,694 additions across 19 files. No bugs, security issues, or logic errors found. The PR cleanly implements container tag filtering, cluster coloring, level-of-detail edge rendering, and dynamic zoom bounds. Code is well-structured with good test coverage. Score: 10/10 — Ready to ship. |
Deploying with
|
| Status | Name | Latest Commit | Updated (UTC) |
|---|---|---|---|
| ✅ Deployment successful! View logs |
supermemory-mcp | aefeec2 | May 19 2026, 05:57 PM |
There was a problem hiding this comment.
Overview: This PR improves memory graph readability with container tag filtering, cluster-colored nodes, dynamic zoom bounds, and level-of-detail edge rendering for dense graphs.
Issues found: None — this looks good to ship.
The code is well-structured with solid test coverage. Key observations:
-
Container tags proxy (
/api/container-tags/route.ts): Clean API proxy pattern appropriate for a playground app. Error handling is thorough. -
Simulation changes (
simulation.ts): The newstop()method and dynamicgetDocMemoryDistance()based on memory count are correctly implemented. The append-only pagination logic inmemory-graph.tsxproperly preserves existing node positions. -
Cluster assignments (
use-graph-data.ts): The BFS-based clustering algorithm correctly merges cross-document relation clusters and assigns consistent colors via deterministic hashing. -
Level-of-detail rendering (
renderer.ts): Smart edge sampling at low zoom levels usinggetRelationEdgeStride()andshouldDrawRelationEdge(). Structural "derives" edges are always drawn, while relation edges are deterministically sampled to reduce visual noise. -
Version chain inference (
version-chain.ts): Good fix for backends that repeat v1 across update chains — the code now infers display versions from chain order when needed. -
Dynamic zoom bounds (
viewport.ts):setMinZoomForNodes()properly allows zooming out further for large graphs while clamping to reasonable limits.
Score: 10/10
Deploying with
|
| Status | Name | Latest Commit | Preview URL | Updated (UTC) |
|---|---|---|---|---|
| ✅ Deployment successful! View logs |
supermemory-app | aefeec2 | Commit Preview URL Branch Preview URL |
May 19 2026, 05:59 PM |
| @@ -142,10 +443,10 @@ export function useGraphData( | |||
| for (const [id] of nodeCache.current.entries()) { | |||
| if (!currentIds.has(id)) nodeCache.current.delete(id) | |||
There was a problem hiding this comment.
Bug: nodeCache.current is mutated inside useMemo.
useMemo is supposed to be side-effect-free. Mutating nodeCache.current (.clear(), .delete(), .set()) here violates that contract — React is allowed to re-run useMemo callbacks multiple times in StrictMode and Concurrent Mode without committing the result, leaving the cache in an inconsistent state.
The original split (useEffect for cache eviction, a separate useMemo for reads) was intentional. Move the eviction back into a useEffect and restrict the useMemo to reading the cache only.
| if (Math.abs(dy) > minDistance) continue | ||
| if (dx * dx + dy * dy < minDistance * minDistance) return false | ||
| } | ||
|
|
There was a problem hiding this comment.
Performance: isAppendCandidateOpen is O(n) per candidate, called up to 144 times per new node.
With 500 nodes this is ~72,000 distance checks per new document, all inside useMemo. At larger graph sizes this causes noticeable jank on every update.
Consider a bounding-box pre-filter before the exact distance check, or a grid/spatial-hash so the nearest-neighbour test is O(1) amortised.
| } | ||
| } | ||
|
|
||
| function hashString(value: string): number { |
There was a problem hiding this comment.
Duplication: hashString is defined identically in both renderer.ts and use-graph-data.ts.
Extract to a shared utility and import from both.
|
|
||
| const chain: ChainEntry[] = all.map((m) => ({ | ||
| const shouldInferVersions = all.some((m, index) => { | ||
| if (!Number.isFinite(m.version) || m.version < 1) return true |
There was a problem hiding this comment.
Aggressive version inference: shouldInferVersions flips to true if any adjacent pair is non-monotonic, which causes every entry in the chain to fall back to positional indices. A single stale or out-of-order record silently discards all real version numbers for the whole chain.
Consider falling back per-entry — assign index + 1 only to entries whose version is invalid or duplicates the previous — rather than replacing the entire chain.
Summary
/v3/container-tags/listmemoryEntries,type, relation fields)Verification
bun --filter @supermemory/memory-graph testbun run buildinpackages/memory-graphbun run buildinapps/memory-graph-playgroundgit diff --cached --check