fix(graph): honest graph-consistent metrics + flow narrative on node click
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>
This commit is contained in:
@@ -1,28 +1,32 @@
|
||||
import type { PodGraphNode } from '@podman/shared';
|
||||
import { Badge } from '@/components/ui/badge';
|
||||
import { statusColor, VIOLET } from './encoding.js';
|
||||
import { statusColor, modeBlurb, VIOLET, type Mode } from './encoding.js';
|
||||
|
||||
export function SelectedNodePanel({
|
||||
node,
|
||||
relCount,
|
||||
flow,
|
||||
mode,
|
||||
}: {
|
||||
node: PodGraphNode | undefined;
|
||||
relCount: number;
|
||||
flow: string;
|
||||
mode: Mode;
|
||||
}) {
|
||||
if (!node) {
|
||||
return (
|
||||
<div className="flex h-full flex-col">
|
||||
<p className="mb-2 text-xs font-medium uppercase tracking-wide text-muted-foreground">
|
||||
Continual learning
|
||||
{mode === 'learn' ? 'Learning edges' : mode === 'all' ? 'Whole graph' : 'Risk path'}
|
||||
</p>
|
||||
<h3 className="mb-2 font-heading text-base font-medium">It learned</h3>
|
||||
<p className="text-sm leading-relaxed text-muted-foreground">
|
||||
The violet{' '}
|
||||
<h3 className="mb-2 font-heading text-base font-medium">What you're looking at</h3>
|
||||
<p className="text-sm leading-relaxed text-muted-foreground">{modeBlurb(mode)}</p>
|
||||
<p className="mt-3 text-sm leading-relaxed text-muted-foreground">
|
||||
Click any node to trace its{' '}
|
||||
<span className="font-medium" style={{ color: VIOLET }}>
|
||||
learned_from
|
||||
flow
|
||||
</span>{' '}
|
||||
edges are ownership PodMan retained from accepted interventions — the graph gets sharper
|
||||
every session. Click any node to trace its relationships, or drag to rearrange.
|
||||
— what PodMan saw, flagged, and learned. Drag to rearrange.
|
||||
</p>
|
||||
</div>
|
||||
);
|
||||
@@ -43,8 +47,16 @@ export function SelectedNodePanel({
|
||||
<span>Relationships</span>
|
||||
<span className="font-medium text-foreground">{relCount}</span>
|
||||
</div>
|
||||
{node.summary && (
|
||||
<p className="mt-2.5 text-sm leading-relaxed text-muted-foreground">{node.summary}</p>
|
||||
{flow && (
|
||||
<>
|
||||
<p className="mt-2.5 text-[0.7rem] font-medium uppercase tracking-wide text-muted-foreground">
|
||||
Flow
|
||||
</p>
|
||||
<p className="mt-1 text-sm leading-relaxed text-foreground/90">{flow}</p>
|
||||
</>
|
||||
)}
|
||||
{node.summary && node.summary !== flow && (
|
||||
<p className="mt-2 text-xs leading-relaxed text-muted-foreground">{node.summary}</p>
|
||||
)}
|
||||
</div>
|
||||
);
|
||||
|
||||
Reference in New Issue
Block a user