feat(graph): continual-learning graph data model + dark-Bauhaus viz

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>
This commit is contained in:
sb-iam
2026-06-27 17:34:02 -07:00
parent 1294b8428d
commit 546aeeed70
11 changed files with 892 additions and 7 deletions
+69
View File
@@ -0,0 +1,69 @@
/**
* Continual-learning graph: PodMan's visible "it learned" surface. A render of
* the per-pod team_model — who owns/edits which files, where work collides, and
* what PodMan learned from accepted interventions (the `learned_from` edges).
*
* Served embedded in the `team_model` document; mirrored into `graph_nodes` /
* `graph_edges` collections so the model can be walked with MongoDB
* `$graphLookup`. See docs/graph.md.
*/
export type PodGraphNodeKind = 'engineer' | 'feature' | 'file' | 'collision' | 'intervention';
export type PodGraphEdgeKind =
'owns' | 'editing' | 'touches' | 'collides' | 'warns' | 'learned_from';
/** `learned` marks a node PodMan retained from a past accepted intervention. */
export type PodGraphNodeStatus = 'stable' | 'active' | 'risk' | 'learned';
export interface PodGraphNode {
/** Stable graph id, e.g. "engineer:karti" or "file:auth.ts". */
id: string;
kind: PodGraphNodeKind;
label: string;
summary: string;
/** 01 relative importance — drives node size in the viz. */
weight: number;
status: PodGraphNodeStatus;
/** Layout position on the SVG canvas (viewBox 0..720 x 0..472). */
x: number;
y: number;
}
export interface PodGraphEdge {
id: string;
/** Source node id. */
source: string;
/** Target node id. */
target: string;
kind: PodGraphEdgeKind;
label: string;
/** 01 confidence/strength — drives edge thickness. */
strength: number;
}
export interface PodGraphMetric {
label: string;
value: string;
detail: string;
}
/** A point-in-time render of a pod's team_model. */
export interface PodGraph {
podId: string;
/** ISO timestamp the snapshot was generated. */
generatedAt: string;
nodes: PodGraphNode[];
edges: PodGraphEdge[];
metrics: PodGraphMetric[];
}
/** One node as a standalone document in the `graph_nodes` collection. */
export interface GraphNodeDoc extends PodGraphNode {
podId: string;
}
/** One edge as a standalone document in the `graph_edges` collection (for $graphLookup). */
export interface GraphEdgeDoc extends PodGraphEdge {
podId: string;
}
+11
View File
@@ -9,3 +9,14 @@ export type {
SuggestedActionKind,
} from './intervention.js';
export * from './messages.js';
export type {
PodGraph,
PodGraphNode,
PodGraphEdge,
PodGraphMetric,
PodGraphNodeKind,
PodGraphEdgeKind,
PodGraphNodeStatus,
GraphNodeDoc,
GraphEdgeDoc,
} from './graph.js';