Skip to content

KB / framework

The five-level signal scale

Last verified

Every banded signal on the platform is classified onto one universal 5-level scale: Favorable / Leaning / Neutral / Cautionary / Adverse. The colored dot next to a signal value is the level; the alignment dots, sparkline tints, and KB article band tables all map to the same five tiers. One scale, one source of truth — the band classifier in app/signals/config/signal_definitions.json.

The five levels

Universal scale — every banded metric maps to one of these

Favorable Green dot (#34d399) Conditions are constructive for the signal's metric. Supports risk-taking. Top score band.
Leaning Lime dot (#a3e635) Slightly positive — tilting constructive but not at the favorable threshold.
Neutral Gray dot (#6b7280) No strong signal either way. Mid-range read.
Cautionary Amber dot (#fbbf24) Deteriorating. Risk management warranted but not yet critical.
Adverse Red dot (#f87171) Danger zone. Immediate attention. Bottom score band.

The hex codes are the canonical dashboard palette pinned in ui/src/pages/humans.astro and reused by every signal card, alignment dot, and KB band table tint.

Why five (not three, not seven)

Three levels (red / yellow / green) collapse meaningful gradations — a DIX of 0.42 (right at the bear threshold) reads the same as 0.30 (deep bear). Seven levels read like noise on a dashboard; the operator can’t hold “very-mild-cautionary vs mild-cautionary” in working memory while scanning twenty dots.

Five captures the differentiation that matters — directional bias (Favorable / Adverse), the soft directional tier next to it (Leaning / Cautionary), and a true middle (Neutral) — without overflowing the visual budget. The same five-tier shape recurs across the platform: alert severity (info / warning / critical maps onto Favorable / Cautionary / Adverse), regime label (RISK-ON / CAUTIOUS / TRANSITIONAL / RISK-OFF / PANIC also reads as a 5-band ladder), and score reconciliation labels.

How a metric maps to a level

The mapping path is registry-driven end-to-end:

  1. A metric’s bands[] array in signal_definitions.json declares thresholds and per-band dot_level strings (one of the five).
  2. band_for(metric_key, value) in app/signals/signal_defs.py returns the matching Band object — carries label, dot_level, implication, and score_pts.
  3. The dashboard renders Band.dot_level as the colored dot; the alignment surface reads it; the hybrid matcher projects it as a tag; the KB band table tint maps to it.

One classifier, many consumers. The dot you see on the dashboard, the tag the matcher pre-filters on, and the alignment leg’s implication all derive from the same band_for() call — drift between them is impossible by construction.

Where the scale surfaces

See also