Rebuild the live "Team memory" view so the light/real-data version matches the
dark Bauhaus mock and the graph is genuinely DYNAMIC instead of dead static columns.
Frontend (frontend/src/components/graph/*, composed into GraphView.tsx):
- forceSim.ts: a tiny dependency-free force layout (charge repulsion, link springs,
centroid recentering + gentle pull, 2-pass collision, bounds clamp, alpha anneal).
No d3-force dependency added — keeps the shared pnpm-lock untouched so CI's
frozen-lockfile install and the deploy path are unaffected.
- GraphCanvas.tsx: SVG render driven by the sim — draggable + pinnable nodes
(double-click to release), curved edges that fan parallel pairs, weight-sized
geometric node shapes, fade-in on new nodes/edges, animated learned_from dash,
risk-path lighting with the rest dimmed, label collision-avoidance.
- MetricsRail / LearningLoop / ActivityStream / SelectedNodePanel / encoding.ts:
the mock's rails + stream + detail panel, light shadcn (ToggleGroup, ScrollArea,
Badge, Button) on theme tokens; only the SVG is bespoke.
- GraphView polls /api/pods/:id/graph every 5s and diffs (positions preserved across
refreshes), with a best-effort ws /api/events nudge. A stale selection (node gone
across a poll) is dropped so the canvas can't dim entirely.
Backend (additive — materializer de-noise untouched):
- live.ts: buildLoop() (observe→store→predict→outcome→adapt counts, deepest-recent
stage active) and buildActivity() (time-sorted typed feed, same isFilePath /
ENGINEER_NOISE / signature de-noise) emitted alongside nodes/edges/metrics.
- demo.ts: fallback loop + activity so the panels render on the demo path.
- shared/src/graph.ts: additive optional PodGraph.loop / .activity + LearningStage /
ActivityEvent types.
Verified: pnpm lint + -r typecheck + -r build pass; Playwright on the dev build
confirmed force layout (distinct positions, ticks on load under StrictMode), drag,
risk-mode dimming (opacity 0.14), selection panel, legend, and no overlaps on both
the clean demo and the 31-node live hairball.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Adds the team_model graph layer (the "it learned" view) and its visualization,
per docs/graph.md. Demo-backed first; built on origin/main conventions.
- shared: PodGraph / node / edge / metric types + GraphNodeDoc / GraphEdgeDoc
- backend/src/graph: demo graph data; Mongo store (loadPodGraph w/ demo
fallback, seedGraph, reachFrom via $graphLookup); graph:seed script
- backend/src/server.ts: additive GET /api/pods/:id/graph + /graph/reach/:node
- frontend: dark-Bauhaus GraphView + fetch helper, reachable from a
"Team memory" toggle in App.tsx
- docs/graph.md: spec (data model, $graphLookup, API, demo-first plan)
Demo-backed: the route serves a grounded demo graph when team_model has no
graph yet; graph:seed writes team_model + graph_nodes/graph_edges so the
$graphLookup traversal is real. Swap loadPodGraph to live team_model later.
Known follow-ups before merge: branch is based on 65a0791; origin/main is now
at 1294b84, so this needs a rebase + App.tsx conflict resolution (teammate
rewrote App.tsx with live room view / one-click join).
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>