Skip to content

graph-stats

Provenance

  • Source: .spec/spexcode/spec-dashboard/dashboard-ui/graph/node-graph/graph-stats/spec.md
  • Source SHA-256: d4eaa7245e92a32e4b21296b662702739c2fd6e243f9767cb2e0e02a735b5f22

raw source

The board showed topology but never posture: every number on it was point-of-data, pinned to one node or one session. A reader could see the shape of the tree but not, at a glance, how big it was, how settled, what needed a human, or how well-measured it was. Add a statistics region — a small always-on strip — that says the whole-tree figures at a glance. Keep it honest and cheap: it counts the per-node badges (distinct things, never double-counted), so it teaches no new vocabulary and asks nothing new of the backend.

expanded spec

A strip pinned to the bottom-left of the [[node-graph]], always on, sharing the minimal-HUD chrome. It reads the same specs the graph plots, so it stays in lock-step with the tiles, and it is pure frontend derivation over each node's explicit [[graph-lean]] reviewSummary — no row array, new endpoint, or new vocabulary. The composition and attention figures are a count of distinct things, never a sum of badges: summing per-node badges double-counts whatever spans nodes (an issue linked to several nodes; a shared file that drifts under all its owners), so the strip counts the underlying things once. Coverage is the deliberate exception — it counts scenarios, the real unit of eval loss (see below), so its base is larger and more honest than a node roll-up.

Three clusters, each answering one question:

  • Composition — what the tree IS. A leading total, then the four status dots counted (●merged ●active ●drift ●pending, the tiles' colours). Mutually exclusive, summing to the total: "how big, and how settled".
  • Attention — what NEEDS a human. ⚠N counts nodes whose code is ahead of their spec; ◆N counts distinct open issues linked to the tree (deduped by number). Both count distinct things — an issue on three nodes is one issue. Lean per-node open ids provide only this dedupe/walk identity, never issue rows; the board only knows node-linked issues, so ◆ is the linked open set.
  • Coverage — how well-MEASURED the tree is. The eval score circles, drawn through the very ScoreBadge the tiles render ([[eval-score-badge]]) — ONE vocabulary: green ✓ fresh pass, red ✗ fresh fail, a stale verdict as the greyed mark inside the ring (never an invented glyph), and a faint empty ring for a blind spot (declares scenarios, no current verdict). Here the server-projected counts remain per scenario, not per node: a node owns several scenarios, each in its own state, so each adds to its state's bucket (a never-measured scenario folds into the blind-spot empty). This gives the row a larger, truer base than collapsing every node to one worst-first verdict. It counts only what the frontend can see — not a "should have a scenario" census, which lives in spex eval lint.

Every chip is a walk, always at node granularity: clicking steps focus to the next node it counts, entering at the first when focus is outside the ring and wrapping — so repeated clicks cycle through them all, each drilling that node's spine open and panning to it. The step is the shared cycleNext primitive ([[keyboard-nav]]) the o/O overlay cycle also walks with, so click and keypress advance alike. For a coverage chip the ring is the nodes that own a scenario in that state (a mixed node can therefore appear under several coverage chips, and the empty chip walks you to the node carrying the unmeasured scenario) — the scenario is the unit COUNTED, the node stays the unit WALKED. A zero-count chip dims and goes inert. Desktop-only — it mounts in the graph shell the phone never renders ([[mobile-ui]]).

GraphStats.jsx is this node's only owned source: mounted by the shared App shell, reusing cycleNext ([[keyboard-nav]]) and ScoreBadge ([[eval-score-badge]]) rather than re-implementing them, and adding a .board-stats block to the shared stylesheet ([[node-graph]] keeps styles.css) plus a stats i18n section it owns. So a later change to the shell, the cycle primitive, or the graph is their node's drift, not this strip's.