Rule handbook metadata
- Rule
DET.DATA.COLOR_ONLY· lanedeterministic- Page status
- stale
- page_version
6867492406d3ec909a0742d87b388c8f118929ae94e16f369025c8fa1c41f736- generated_at
- 2026-05-19T21:45:00.000Z
- registry_fingerprint
6773fda516344e110b5a7b1435e655e1264e773825ca8bbe62194189891c42ba
How this rule is fixed
Pilot deterministic fixer: handbook_after · harness mode standalone · verify expect_rule_clean.
- Harness:
apply-harness-fixture-remediation.pycopies the After example HTML from this handbook page onto the defect fixture, theninvoke-det-ruleset-remediation-verify.shre-audits and expects zero findings for this rule. - Production sites:
run-website-ux-remediation-loop.shrunshandbook_html_patch(HTML patches inlib/ux-deterministic-fixers/fixers/patches/) before invoking the Cursor agent when the quality gate still fails.
Detection module: docs/design/ux-audit/deterministic-design-rules.md#det-data-color_only. Scroll down for Before / After examples and Evidence and remediation steps.
Purpose
Kitchen Sink data surfaces—ks-chart-mount / [data-ks-chart] charts (forge-data-charts.js), token swatches on Tkn / For Agents pages (.ks-swatch, .ks-swatch-box, .ks-swatch-label), and tables beside charts—often use color to encode series, status, or magnitude. Visitors who cannot distinguish cyan from amber, or who print in grayscale, still need the same meaning from redundant text or shape.
This deterministic rule (metrics phase, colorOnlyReport) flags detectable color-only encoding inside data contexts: legend rows with a colored mark but no label (minimum 2 characters via MIN_COLOR_LABEL_CHARS), .ks-swatch blocks missing .ks-swatch-label, and table cells whose background carries meaning while the cell body is empty. Decorative ambient layers and aria-hidden subtrees are ignored.
Plan: Inventory chart mounts, token grids, and heatmap-style tables on the page. Do: Pair every swatch or color-filled cell with a visible name, value, or icon in the same row. Check: Re-run auditor metrics or inspect colorOnlyReport.violations[]. Adjust: Wire labels in generators (tokens.py, forge-data-charts.js) or page templates; for narrative quality of the insight, see AI.DATA.INSIGHT_LEGIBILITY.
Passing signals
- Token swatches follow the showcase pattern:
.ks-swatch>.ks-swatch-box+.ks-swatch-labelwith at least two characters (for exampleamber,surface-2). - Donut / bar legends from
forge-data-charts.jsuse.lenses-overview-donut-swatchin a.d-flexrow with a<span>series name and optional.text-mutedpercentage—hue is not the only cue. - Chart swatch rows include sibling text,
.ks-swatch-label, oraria-label/titleon the swatch or row container (at least 2 characters). - Heatmap or status tables put numeric or categorical text (or
aria-label) in the same<td>as a background tint, or use icons/patterns in addition to fill. - SVG slices expose
<title>with series name and value when a separate legend is omitted (supplements, not replaces, visible legend text for sighted users). - Swatches and encoded cells sit inside a data context (
[data-ks-chart],.ks-chart-mount,figure,table, etc.) so the check applies; unrelated decorative dots outside those regions are not scored.
Failing signals
.ks-swatchwith.ks-swatch-boxbut no.ks-swatch-label(or label shorter than two characters)—kindks-swatch-missing-label, major..lenses-overview-donut-legendrow containing only.lenses-overview-donut-swatchwith inlinebackground:and no adjacent text—kindlegend-swatch-without-label, warn.- Generic legend marks (
[class*="legend-mark"],[class*="color-dot"],[class*="status-dot"]) inside a chart or table context with no row label and noaria-label. - Table body cells with meaningful background-color but empty text and no
aria-label, while the table has a header row with real<th>labels—kindtable-cell-color-only, warn. - Status dashboards that rely on green/red cell fills alone for pass/fail with no column text or icon.
- Heatmap grids where intensity is only
style="background:…"on<td>elements with no legend key or cell values.
Before example
Before (failing example)
Accent palette
Repository mix
| Check | Status |
|---|---|
| Unit tests | |
| Lint |
Failing KS markup: token swatch and chart legend rely on color alone; the data table encodes severity only via background fill.
After example
After (passing example)
Accent palette
Repository mix
Donut of tracked files by top-level language; Python leads at 41.2%, Markdown 33.8%.
| Check | Status |
|---|---|
| Unit tests | Pass |
| Lint | Fail |
Passing KS markup: every swatch and legend row includes text labels; status cells repeat meaning in characters, not only fill.
Evidence and remediation
Evidence: Auditor metrics colorOnlyReport with violations[] entries: kind (ks-swatch-missing-label, legend-swatch-without-label, table-cell-color-only), region, selectorHint, and className. Findings use evidence token color_only_encoding with severity major for missing .ks-swatch-label and warn for legend or table-cell cases. Capture the swatch row outer HTML, sibling text nodes, and any aria-label / title attributes.
Remediate (in order):
- Token pages: emit
.ks-swatch-labelbeside every.ks-swatch-box(seegenerator/pages/tokens.pyandcomponents/layouts.pyshowcase styles). - Chart legends: match
forge-data-charts.js—each.lenses-overview-donut-swatchin a.d-flexrow with series name and optional percentage text. - Custom legends: add
.ks-swatch-label, visible<span>text, oraria-labelon the swatch or row (at least 2 characters). - Tables: put status words, counts, or icons in the cell; use
aria-labelonly when visible text is intentionally abbreviated. - Re-run deterministic color-only checks; pair with
DET.CHART.ALT_SUMMARYfor mount-level summaries andDET.DATA.TABLE_HEADERSfor header scope.