feat(node-ui): PR6 — dashboard revamp + Context Graph terminology + bottom panel#583
feat(node-ui): PR6 — dashboard revamp + Context Graph terminology + bottom panel#583Jurij89 wants to merge 34 commits into
Conversation
Remove Gossip / Agent Runs / SPARQL tabs (keep Node Log + Transactions). Add a vertical drag-resize: layout store gains `bottomHeight` (clamp 120–600, default 200 = old fixed height, debounced persist to dkg-layout, clamp on load) mirroring leftWidth/rightWidth; App.tsx adds `useDragResizeV` (clientY twin of useDragResize) + a `.v10-resize-handle-v` above PanelBottom, hidden when collapsed; PanelBottom drives its height from the store. (Handle CSS lands with the dashboard styles commit.) Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
…phs list) Top row → My Context Graphs / Context Graph Size / Connected Agents (Knowledge Assets + Connected Peers stats dropped per plan). Context Graph Size shows TWO numbers (entities/KAs + triples), each with a WM/SWM/VM proportion bar using the shared --layer-* CSS tokens (not raw hex — fixes light theme) with a 1px track/separator so the light-theme WM segment stays legible (ui-lead). Removed Quick Actions + Recent Operations; kept Spending. "Projects" box → "My Context Graphs": filtered to the sidebar membership set, columns (name / Lock·Globe type icon / size / agents / curator·joined badge), 10-row internal scroll. One canonical "what is a Context Graph?" header affordance (not per-card tooltips — ux-lead); helper text always-visible in the sub slot; informational dim text uses --text-secondary (AA). Data: new shared `useHiddenContextGraphIds` (PanelLeft + MemoryStack refactored onto it — single source of truth so the dashboard count == sidebar count) and `useMyContextGraphs`. Per-CG `CgRow` is the single data probe (one useMemoryEntities + one listParticipants, reports up; parent dedups agents via canonicalAgentDid). `normalizeAccessPolicy` exported. Also carries the `.v10-resize-handle-v` CSS for the bottom panel. Per-CG SPARQL aggregation at PoC scale (MemoryStack pattern); bulk endpoint is a documented follow-up. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
…st updates User-visible copy only across the create/join/share modals, the composer picker placeholder + attach hints (PanelRight), and the context-graph overview back-button title. Internal identifiers, store keys, CSS classes, tab ids and filenames are intentionally unchanged. Update tests to the new copy and remove the ui-compat block that guarded the now-removed dashboard "Import Memories" Quick Action (import still launches from the left sidebar). Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
The PR6 dashboard revamp shipped two new shared hooks that back the sidebar↔dashboard membership-parity invariant but had no unit coverage (rubric: missing tests for high-risk user-facing behavior = blocker). Adds 11 tests: - useHiddenContextGraphIds: localStorage load, legacy-key back-compat, corrupt-payload tolerance, hide()/unhideAll() persistence, and the cross-instance custom-event sync that the parity guarantee depends on. - useMyContextGraphs: callerInvolved membership filter (identity- independent), hidden-id subtraction (the exact sidebar filter), case-insensitive curator-by-identity match, identityLoading lifecycle, and the hidden+non-member → empty-set edge. No source change (DashboardView reducer findings reported to team-lead for the in-flight sig rework). Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
… state, badge AA 🔴 Codex: the onReport memo key compared only entity/triple totals + agents.length, so a WM→SWM/VM promotion or an agent swap left the dashboard cards stale until remount. Replace with a full `sig` (per-layer counts + sorted agent ids + flags) used as both the report effect dep and the parent dedupe key. 🟡 Codex: CgRow coerced a failed/in-flight participant probe to `[]`, so the Agents column / Connected Agents card showed a silent 0. Propagate `agentsLoading`/`agentsError`; the aggregate excludes errored CGs from the unique-agent union and marks the count partial. #86 (ui-lead): curator role badge used `--accent-green` text on `--bg-elevated` — ~1.9:1 in light theme (accent-green is theme-invariant, bg-elevated isn't). Invert to a solid green chip with fixed near-black text — AA in both themes and rightly emphasises the consequential role. Also adds the Connected Agents partial-caveat parity (ux-lead NB-2). Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
…ale reports ui-lead: light `--layer-working` #a3a3a3 (~2.0:1 vs the white card) left the WM proportion-bar segment near-invisible. Not a hard WCAG blocker (the breakdown is redundantly available via the legend at --text-secondary 7.81:1 and the bar's title/aria-label), but nudged the light token to #8a8a8a (~3:1) so the segment has a visible edge. Dark unaffected. qa-lead: `reports` accumulated orphaned per-CG entries across hide/unhide. Added a guarded prune keyed on the membership set — memory hygiene (aggregate already iterates myCgs). Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
…rtial qa-lead round-2 🔵: the unified `loading`/`partial` flags made the Context Graph Size card flash "loading…" during an unrelated participant refetch (and vice-versa). Split the aggregate into `sizeLoading`/`agentsLoading` + `sizePartial`/`agentsPartial`; each card now reflects only its own data's state. No behavior change at rest; removes the cross-card transient. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
…ent copy 🔴 CgRow size cell gated on `mem.loading && agents===null`, so if /participants resolved before useMemoryEntities the row briefly showed a false "0 entities · 0 triples". Gate on `mem.loading` alone. 🟡 Bottom-panel height clamped to a static 600 only — a height persisted on a tall screen could squeeze the center pane out of view after reload on a shorter one. Add viewport-aware `maxBottomHeight()` (min center 240px) applied at drag time and at render. 🟡 `/participants` returns the access allow-list, not a live roster — relabel the Connected Agents helper + Agents column to "allow-listed with access" so the metric isn't over-claimed (it maps exactly to the user-spec'd "unique agent addresses across your context graphs"; 0 on fully-public graphs is correct for explicitly-granted access). Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
… teardown, viewport clamp sync 🔴 The /participants allow-list can omit the curator (and is empty on public graphs), so the Agents count / Connected Agents stat under- counted. Fold the CG's canonical curator into the per-row agent set (they inherently have access); null loading/error semantics preserved. 🟡 useMyContextGraphs fetched identity once on mount — if it failed at startup or the agent later changed it permanently diverged from the sidebar, breaking the parity invariant. Re-fetch on context-graph-list change (same cadence as PanelLeft's reload-with-identity). 🔴/🟡 useDragResizeV cleanup only removed the mousedown listener; an unmount mid-drag leaked document mousemove/mouseup + body cursor/ user-select. Cleanup now calls onMouseUp() for a full teardown. 🔴 The bottom-height viewport clamp was render-only, leaving the store holding a stale large value so the first shrink-drag felt stuck and window resize didn't reclamp. Sync the clamp into the store on mount and on window resize so render + drag math agree. 🟡 Per-row useMemoryEntities SPARQL cost: unchanged — the explicit, plan/PR-documented PoC-scale decision (see PR thread). Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
…rk, Wallets&Spending) User round-1 feedback on the dashboard: - Remove the stray header "What is a Context Graph?" affordance; merge a concise CG definition into the My Context Graphs card under its sub (.v10-cg-defn, --text-secondary AA). Drop unused HelpCircle import. - Context Graph Size: drop the redundant combined top number; the two metrics ARE the headline now — big number (.v10-cg-size-big 24/700) + small unit label, each over its WM/SWM/VM bar; shared legend; tighter card. Copy clarifies totals are "across all your context graphs". - WM/SWM/VM legend + bar segments get concise per-layer hover descriptions (README + MemoryStackView desc). - Connected Agents sub → "Unique agents allow-listed and collaborating across your context graphs." - Spending → "Wallets and Spending": node wallets + TRAC/ETH balances (existing /api/wallets/balances, now wired through api-wrapper + mock) with loading/error/addresses-only states; a 3-row spending overview (Last 24h / 7d / 30d, publishes·TRAC) from the existing economics periods. No backend change. - My Context Graphs list: header cells now align to their column content (Type/Role centered, Agents right); role badge centered. - Widen dashboard max-width 1200 → 1600 so wide screens aren't a big empty gutter. tsc clean; full node-ui suite green (the 2 parallel-flake files pass 88/88 in isolation, as before). Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
…ements - CG definition: card footer with hairline divider, 11px (was inline 10px) - Size card: 26px numbers, 14/6 spacing, scoped tighter padding - Width cap 1600 → 1440; grid-2 → minmax(0,2.2fr) minmax(320px,1fr) - CG list: cols 40/52/76px, Role badge left-anchored (was centered) - Wallets & Spending: per-wallet TRAC+ETH, grouped formatting, 3-col spending mini-table with header - Section/stat-card lucide icons; gated 160ms fadeSlideIn mount Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
- Resolved-but-empty / error+no-wallets no longer fall through to a perpetual "Loading wallets…"; distinct loading vs "No node wallets found." vs error states - Spending mini-table TRAC column header is literal "TRAC" (economics totalTrac is TRAC-denominated regardless of node wallet symbol) Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
- Wallets block rebuilt as one state machine on useFetch `loading`: loading → balances → addresses-only → error → "No node wallets found." (resolves 🔴 permanent "Loading wallets…") - 🟡 surface chain/RPC error as a stale caveat even when balances/ addresses are shown (mirrors agentsPartial); previously swallowed - 🔵 fmtTrac: empty/whitespace/nullish → "—" not misleading "0" (real 0.00 still renders 0) - Drop wb! non-null assertion in favour of (wb?.wallets ?? []) Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
- layout.maxBottomHeight: subtract fixed shell chrome (--header-h 44px) before clamping; bottom panel could grow ~44px too tall and push the center pane below CENTER_MIN_HEIGHT - DashboardView effectiveAgents: seed the locally-known curator even when listParticipants() fails, so a /participants outage no longer undercounts/zeros a CG (loading still null to preserve loading state) - DashboardView wallets: capture useFetch `error` (hard fetch rejection) — a rejected /api/wallets/balances now shows "Wallet balances unavailable." instead of false "No node wallets found." Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
- useDragResizeV: bind via state-tracked callback ref so the bottom resize handle works after expanding (panel defaults collapsed, so the one-shot useEffect([]) bound to a null ref and never re-ran) - useMemoryEntities/queryLayer: propagate fetch failures instead of coercing to []; in mock/offline mode every CG was shown as a real 0/0 instead of lighting the existing size-unavailable/partial state - wallets stale caveat: also trigger on useFetch `wbError` (a later poll rejecting keeps stale `wb` but only set wbError) Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
- App.tsx: remove stray `return handleRef;` / `}` orphaned by the round-2 useDragResizeV refactor (top-level return — broke the clean Vite/tsc build; incremental tsc had masked it) - DashboardView aggregate: union r.agents unconditionally. The row already reports only known DIDs (curator fallback on participant- probe failure, [] while loading), so skipping the row on agentsError cancelled the fallback and dropped the curator to 0; agentsPartial still flags the undercount Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
…parity - Rename "Connected Agents" card → "Collaborating Agents" (matches the allow-listed-and-collaborating sub-copy; drops the live-presence overclaim) — per product owner Codex round-6 (recurring mock/offline-parity root cause, fixed at source): - listParticipants now routes through api-wrapper with a mock (MOCK_PARTICIPANTS); mock CGs gain callerInvolved + curator. In mock/offline mode the dashboard now shows the mock context graphs and a real (deduped) agent count instead of 0/empty/partial - triples metric renders "—" (unknown) instead of a misleading exact 0 when the live /api/query failed and entities fell back to the cg.assetCount summary (no triple count exists in that summary) Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
- useMemoryEntities.fetchAll: Promise.allSettled per layer instead of
Promise.all. A single layer's timeout/500 no longer blanks WM/SWM/VM
for every consumer (ProjectView/MemoryStackView); partial results
are kept, and `error` is set only on total (all-three) failure —
which is the case the dashboard's assetCount fallback keys off
- Collaborating Agents sub copy: add a !hasCgs branch ("No context
graphs yet.") so a fresh empty node doesn't describe nonexistent
collaborators (mirrors the size card)
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
- useMemoryEntities: add a `partial` signal (some-but-not-all layers failed). error stays null in that case, but consumers can now tell counts are incomplete. New regression test for the one-layer-fails case (use-memory-entities-partial.test.ts) - DashboardView size fallback: use `cg.assetCount ?? cg.assets` (legacy-field compat, matching PanelLeft) so older daemon responses don't collapse a non-empty graph to 0 - DashboardView: report sizeError on mem.partial too (lights the "total is partial" caveat); per-row size cell shows the coarse summary count + "— triples" instead of a bare — when the live query failed, so rows aren't empty while the aggregate is populated Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
- maxBottomHeight: stop flooring the viewport-derived max back up to BOTTOM_HEIGHT_MIN. On short viewports (e.g. 360px) that forced the panel to 120 and squeezed the center pane below CENTER_MIN_HEIGHT; now returns the true available space (→ 0/collapsed if needed) so the center keeps its minimum. The 120 floor is storage-sanity only, enforced on load - fetchCurrentAgent now routes through api-wrapper (mock-aware) + MOCK_AGENT_IDENTITY whose agentDid matches the mock curators, so mock/offline mode keeps curator-aware behavior (CURATOR badge, identity-fallback membership) in sync with the real daemon path. Test mocks it at the api-wrapper layer accordingly Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
- useMemoryEntities: failed-vs-empty signalling is now opt-in (`signalErrors`, default false). queryLayer no longer throws by default, so ProjectView/MemoryStackView/AgentProfilePage keep their original empty-on-failure behavior in mock/offline mode. Only the dashboard opts in to get the unavailable/partial distinction it needs (Codex-sanctioned alternative) - Per-row participants now refresh on a 30s interval (matches the dashboard's other live data), so the agent count + aggregate don't go stale after join approvals/removals until a page reload - Per-row size cell: a `mem.partial` (some layers failed) state now renders "~N entities · ~N triples" + tooltip instead of silently presenting truncated counts as exact Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
- useMyContextGraphs now hydrates the CG store itself (fetch on mount + 60s + node-event refresh) instead of depending on PanelLeft's side effect. A reload with a persisted collapsed sidebar no longer shows 0 context graphs (PanelLeft is unmounted while collapsed) - useMyContextGraphs resets identity + identityLoading before each refetch and clears identity on failure, so after an agent/node switch membership can't be computed against a stale DID (falls back to callerInvolved instead) - Per-row participants subscribe to join_approved/join_rejected/ project_synced node events (filtered to this CG), so collaborator counts reflect membership changes immediately instead of up to 30s later; the 30s poll remains the backstop Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
- useMyContextGraphs: filter the node-event CG refresh to join_approved/join_rejected/project_synced (was firing on every SSE event incl. high-volume memory_graph_changed → continuous list+identity refetch with the dashboard open) - useMyContextGraphs: stop clearing identity before/on failed refetch (round-11 overcorrection). Keep the last good identity until a replacement fetch succeeds, so a transient /api/agent/identity blip no longer drops every graph for curator-DID-fallback daemons; a real agent switch still replaces it - PanelBottom: floor the expanded panel render height at the tab-strip height (--tab-h 36px) so the tabs + collapse control can't vanish on short viewports while bottomCollapsed is still false Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Gate the My Context Graphs count + list empty-state on identityLoading: older daemons (no callerInvolved) resolve membership only once /api/agent/identity returns, so an unresolved empty list now shows "loading…" / "Loading context graphs…" instead of a false "0 / No context graphs yet" flash on every load. Round-13 #2 (small-screen variant for the CG list) is intentionally deferred to a follow-up — a responsive redesign for a non-primary form factor is out of scope for this dashboard-revamp PR. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
…led refresh) listParticipants .catch now clears `agents` to null in addition to setting agentsError. Previously a failed *refresh* kept the last-good array, so effectiveAgents returned the stale full member list and the row/aggregate hid a real membership removal behind the "partial" caveat. null now routes through the error branch (curator-only fallback + parent marks total partial) instead of trusting stale data. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
- useMemoryEntities: queryLayer no longer throws; returns
{ triples, ok }. `partial` is now computed UNCONDITIONALLY for
every caller (was dead unless a caller opted in, so
MemoryStackView/ProjectView showed truncated-but-exact-looking
counts on a single-layer 500). Only the *hard error* escalation
on total failure stays configurable via signalErrors. Triple data
still degrades to [] on failure, so no consumer behavior regresses
- layout.setBottomHeight: lower clamp bound is now
min(BOTTOM_HEIGHT_MIN, maxBottomHeight()) instead of a hard 120.
On short viewports the static floor snapped every drag back to 120
while render clamped to the smaller viewport max — handle inert,
store wrong. Normal viewports keep the 120 floor
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
- Size card: in pure-fallback (live entity probe unavailable, value is the cg.assetCount summary) the entities metric is now explicitly labelled "Knowledge Assets (summary)" with a tooltip, and its layer bar is hidden — instead of silently presenting a published-KA count under the all-layer "entities" unit (Codex) - Collaborating Agents: public context graphs now report unknown (null → excluded from row + aggregate) instead of a confidently wrong [curator] count — for public graphs the /participants allow-list is not authoritative membership (Codex) Round-16 #C (identity reuse after rejected refresh) intentionally NOT changed: reviewer guidance has oscillated (r11 clear → r12 keep → r16 clear). r12's keep-last-identity optimizes the common case (transient blip must not empty the dashboard); the rare node-switch + identity-fail stale edge needs a backend node-version signal to solve without regressing the common case — tracked as a follow-up. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Round-16's row-level fixes left the aggregate cards silently exact. Comprehensive propagation of unknown/approx state into CgReport: - New CgReport.agentsUnknown (public graph = unmeasurable membership, distinct from agentsError). Aggregate now marks agentsPartial for public graphs, and the Collaborating Agents value renders "~N" when partial — instead of a confident exact count that silently excluded public graphs as 0 - New CgReport.sizeFallback (entities.total is the cg.assetCount summary substitute). If ANY row used it, the Size card no longer sums summary + live counts under a clean "entities" label: shows "~N" + "entities / KA · approx." + tooltip and hides the (now unreliable) WM/SWM/VM bars. Pure all-fallback keeps the stronger "Knowledge Assets (summary)" treatment from round-16 Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Make the per-row cells agree with the aggregate cards (the unit/approx honesty fixes were card-level only): - Size row fallback labels the value "KA (summary)" + tooltip instead of "entities" (matches the card's "Knowledge Assets (summary)" treatment) when the live entity probe is unavailable - Agents row shows "~N" + tooltip on the curator-only degraded fallback (agentsError) instead of a bare authoritative number, matching the card's "~N" partial treatment Third yellow (per-CG fan-out cost) is the known architectural scale item — deferred and tracked as the backend batched-aggregates follow-up, not a round-1 code change. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
- My Context Graphs: single merged description (drop footnote+divider); add curator/joined split bar + legend (RoleBar) - Better panel icons: Workflow (graph) / TrendingUp (size) / UsersRound (agents) - Size card: "Note: Entities become Knowledge Assets…" on its own line - CG list grid rebalanced: Name flexes widest, Size flexes (no hard min) so names stay readable on narrow widths; Agents stays numeric right-aligned with matching header (standard for numeric columns) - Glow/hover lift extended to the lower section panels - Subtitle gains chain name (client chainId→name map, no backend) - Wallets & Spending: chain name in subhead; balances as an aligned 3-col table (Wallet | TRAC | Gas(<token>)); spending mini-table grid fixed (fixed numeric columns so Publishes/TRAC sit under their own headers — was collapsing both right) - Spending column renamed "Publishes to VM"; db.getSpendingSummary now counts only TRAC-spending VM publishes so the count and TRAC are consistent (free SWM/local/testnet publishes excluded) + tooltip Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
- layout/PanelBottom: derive SHELL_CHROME_HEIGHT and TAB_STRIP_H from the CSS custom properties (--header-h, --tab-h) at runtime instead of duplicating the px numbers in JS. New `readPxVar` helper; a CSS tweak can no longer silently break the clamp - useMyContextGraphs: flip `identityLoading=true` at the start of every identity refetch (was never going back to true after the initial load). RoleBar accepts a `refreshing` prop and shows a subtle dim (`.is-refreshing` opacity 0.55, with prefers-reduced- motion guard) + aria-busy while the refetch is in flight, so a node/agent switch no longer asserts the old split with confidence. Identity itself is still NOT cleared (preserves round-12's transient- blip protection) Two yellows skipped with on-thread rationale: (1) PanelLeft loader dedup is an out-of-scope refactor with real regression risk — tracked; (4) per-CG fan-out cost is the 4th restatement, already tracked as backend follow-up #96. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
|
|
||
| const agentsMounted = useRef(true); | ||
| const loadParticipants = useCallback(() => { | ||
| api.listParticipants(cg.id) |
There was a problem hiding this comment.
🔴 Bug: loadParticipants() can race with itself here. The mount load, 30s poll, and SSE-triggered refreshes all call the same promise chain, so a slower older response can arrive last and overwrite a newer allow-list. That will make the dashboard's agent counts jump backwards after a join/remove. Guard this with a request sequence/AbortController and ignore stale responses before calling setAgents/setAgentsError.
| // the agent identity (curator-DID fallback) arrives. Until then an | ||
| // empty list is "not known yet", not a real zero — show a loading | ||
| // state rather than a false "0 / No context graphs yet" flash (Codex). | ||
| const cgsResolving = identityLoading && myCgs.length === 0; |
There was a problem hiding this comment.
🟡 Issue: cgsResolving only tracks identityLoading, but the context-graph list is fetched independently inside useMyContextGraphs. On a cold load, fetchCurrentAgent() can settle before fetchContextGraphs(), which makes the dashboard briefly render 0 / No context graphs yet even when graphs exist. Expose a real list-loading flag from the hook (or delay the empty state until the first CG fetch settles).
Summary
--layer-*tokens, light-theme-safe, 1px separator/track for the low-contrast light WM segment). Removed Quick Actions + Recent Operations; kept Spending. "Projects" box → My Context Graphs: filtered to the sidebar membership set, columns (name / Lock·Globe type icon / size / agents / curator·joined badge), up to 10 rows then internal scroll. One canonical "what is a Context Graph?" header affordance; always-visible helper text; AA-safe dim text..v10-resize-handle-vmirroring the horizontal handle, persistedbottomHeight(clamp 120–600, default 200) in the layout store.Peer-count investigation
Confirmed not a bug — two different concepts: header/old-dashboard "peers" = unique peers (
new Set(remotePeer)); Network tab "connected" = total libp2p connections (one peer can hold several). Per direction, no UI change — the dashboard peers stat is removed anyway and the header is left as-is; reported here for the record.Data strategy / assumptions
MemoryStackViewpattern: oneuseMemoryEntities+ onelistParticipantsper CG (the list rows are the single probe; top cards consume their aggregate). Accepted at PoC scale per plan.useHiddenContextGraphIdshook + the samebelongsInMyProjectsSidebarpredicate.Recommended follow-ups
Test plan
🤖 Generated with Claude Code