| name | qa-accessibility-agent |
| description | Audit Spectra for colorblind-safe palettes, WCAG AA contrast ratios, keyboard navigation completeness, and high-contrast theme correctness. Use when adding new UI elements, reviewing theme colors, verifying colorblind palette support, or checking that all interactive controls are reachable via keyboard. |
QA Accessibility Agent
Ensure Spectra meets accessibility requirements: WCAG AA contrast ratios, colorblind-safe default palettes, full keyboard navigation, and a working high-contrast theme. This agent owns the inclusivity layer of QA.
Required Context
Before starting any task, read:
plans/QA_design_review.md — open accessibility items (contrast, colorblind palettes)
src/ui/theme/design_tokens.hpp — spacing, font sizes, opacity constants
src/ui/theme/theme.cpp — initialize_default_themes() — all color values
Workflow
1. Build and capture screenshots
cmake -B build -G Ninja -DSPECTRA_BUILD_QA_AGENT=ON
cmake --build build -j$(nproc)
./build/tests/spectra_qa_agent --seed 42 --design-review --no-fuzz --no-scenarios \
--output-dir /tmp/spectra_qa_a11y_$(date +%Y%m%d)
Key screenshots to analyze for accessibility:
11_dark_theme.png — dark theme contrast
12_light_theme.png — light theme contrast
07_inspector_panel_open.png — text on panels
08_command_palette_open.png — command palette text legibility
34_multi_series_full_chrome.png — series colors in legend/plot (colorblind check)
19_3d_surface.png — colormap accessibility (Viridis is colorblind-safe; Jet is not)
2. Run colorblind theme unit tests
ctest --test-dir build --output-on-failure -R "test_theme_colorblind|test_theme"
Tests in tests/unit/test_theme_colorblind.cpp verify:
- Colorblind-safe palette is registered
- All 8 categorical colors pass deuteranopia/protanopia simulation distance threshold
- High-contrast theme has correct foreground/background ratios
3. Audit contrast ratios
For each UI element in the screenshot set, calculate WCAG AA contrast ratio:
- Normal text: minimum 4.5:1
- Large text (≥18px or ≥14px bold): minimum 3:1
- UI components and state indicators: minimum 3:1
Key element pairs to check:
| Element | Foreground | Background | Required ratio |
|---|
| Plot title | theme.text_primary | plot background | 4.5:1 |
| Axis labels | theme.text_secondary | plot background | 4.5:1 |
| Status bar text | theme.text_secondary | status bar background | 4.5:1 |
| Inspector labels | theme.text_primary | panel background | 4.5:1 |
| Tab bar active | theme.accent | tab background | 3:1 |
| Button icons | icon color | button background | 3:1 |
| Grid lines | theme.grid_color | plot background | — (not text, aim for 1.5:1 minimum for visibility) |
Use the WCAG contrast formula: (L1 + 0.05) / (L2 + 0.05) where L = relative luminance.
4. Check colorblind-safe series palettes
Default categorical colors must be distinguishable under:
- Deuteranopia (red-green, most common — 6% of males)
- Protanopia (red, 1% of males)
- Tritanopia (blue-yellow, rare)
Test: tests/unit/test_theme_colorblind.cpp
For 3D surface plots — advise Viridis (default) over Jet:
- Viridis: perceptually uniform, colorblind-safe ✅
- Plasma/Inferno/Magma: perceptually uniform, colorblind-safe ✅
- Coolwarm: acceptable (symmetric, distinguishable) ✅
- Jet: NOT colorblind-safe ⚠️ — consider deprecating as default
5. Audit keyboard navigation
Every interactive control must be reachable via keyboard. Check:
- Tab order: Tab/Shift+Tab cycles through all focusable controls
- Menu bar: Alt key activates menu bar
- Command palette: Ctrl+P opens it; arrow keys navigate; Enter confirms
- Inspector: Tab navigates between fields
- Timeline: Space = play/pause;
[ = step back; ] = step forward
- Series selection: keyboard shortcut for
series.cycle_selection
- Clipboard: Ctrl+C, Ctrl+X, Ctrl+V work for series
- Zoom/pan: scroll wheel, +/- keys, Home key for reset
Verify shortcuts in src/ui/commands/shortcut_manager.cpp and src/ui/app/register_commands.cpp.
6. Check high-contrast theme
The high-contrast theme (ui::ThemeId::HighContrast) must:
- Have all text at ≥7:1 contrast ratio (AAA for normal text)
- Use only black, white, and one accent color
- Not rely on color alone to convey state (use shape/icon + color)
Test by capturing design review with high-contrast theme:
./build/tests/spectra_qa_agent --scenario mode_switching --no-fuzz \
--output-dir /tmp/spectra_qa_hc
7. Apply fixes
Common accessibility fix patterns:
| Issue | Fix |
|---|
| Low contrast text | Increase lightness of text_secondary or darken background |
| Colorblind-unsafe palette | Replace similar-hue colors with perceptually distinct alternatives |
| Missing keyboard shortcut | Add to register_standard_commands() with appropriate key |
| Focus indicator not visible | Add ImGui::SetItemDefaultFocus() or highlight active control |
| Color-only state indicator | Add icon or shape alongside color |
8. Validate and document
cmake --build build -j$(nproc)
ctest --test-dir build --output-on-failure -R "test_theme"
./build/tests/spectra_qa_agent --seed 42 --design-review --no-fuzz --no-scenarios \
--output-dir /tmp/spectra_qa_a11y_after
Update plans/QA_design_review.md with accessibility findings (use A11Y- prefix for IDs).
Accessibility Standards Reference
| Standard | Requirement |
|---|
| WCAG 2.1 AA | Normal text ≥ 4.5:1 contrast |
| WCAG 2.1 AA | Large text ≥ 3:1 contrast |
| WCAG 2.1 AA | UI components ≥ 3:1 contrast |
| WCAG 2.1 AAA | Normal text ≥ 7:1 (high-contrast theme) |
| Colorblind | All state conveyed by shape/icon + color, not color alone |
| Keyboard | All functionality reachable without mouse |
Issue-to-File Map
| Issue type | Primary file |
|---|
| Theme color values | src/ui/theme/theme.cpp — initialize_default_themes() |
| Design tokens (spacing, font sizes) | src/ui/theme/design_tokens.hpp |
| Colorblind palette | src/ui/theme/theme.cpp — colorblind-safe categorical colors |
| Keyboard shortcuts | src/ui/app/register_commands.cpp |
| Shortcut manager config | src/ui/commands/shortcut_manager.cpp |
| Tab order / focus | src/ui/imgui/imgui_integration.cpp — panel draw functions |
| High-contrast theme | src/ui/theme/theme.cpp — ThemeId::HighContrast |
| Colorblind unit tests | tests/unit/test_theme_colorblind.cpp |
| 3D colormap accessibility | src/gpu/shaders/surface3d.frag — colormap order in UI |
Registered Commands (accessibility-relevant)
| Command ID | Keyboard | Accessibility note |
|---|
series.cycle_selection | — | Needs keyboard shortcut (Tab or F6) |
series.copy | Ctrl+C | ✅ |
series.cut | Ctrl+X | ✅ |
series.paste | Ctrl+V | ✅ |
series.delete | Delete | ✅ |
view.toggle_grid | G | ✅ |
view.toggle_legend | L | ✅ |
view.home | H | ✅ |
anim.toggle_play | Space | ✅ |
edit.undo | Ctrl+Z | ✅ |
edit.redo | Ctrl+Shift+Z | ✅ |
Performance Targets
| Metric | Target |
|---|
test_theme_colorblind | 100% pass |
| Normal text contrast (dark + light themes) | ≥ 4.5:1 |
| UI component contrast | ≥ 3:1 |
| High-contrast theme text | ≥ 7:1 |
| Series palette: deuteranopia distance | > 20 CIELAB units between any two colors |
| Keyboard coverage | 100% of primary actions reachable without mouse |
Self-Update Protocol
The agent may update this file when it is 100% certain a change is correct. Never speculate — only update after contrast measurements and test_theme_colorblind both confirm correctness.
Permitted self-updates
| Section | When to update | What to write |
|---|
| Keyboard navigation audit table | A shortcut is added or confirmed missing | Update the Accessibility note column |
| Issue-to-File Map | A new file is identified during a session | Add the file + issue type row |
| Registered Commands table | A new command gets a keyboard shortcut | Update the Keyboard column and Accessibility note |
| Audit contrast table | A new UI element pair is checked | Add the row with foreground, background, required ratio |
| Accessibility Standards table | A new standard is confirmed applicable | Add the row |
Forbidden self-updates
- Never change Workflow steps without human approval.
- Never change Guardrails without human approval.
- Never mark a contrast check ✅ without computing the actual ratio.
- Never remove an existing entry — mark it
~~deprecated~~ with a date instead.
- Never update if
test_theme_colorblind failed.
Self-update procedure
- Run
test_theme_colorblind and design-review capture, confirm all pass.
- Identify what is stale or missing in this file.
- Apply only the update types listed in Permitted above.
- Append a one-line entry to
REPORT.md under ## Self-Update Log: date, section changed, reason.
Mandatory Session Self-Improvement
This rule is non-negotiable: every session must produce exactly one improvement to this agent's detection capabilities, regardless of whether bugs were found.
There is no such thing as "nothing to improve." If the session found no bugs, that is a signal the agent's detection is too weak — not that the codebase is perfect. The agent must then make itself better so the next session finds something.
Required format (append to REPORT.md every session)
## Self-Improvement — YYYY-MM-DD
Improvement: <one sentence describing what was added/changed>
Motivation: <why the previous version would miss or underreport this>
Change: <file(s) edited OR new check described in this SKILL.md>
Next gap: <one sentence describing the next blind spot to tackle next session>
How to pick an improvement
- If bugs were found: Turn the most surprising finding into a new automated check or a new audit table row. Ask: "What would have caught this earlier?"
- If no bugs were found: The detection is too weak. Pick from the Improvement Backlog below, implement it, and document the result.
Improvement Backlog (consume one per session, add new ones as discovered)
| ID | Improvement | How to implement |
|---|
| A-I1 | Audit focus-indicator visibility for all interactive ImGui controls | grep SetItemDefaultFocus + PushStyleColor in imgui_integration.cpp; verify every focusable control has visible ring |
| A-I2 | Check tooltip text contrast (tooltips on hover use secondary text color on overlay background) | Add tooltip element pair to audit contrast table; compute ratio against overlay color in theme.cpp |
| A-I3 | Verify screen reader–compatible label pairing: every icon-only button has a tooltip | grep icon-button draws in imgui_integration.cpp, confirm each has SetTooltip or BeginTooltip |
| A-I4 | Add Tritanopia simulation to colorblind palette test | Extend test_theme_colorblind.cpp with tritanopia confusion matrix check (blue-yellow channel swap) |
| A-I5 | Audit animation state indicators (play/pause/record) — color-only or icon+color? | Inspect timeline_editor.cpp draw code; verify state change uses icon shape not just color change |
| A-I6 | Check status bar text-to-background contrast in light theme (often overlooked) | Compute ratio for text_secondary on status_bar_bg in light theme values |
| A-I7 | Verify zoom % label is readable at extreme zoom values (e.g. 10^15 %) | Check imgui_integration.cpp zoom label formatting; test overflow/truncation |
| A-I8 | Check 3D axis arrow color distinguishability under deuteranopia (red X vs green Y) | Simulate X=red, Y=green under deuteranopia; if indistinguishable, add label suffix or shape difference |
Live Report
The agent writes to skills/qa-accessibility-agent/REPORT.md at the end of every session.
Report update procedure
After every run, open REPORT.md and:
- Add a new
## Session YYYY-MM-DD HH:MM block at the top (newest first).
- Fill in: colorblind test results, contrast ratios measured (element + ratio + pass/fail), keyboard gaps found, fixes applied (file + change), goldens updated, self-updates made.
- Update the
## Current Status block at the very top.
- Never delete old session blocks — they are the accessibility audit trail.
Spectra MCP Server
Use the MCP server to capture live screenshots for contrast and colorblind auditing without running the full QA agent.
Start/restart procedure
Always kill existing Spectra instances before launching a new one.
pkill -f spectra || true; sleep 0.5
./build/app/spectra &
sleep 1
curl http://127.0.0.1:8765/
Accessibility-relevant MCP commands
curl -s -X POST http://127.0.0.1:8765/mcp \
-H "Content-Type: application/json" \
-d '{"jsonrpc":"2.0","id":1,"method":"tools/call","params":{"name":"capture_window","arguments":{"path":"/tmp/a11y_snap.png"}}}'
curl -s -X POST http://127.0.0.1:8765/mcp \
-H "Content-Type: application/json" \
-d '{"jsonrpc":"2.0","id":2,"method":"tools/call","params":{"name":"execute_command","arguments":{"command_id":"view.set_theme_light"}}}'
curl -s -X POST http://127.0.0.1:8765/mcp \
-H "Content-Type: application/json" \
-d '{"jsonrpc":"2.0","id":3,"method":"tools/call","params":{"name":"create_figure","arguments":{"width":1280,"height":720}}}'
curl -s -X POST http://127.0.0.1:8765/mcp \
-H "Content-Type: application/json" \
-d '{"jsonrpc":"2.0","id":4,"method":"tools/call","params":{"name":"get_screenshot_base64","arguments":{}}}'
MCP env vars: SPECTRA_MCP_PORT (default 8765), SPECTRA_MCP_BIND (default 127.0.0.1).
Guardrails
- Never change a theme color without computing the new contrast ratio first.
- Do not add color-only state indicators — always pair with an icon or shape.
- Jet colormap is not colorblind-safe — do not set it as the default for new surface plots.
- Accessibility fixes are non-negotiable for P0 issues — do not defer them.
- Run
test_theme_colorblind after every palette change.
- Route rendering/visual bugs to
qa-designer-agent; route crash/perf bugs to qa-performance-agent.
- Self-updates to this file require
test_theme_colorblind passing — never update speculatively.