fix(dashboard): graph renders edges + harness turns attribute correctly#90
Conversation
… the right harness
Two dashboard-truthfulness bugs.
ITEM 1 — graph showed 16068 nodes but 0 edges. The dashboard's parseSnapshot
read `rec.edges`, but the codebase snapshot is NetworkX node-link JSON whose
edges live under `links` (source/target) — so edges were always empty while
nodes rendered. Replaced the loose reader with a TYPED snapshotToGraphView mapper
over the Snapshot contract (links → edges{from,to,kind}), so the field-name bug
can't silently recur. Also resolved the latent GET /api/graph double-registration
(a counts-only codebase handler vs the dashboard full-view handler) that flapped
built:false: GET /api/graph is now a single handler reading the freshest LOCAL
snapshot — the same file POST /api/graph/build writes — so the "Build graph"
button's re-read shows edges immediately with no DeepLake eventual-consistency
wait. Dead fetchGraphView/parseSnapshot removed. Live: GET /api/graph 0 → 3550 edges.
ITEM 2 — every harness showed 0 turns captured. Captured sessions were written
with agent="" because no shim stamped the harness identity, so harness-api's
COUNT(*) GROUP BY agent matched none of the canonical names. All six shims now
stamp meta.agent with their canonical token (claude-code/codex/cursor/hermes/pi/
openclaw) at the shared createShim.normalize seam. Also fixed a latent OpenClaw
defect: deriveMeta was clobbering `agent` (harness provenance) with the per-user
name — it now sets only agent_id, keeping the openclaw/alice split correct.
Existing agent="" rows are not backfilled (no destructive migration); new captures
attribute correctly. eventCount:0 in fetchSessionsView is a separate deferred read
change (it does not feed the Harnesses page).
Security: PASS, zero remediations (no path traversal — graph dir keys on daemon-
local git identity, not request headers; scope/RBAC/local-gate preserved; inert-
text render; agent token hardcoded, not forgeable; provenance/per-user split
correct). Quality: PASS — both fixes real + test-locked.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
📝 WalkthroughWalkthroughTwo dashboard-truthfulness fixes: (1) ChangesGraph Edge Routing Fix
Harness Attribution Stamping Fix
QA and Security Audit Reports
Estimated code review effort🎯 3 (Moderate) | ⏱️ ~25 minutes Possibly related PRs
Poem
🚥 Pre-merge checks | ✅ 5✅ Passed checks (5 passed)
✏️ Tip: You can configure your own custom pre-merge checks in the settings. ✨ Finishing Touches📝 Generate docstrings
🧪 Generate unit tests (beta)
Comment |
There was a problem hiding this comment.
🧹 Nitpick comments (1)
tests/daemon/runtime/capture/capture-handler.test.ts (1)
291-297: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick winAssert
agent/agent_idpersistence with column-aware checks, not raw substring presence.These
toContain(...)checks can be satisfied by the serializedmessageJSON alone, so they may pass even if thesessions.agentorsessions.agent_idmapping regresses. Please assert against the actual INSERT column-value mapping (column-position-aware parsing of the INSERT statement) to avoid false positives.Also applies to: 310-311
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@tests/daemon/runtime/capture/capture-handler.test.ts` around lines 291 - 297, The current assertions using toContain("claude-code") and toContain("alice") are checking for substring presence anywhere in the SQL statement, which is insufficient because these values could appear in the serialized message JSON or other parts of the INSERT statement rather than in the actual agent and agent_id columns. Parse the INSERT statement in a column-aware manner to extract the actual column-value mappings for the sessions table, then verify that "claude-code" is specifically mapped to the agent column and "alice" is specifically mapped to the agent_id column, rather than just checking for raw substring presence.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Nitpick comments:
In `@tests/daemon/runtime/capture/capture-handler.test.ts`:
- Around line 291-297: The current assertions using toContain("claude-code") and
toContain("alice") are checking for substring presence anywhere in the SQL
statement, which is insufficient because these values could appear in the
serialized message JSON or other parts of the INSERT statement rather than in
the actual agent and agent_id columns. Parse the INSERT statement in a
column-aware manner to extract the actual column-value mappings for the sessions
table, then verify that "claude-code" is specifically mapped to the agent column
and "alice" is specifically mapped to the agent_id column, rather than just
checking for raw substring presence.
ℹ️ Review info
⚙️ Run configuration
Configuration used: Organization UI
Review profile: CHILL
Plan: Pro Plus
Run ID: b97192d1-7d03-484f-b160-577302e1ede5
📒 Files selected for processing (15)
library/qa/dashboard/2026-06-23-graph-edges-harness-turns-qa.mdlibrary/qa/dashboard/2026-06-23-graph-edges-harness-turns-security.mdsrc/daemon/runtime/assemble.tssrc/daemon/runtime/codebase/api.tssrc/daemon/runtime/dashboard/CONVENTIONS.mdsrc/daemon/runtime/dashboard/api.tssrc/hooks/index.tssrc/hooks/normalize.tssrc/hooks/openclaw/shim.tstests/daemon/runtime/capture/capture-handler.test.tstests/daemon/runtime/codebase/api.test.tstests/daemon/runtime/dashboard/api.test.tstests/daemon/runtime/dashboard/harness-api.test.tstests/hooks/harness-identity-stamp.test.tstests/hooks/openclaw/shim.test.ts
Two dashboard-truthfulness bugs, fixed via the Bee Army (typescript-node + harness-integration, security→quality close-out). Both verified.
Item 1 — graph showed "16068 nodes, 0 edges"
The dashboard's
parseSnapshotreadrec.edges, but the codebase snapshot is NetworkX node-link JSON whose edges live underlinks(source/target) — so the edge array was always empty while nodes rendered fine.snapshotToGraphViewmapper over theSnapshotcontract (links→edges{from,to,kind}), so the field-name bug can't silently recur (tsc checks it).GET /api/graphdouble-registration (a counts-only codebase handler vs the dashboard full-view handler) that flappedbuilt:false.GET /api/graphis now a single handler reading the freshest local snapshot — the same filePOST /api/graph/buildwrites — so the just-shipped "Build graph" button's re-read shows edges immediately (no DeepLake eventual-consistency wait). DeadfetchGraphView/parseSnapshotremoved.GET /api/graphwent 0 → 3,550 edges after a build (e.g.Badge.jsx → external:react (imports)).Item 2 — every harness showed "0 turns captured"
Captured sessions were written with
agent=""(no shim stamped the harness identity), soharness-api'sCOUNT(*) GROUP BY agentmatched none of the canonical names.meta.agentwith their canonical token (claude-code/codex/cursor/hermes/pi/openclaw) at the sharedcreateShim.normalizeseam.deriveMetawas clobberingagent(harness provenance) with the per-user name — it now sets onlyagent_id, keeping theopenclaw/alicesplit correct.agent=""rows are not backfilled (no destructive migration); new captures attribute correctly.eventCount:0infetchSessionsViewis a separate deferred read change (it does not feed the Harnesses page).Close-out
Security — PASS, zero remediations: no path traversal (graph dir keys on daemon-local git identity, never request headers), scope/RBAC/local-gate preserved, inert-text render (no
dangerouslySetInnerHTML), theagenttoken is hardcoded (not forgeable / no injection), provenance-vs-per-user split correct. One non-blocking Low (the dir sanitizer permits./..butrepois daemon-local → not reachable; flagged as a follow-up).Quality — PASS: both fixes real, complete, and locked by behavior-asserting tests (typed mapper links→edges; single-handler regression both ways; six-harness stamp parameterized;
openclaw/alicesplit; seeded GROUP BY attribution + aname↔agentrename guard).Gate
npm run ci— 2855 passed, 6 skipped (thesources/api.test.tsload-flake didn't surface).build/audit:sql/audit:openclawgreen. Zero deletions, nothing underassets/.🤖 Generated with Claude Code
Summary by CodeRabbit
Bug Fixes
Documentation
Tests