Skip to content

feat(viz): cluster the Knowledge graph — each pitfall is a box holding its incident history#26

Merged
sshanzel merged 2 commits into
mainfrom
feat/viz-knowledge-clusters
Jun 17, 2026
Merged

feat(viz): cluster the Knowledge graph — each pitfall is a box holding its incident history#26
sshanzel merged 2 commits into
mainfrom
feat/viz-knowledge-clusters

Conversation

@sshanzel

Copy link
Copy Markdown
Owner

What changed

The Knowledge tab rendered pitfalls in one row and incidents in another, joined by a dense mesh of crossing from/about edges — a hairball that hid the one thing that matters most (which lesson owns which history), exactly where Plex's differentiator data lives. This clusters it: each Pitfall/Suppression is now a box holding its incident history.

  • VizNode.parent (model) — collectKnowledge nests each incident inside the first pitfall that cites it; the containment replaces the redundant from/about edge. A second pitfall citing a shared incident keeps a cross-cluster edge (a Cytoscape compound node has one parent only), so shared provenance stays visible.
  • :parent style — a tinted, type-coloured box with the lesson title pinned top; children keep their own colour + the existing outcome (green/red border) and regression-sentinel (orange ring) encoding.
  • knowledgeGrid — lays the lesson-boxes in a deterministic grid and packs each box's incidents in a mini-grid (preset positions). cose/force layouts band the (edge-less) clusters into one overlapping strip, so a hand-rolled grid is used instead of adding the fcose extension — keeps the CDN/SRI/dependency surface minimal (ADR-35 posture).
  • Incident dots drop their colliding file-path label (shown on select); the box title + outcome ring carry the meaning.

Result: the hairball becomes a readable grid of lessons — suppressions (red boxes) clearly distinct from pitfalls (teal), each box's incident count and outcomes visible at a glance.

How to test

  • pnpm test:unit (549) — collect.test asserts incidents nest via parent and that a cross-cluster from edge is kept for a shared incident; ui.test asserts the :parent style + knowledgeGrid. pnpm typecheck + pnpm build green.
  • Manual: plex serve → Knowledge tab (try "All repos (global)" and a repo scope). Verified against the populated playright/global base (26 pitfalls / 96 incidents / 6 suppressions).

Notes

Scope is the Knowledge graph only — the code-graph "800-file cold dump" landing state is a separate follow-up (the other hairball from the viz-validation pass). Lineage/Review-history is unchanged (already legible).

🤖 Generated with Claude Code

sshanzel and others added 2 commits June 17, 2026 21:35
…g its incident history (ADR-45)

The Knowledge tab rendered pitfalls in one row and incidents in another with a dense mesh
of crossing `from`/`about` edges — a hairball that hid the structure (which lesson owns
which history) exactly where the differentiator data lives. Now each Pitfall/Suppression
is a Cytoscape compound box containing its incidents:

- VizNode.parent (model) — collectKnowledge nests each incident inside the first pitfall
  that cites it; containment replaces the redundant `from`/`about` edge. A second citer of
  a shared incident keeps a cross-cluster edge (one compound parent only).
- :parent style — a tinted, type-coloured box with the lesson title pinned top; children
  keep their own colour + outcome/sentinel borders.
- knowledgeGrid — lays the lesson-boxes in a deterministic grid and packs each box's
  incidents in a mini-grid (preset positions). cose/force layouts band the edge-less
  clusters into an overlapping strip, so a hand-rolled grid is used rather than adding the
  fcose extension (keeps the SRI/dep surface minimal).
- Incident dots drop their (colliding) file-path label — shown on select; the box title +
  outcome ring carry the meaning.

Tests: collect.test asserts incidents nest via `parent` + a cross-cluster `from` edge is
kept for a shared incident; ui.test asserts the `:parent` style + knowledgeGrid. Verified
against the populated playright/global knowledge base (26 pitfalls / 96 incidents / 6
suppressions) — the hairball is now a readable grid of lessons.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
…ross-cluster edge + size grid cells to fit (PR #26 review)

Address the Plex self-review of PR #26:

- BUG: the `node[type="Incident"]{text-opacity:0}` label-hide was GLOBAL, so it also blanked
  incident labels in the code-graph symbol↔incident expand and in Lineage — views the PR
  doesn't touch. The Incident node always carries graph:'knowledge' (it's the same
  incidentVizNode reused across views), so it can't be node-scoped; gate the rule on the
  CURRENT graph instead — styleFor(graph) adds it only for knowledge.
- NIT: an incident both cited by a pitfall (incidentIds) and carrying pitfallId for that same
  non-container pitfall got both a `from` (pf→inc) and an `about` (inc→pf) edge — duplicate
  arrows for one link. Track cross-cluster `from` pairs and skip the redundant `about`.
- FLAG: the fixed 360x250 grid cell could be overflowed by a high-incident pitfall, spilling
  into the row below and overlapping a neighbour (positions are fixed). Size the uniform cell
  from the LARGEST box (+title/padding) so every box's mini-grid fits.

Tests: collect.test gains a from/about de-dup case; the existing label assertion still holds
(the rule string is emitted, now inside the knowledge branch). Verified against the populated
base — boxes read cleanly, the 16- and 24-incident boxes fit without overlap.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
@sshanzel sshanzel merged commit e64eaa4 into main Jun 17, 2026
1 check passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant