Skip to content

feat(node-ui): PR6 — dashboard revamp + Context Graph terminology + bottom panel#583

Open
Jurij89 wants to merge 34 commits into
mainfrom
feat/chat-ui-pr6
Open

feat(node-ui): PR6 — dashboard revamp + Context Graph terminology + bottom panel#583
Jurij89 wants to merge 34 commits into
mainfrom
feat/chat-ui-pr6

Conversation

@Jurij89
Copy link
Copy Markdown
Contributor

@Jurij89 Jurij89 commented May 18, 2026

Summary

  • Terminology: user-visible "Project/Projects" → "Context Graph/Context Graphs" across sidebar, create/join/share modals, composer picker, Memory Stack, context-graph overview. Internal identifiers / store keys / CSS classes / tab ids / filenames unchanged.
  • Dashboard revamp: top row → My Context Graphs / Context Graph Size / Connected Agents (Knowledge Assets + Connected Peers stats removed). Context Graph Size shows two numbers — entities/Knowledge Assets and triples — each with a WM/SWM/VM proportion bar (shared --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.
  • Bottom panel: removed Gossip / Agent Runs / SPARQL (kept Node Log + Transactions); vertically resizable via a .v10-resize-handle-v mirroring the horizontal handle, persisted bottomHeight (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

  • Context Graph Size + per-CG agents reuse the shipped MemoryStackView pattern: one useMemoryEntities + one listParticipants per CG (the list rows are the single probe; top cards consume their aggregate). Accepted at PoC scale per plan.
  • Dashboard "My Context Graphs" count is provably equal to the sidebar via a shared useHiddenContextGraphIds hook + the same belongsInMyProjectsSidebar predicate.

Recommended follow-ups

  • Bulk per-CG layer-counts daemon endpoint (replaces N×3 SPARQL when a user routinely has >~10 context graphs).
  • Transactions tab real content (currently the existing placeholder).
  • Empty project-picker recovery affordance (pre-existing, tracked separately).

Test plan

  • Dashboard: 3 panels; Size shows entities + triples with WM/SWM/VM bars (dark + light); loading/partial/empty/zero-agents states; My Context Graphs list matches sidebar, scrolls past 10.
  • Bottom panel: only Node Log + Transactions; drag the top edge to resize (min/max), persists across reload, hidden when collapsed, Cmd/Ctrl+J still toggles.
  • No user-visible "Project" in revamped surfaces; create/join/import still work from the sidebar.
  • Full node-ui suite green: 615 passed / 38 skipped / 0 failed.

🤖 Generated with Claude Code

Jurij Skornik and others added 3 commits May 18, 2026 21:09
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>
Comment thread packages/node-ui/src/ui/views/DashboardView.tsx Outdated
Comment thread packages/node-ui/src/ui/views/DashboardView.tsx Outdated
Jurij Skornik and others added 3 commits May 18, 2026 21:19
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>
Comment thread packages/node-ui/src/ui/views/DashboardView.tsx Outdated
Comment thread packages/node-ui/src/ui/views/DashboardView.tsx Outdated
Comment thread packages/node-ui/src/ui/views/DashboardView.tsx Outdated
Comment thread packages/node-ui/src/ui/stores/layout.ts
…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>
Comment thread packages/node-ui/src/ui/views/DashboardView.tsx Outdated
Comment thread packages/node-ui/src/ui/views/DashboardView.tsx Outdated
Comment thread packages/node-ui/src/ui/hooks/useMyContextGraphs.ts Outdated
Comment thread packages/node-ui/src/ui/App.tsx Outdated
…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>
Comment thread packages/node-ui/src/ui/components/Shell/PanelBottom.tsx Outdated
Comment thread packages/node-ui/src/ui/App.tsx Outdated
… 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>
Copy link
Copy Markdown

@github-actions github-actions Bot left a comment

Choose a reason for hiding this comment

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

Codex review completed — no issues found.

…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>
Copy link
Copy Markdown

@github-actions github-actions Bot left a comment

Choose a reason for hiding this comment

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

Codex review skipped: filtered diff is 29580 lines (cap: 5,000). Please consider splitting this into smaller PRs for reviewability.

…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>
Copy link
Copy Markdown

@github-actions github-actions Bot left a comment

Choose a reason for hiding this comment

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

Codex review skipped: filtered diff is 29683 lines (cap: 5,000). Please consider splitting this into smaller PRs for reviewability.

- 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>
Copy link
Copy Markdown

@github-actions github-actions Bot left a comment

Choose a reason for hiding this comment

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

Codex review skipped: filtered diff is 29687 lines (cap: 5,000). Please consider splitting this into smaller PRs for reviewability.

- 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>
Copy link
Copy Markdown

@github-actions github-actions Bot left a comment

Choose a reason for hiding this comment

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

Codex review skipped: filtered diff is 29694 lines (cap: 5,000). Please consider splitting this into smaller PRs for reviewability.

Comment thread packages/node-ui/src/ui/stores/layout.ts Outdated
Comment thread packages/node-ui/src/ui/views/DashboardView.tsx Outdated
Comment thread packages/node-ui/src/ui/views/DashboardView.tsx Outdated
- 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>
Comment thread packages/node-ui/src/ui/App.tsx
Comment thread packages/node-ui/src/ui/views/DashboardView.tsx Outdated
Comment thread packages/node-ui/src/ui/views/DashboardView.tsx Outdated
- 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>
Comment thread packages/node-ui/src/ui/App.tsx Outdated
Comment thread packages/node-ui/src/ui/views/DashboardView.tsx Outdated
- 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>
Comment thread packages/node-ui/src/ui/views/DashboardView.tsx Outdated
Comment thread packages/node-ui/src/ui/views/DashboardView.tsx Outdated
…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>
Comment thread packages/node-ui/src/ui/hooks/useMemoryEntities.ts Outdated
Comment thread packages/node-ui/src/ui/views/DashboardView.tsx Outdated
- 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>
Comment thread packages/node-ui/src/ui/hooks/useMemoryEntities.ts Outdated
Comment thread packages/node-ui/src/ui/views/DashboardView.tsx Outdated
Comment thread packages/node-ui/src/ui/views/DashboardView.tsx Outdated
- 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>
Comment thread packages/node-ui/src/ui/stores/layout.ts Outdated
Comment thread packages/node-ui/src/ui/hooks/useMyContextGraphs.ts Outdated
- 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>
Comment thread packages/node-ui/src/ui/hooks/useMemoryEntities.ts Outdated
Comment thread packages/node-ui/src/ui/views/DashboardView.tsx
Comment thread packages/node-ui/src/ui/views/DashboardView.tsx
- 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>
Comment thread packages/node-ui/src/ui/views/DashboardView.tsx Outdated
Comment thread packages/node-ui/src/ui/views/DashboardView.tsx Outdated
Comment thread packages/node-ui/src/ui/hooks/useMyContextGraphs.ts
- 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>
Comment thread packages/node-ui/src/ui/hooks/useMyContextGraphs.ts Outdated
Comment thread packages/node-ui/src/ui/hooks/useMyContextGraphs.ts Outdated
Comment thread packages/node-ui/src/ui/components/Shell/PanelBottom.tsx Outdated
- 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>
Comment thread packages/node-ui/src/ui/views/DashboardView.tsx Outdated
Comment thread packages/node-ui/src/ui/styles.css Outdated
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>
Comment thread packages/node-ui/src/ui/views/DashboardView.tsx
Comment thread packages/node-ui/src/ui/views/DashboardView.tsx Outdated
…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>
Comment thread packages/node-ui/src/ui/hooks/useMemoryEntities.ts
Comment thread packages/node-ui/src/ui/stores/layout.ts Outdated
- 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>
Comment thread packages/node-ui/src/ui/views/DashboardView.tsx
Comment thread packages/node-ui/src/ui/views/DashboardView.tsx
Comment thread packages/node-ui/src/ui/hooks/useMyContextGraphs.ts
- 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>
Comment thread packages/node-ui/src/ui/views/DashboardView.tsx
Comment thread packages/node-ui/src/ui/views/DashboardView.tsx
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>
Comment thread packages/node-ui/src/ui/views/DashboardView.tsx
Comment thread packages/node-ui/src/ui/views/DashboardView.tsx Outdated
Comment thread packages/node-ui/src/ui/views/DashboardView.tsx Outdated
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>
Comment thread packages/node-ui/src/ui/hooks/useMyContextGraphs.ts
Comment thread packages/node-ui/src/ui/stores/layout.ts Outdated
- 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>
Comment thread packages/node-ui/src/ui/hooks/useMyContextGraphs.ts
Comment thread packages/node-ui/src/ui/views/DashboardView.tsx
- 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)
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

🔴 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;
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

🟡 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).

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