---
id: dashboards
class: b2
sourced: 2026-07-12
source: "b2b-ux-patterns ch.15"
license: open
---
# Pass: dashboards

**Inputs:** per canvas — `dashboardJob` (monitoring | narrative | work-router), `multiJobCanvas`, `cachedDecisionData`, `viewerScopedMetrics`, `promotionRole` (manager | operator), `pushDigest`; per tile — `tile`, `monitoringTile`, `thresholdDeclared`, `trendTileRequested`, `sourceHistoryClass` (overwrite | sampled | logged).
**Owns:** `archetypes`, `requiredStates`, `requiredMechanics`, `clarifications`.
**Output artifact:** for each surface a product calls a "dashboard," which of the three archetypes it actually is, the five-part contract every tile obeys, and the data properties (Sampled trends, freshness, config-object thresholds) the surface renders.

## The rule

**"Dashboard" is not one archetype — it is three, with different jobs, metrics, and consumers.** *The monitoring glance* answers "is anything on fire?" in under five seconds and lets the user leave; **success = the user leaves quickly**; it renders **judgment, not data** — green/amber/red against declared thresholds, states instead of precise values, anomaly-first ordering, pre-attentive color-plus-icon (never color alone). A wall of raw numbers on a monitoring surface is an abdication. *The narrative report* tells what happened this period and why, usually to someone other than the operator; **success = the reader trusts and can retell the story**; period comparisons and targets-vs-actuals everywhere, trend context on every number, an explicit as-of timestamp and reporting-timezone declaration, and the house-knowledge corrective behind the significance gate. *The work router in dashboard clothes* is really the Home/work router — my tasks, approvals waiting, the ranked next-best-action queue; **success = click-through, not dwell**; it is a queue and is already specified by that archetype — recognize it and never mix it onto a monitoring or narrative canvas.

**The mixing rule: one canvas serves one of the three jobs.** If a page must carry more than one (a home page with a status strip above a worklist), zone them explicitly — separate regions with separate refresh and interaction contracts — rather than interleaving tiles of different species.

**Every number is a door — a number alone is decoration.** The full tile contract, required of every tile: (1) **the number**, formatted per its field type, no precision theater; (2) **a comparison** — vs target, prior period, or cohort — without which the reader cannot tell if the number is good; (3) **a trend** — sparkline or delta, shape not just position; (4) **a state** — good/warn/bad, which requires a declared threshold, so no threshold means no state and no place on a monitoring surface; (5) **a door** — clicking lands on the exact filtered record set or analytics view that *produced* the number. A stat tile is a saved view rendered as an aggregate, and the door is a reconciliation requirement: the count behind the door must equal the number on the tile, or trust in the whole surface dies. Browse-index stat cards obey the same five-part contract, scoped to the index's current filter.

**Dashboards are where three lifecycle declarations become visible.** Trend tiles are the UI output of the **Sampled** history class — a field declared Overwrite has no trend to show, and an empty trend tile is a history-class declaration failure, not a chart bug. **Freshness is mandatory** — every tile group carries "updated N minutes ago" and degraded tiles fail individually, so one dead query never blanks the board. **Targets and thresholds are config objects** — owned, versioned, auditable — not constants buried in tile definitions. The whole surface renders f(data, viewer): a scope switcher (me / my team / org) rather than separate dashboards per rung, tiles gated by role and plan.

**Promotion follows frequency × criticality, not habit** — dashboards go high for managers and low for operators, whose landing surface is the queue or index with the glance strip at most zoned above it; defaulting every sidebar item to a dashboard is the dashboard-first fallacy. The 2026 push inversion turns the monitoring dashboard from the ritually-visited wall into the drill-down destination behind a pushed digest — design the digest → dashboard → door → records chain unbroken, and ship auto-narration only behind the significance gate. A monitoring tile with no declared threshold cannot render a state: clarify. A trend tile over an Overwrite field has no trend to show: clarify.

```json decision-table
{"pass": "dashboards", "rows": [
  {"when": {"dashboardJob": "monitoring"}, "then": {"archetypes": {"mustInclude": ["dashboard"]}, "requiredMechanics": {"mustInclude": ["judgment-not-data", "declared-thresholds", "state-color-plus-icon", "anomaly-first-ordering"], "mustNotInclude": ["wall-of-raw-numbers", "color-alone-encoding"]}}, "reason": "monitoring-renders-judgment"},
  {"when": {"dashboardJob": "narrative"}, "then": {"archetypes": {"mustInclude": ["dashboard"]}, "requiredMechanics": {"mustInclude": ["period-comparison", "targets-vs-actuals", "trend-on-every-number", "as-of-timestamp", "reporting-timezone-declaration"]}}, "reason": "narrative-tells-a-trusted-story"},
  {"when": {"dashboardJob": "work-router"}, "then": {"archetypes": {"mustInclude": ["queue"], "mustNotInclude": ["dashboard"]}, "requiredMechanics": {"mustInclude": ["viewer-scoped-worklist", "click-through-not-dwell"], "mustNotInclude": ["mixed-onto-monitoring-canvas"]}}, "reason": "work-router-is-a-queue-not-a-dashboard"},
  {"when": {"tile": true}, "then": {"requiredMechanics": {"mustInclude": ["tile-number-formatted", "tile-comparison", "tile-trend", "tile-state-threshold", "tile-door-reconciled"], "mustNotInclude": ["number-alone", "unreconciled-door"]}}, "reason": "every-number-is-a-door"},
  {"when": {"multiJobCanvas": true}, "then": {"requiredMechanics": {"mustInclude": ["zone-explicitly-separate-regions"], "mustNotInclude": ["interleave-tile-species"]}}, "reason": "one-canvas-one-job"},
  {"when": {"cachedDecisionData": true}, "then": {"requiredStates": {"mustInclude": ["stale", "degraded"]}, "requiredMechanics": {"mustInclude": ["freshness-updated-n-min", "degraded-tiles-fail-individually"]}}, "reason": "decisions-get-made-on-cached-numbers"},
  {"when": {"viewerScopedMetrics": true}, "then": {"requiredMechanics": {"mustInclude": ["scope-switcher-me-team-org", "role-plan-gated-tiles"]}}, "reason": "dashboard-renders-f-data-viewer"},
  {"when": {"promotionRole": "manager"}, "then": {"requiredMechanics": {"mustInclude": ["dashboard-sidebar-promotion"]}}, "reason": "dashboards-are-high-for-managers"},
  {"when": {"promotionRole": "operator"}, "then": {"requiredMechanics": {"mustInclude": ["glance-strip-zoned-above-queue"], "mustNotInclude": ["dashboard-first-fallacy"]}}, "reason": "operators-land-on-a-queue-not-a-dashboard"},
  {"when": {"pushDigest": true}, "then": {"requiredMechanics": {"mustInclude": ["subscribe-to-metric-digest", "digest-to-dashboard-to-door-chain", "auto-narration-behind-significance-gate"]}}, "reason": "push-inversion-precedes-the-visit"},
  {"when": {"trendTileRequested": true, "sourceHistoryClass": "sampled"}, "then": {"requiredMechanics": {"mustInclude": ["sparkline-from-sampled-class"]}}, "reason": "trend-tiles-render-the-sampled-class"},
  {"when": {"monitoringTile": true, "thresholdDeclared": false}, "then": {"clarifications": ["threshold-unspecified"]}, "reason": "no-threshold-no-state-no-monitoring-tile"},
  {"when": {"trendTileRequested": true, "sourceHistoryClass": "overwrite"}, "then": {"clarifications": ["trend-needs-sampled-class"]}, "reason": "overwrite-field-has-no-trend-to-show"}
]}
```
