Address review feedback on the live view:
Metrics looked fake because they counted raw DB events (test churn) instead of
the de-noised entities actually drawn — e.g. "Open risk paths: 50" for 2 files,
"Learned owners: 16" with 2 ownership edges, and the caption ("Files with 2+
editors") contradicting the number. Now derived from the final graph:
- Open risk paths = distinct files carrying a surviving collision (50 -> 4 on live).
- Learned owners = distinct engineers retained as owners via owns/learned_from
edges (16 -> 1 on live).
- Accept rate = accepted vs total real outcomes.
demo.ts metrics + loop counts realigned to its own graph (3 owners / 1 risk path
/ 100%) so nothing contradicts the picture; the PREDICT/ADAPT loop stages reuse
the same de-noised counts.
Right pane now explains the flow: clicking a node renders a plain-English walk of
its path (flowNarrative) — "Karti and Yahya are both editing auth.ts before
pushing ... PodMan suggested a sync PR", "PodMan offered a sync PR for the overlap
on auth.ts. The pod accepted it, so PodMan learned Karti owns auth.ts." With no
selection the panel gives a mode-aware explainer of what the lit path means. Edge
legend rounded out with editing/touches.
Verified: lint + -r typecheck + -r build pass; Playwright confirmed the flow text
per node kind and the demo metrics (3/1/100%); the metric formula re-checked
against the real live graph (4 risk files / 1 learned owner).
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
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>
The deployed graph was an unreadable mess: full file paths centered on nodes
bled across columns, and collision labels showed garbage vision symbols
("infra/README.md### Running the git watcher").
- node labels are now the last two path segments (full path in summary)
- collision labels are just the file (drop the junk #symbol)
- cap file nodes to 9 (collision files prioritized)
demo-pod: 22 -> 20 clean nodes; no label bleed.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Materializer (live.ts) — cut demo-pod from 110 -> 22 nodes:
- cap to 8 recent collisions; collapse repeats by memorySignature
- collapse interventions to one (most recent) per collision
- filter junk 'files' (URLs, env vars, browser/app names, scratch/test) to
real source paths only
- prune test-artifact engineers (a/b/verify/codex-check/-testrepo) + any node
orphaned by that
- collisions referenced by accepted outcomes bypass the cap so the learned_from
money path never drops; risk-paths metric counts distinct signatures
UI: per-pod 'Team memory' action on each PodCard's menu (replaces the header
button that always opened pods[0]).
Verified against live demo-pod data (joins connect); typechecks clean.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Verified materializePodGraph against real demo-pod data (joins all connect:
21/21 interventions->collisions, learned_from produced). Tuning:
- engineer nodes are case-insensitive (merges Shakthi/shakthi)
- git (engineer_states) now only CONFIRMS editing on files vision/collisions
already surfaced, instead of adding the whole repo diff (killed a 29-file
node explosion from a watcher running against the full podman repo)
Cut demo-pod from 110 -> 77 nodes; git file-edges 39 -> 6.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
- backend/src/graph/live.ts: materializePodGraph builds the graph from the real
collections (pods, engineer_states, observations, collisions, interventions,
outcomes) instead of the demo seed. Parses git-status paths, fuses git+vision,
draws collides/warns/learned_from, computes live metrics + a column layout.
- store.ts: loadPodGraph now prefers live → seeded team_model.graph → demo.
- GraphView.tsx: light/shadcn theme (from the team-memory-theme work), composed
from the ruixen primitives; node-shape encoding unchanged.
- docs/graph.md: live data→graph mapping + fallback order.
Typechecks clean. Not yet runtime-verified end-to-end (Atlas creds rotated again).
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>