Skip to content

Warn when an html surface hardcodes scheme colors#190

Open
benvinegar wants to merge 1 commit into
mainfrom
fix/warn-hardcoded-surface-colors
Open

Warn when an html surface hardcodes scheme colors#190
benvinegar wants to merge 1 commit into
mainfrom
fix/warn-hardcoded-surface-colors

Conversation

@benvinegar

Copy link
Copy Markdown
Member

Problem

Agents sometimes publish an html surface whose markdown/HTML hardcodes a light (or dark) color palette — e.g. background:#ffffff; color:#57606a. On a board in the opposite scheme it renders washed-out and nearly unreadable:

hardcoded #ffffff on a dark board same content via --color-* tokens
white box, faint blue/gray text adapts: transparent/dark, light text

This was reported as "the agent sometimes generates markdown that doesn't match the theme (dark + light)." Root-caused by reproduction: it's not markdown (markdown surfaces are transparent and escape raw HTML), not a theming/cache/timing bug, and not the renderer — token-driven surfaces already adapt correctly. It's an html surface hardcoding colors.

The guide already states the firm rule ("Theming — dark mode is mandatory … Never hardcode colors"), and the renderer can't fix it after the fact: it can't distinguish an accidental light card from a deliberate one (some light/dark designs are intentional). So the clash goes unnoticed until a human sees it.

Change

Flag it back to the author at publish/revise time as a non-blocking warnings array in the API response — the same channel that already carries userFeedback:

{ "id": "", "sessionId": "", "version": 1,
  "warnings": ["surface hardcodes colors (background: #ffffff, color: #57606a) — drive color from the --color-* theme tokens so it adapts to light/dark; hardcoded colors render washed-out on a board in the opposite scheme."] }
  • server/surfaceLint.tsfindHardcodedColors / lintSurfaces. Scans inline style="…" and <style> blocks for background/color declarations with a literal value (hex / rgb / hsl / white|black). Skips var(--…) (including var(--x, #fff) fallbacks), SVG fill/stroke, and decorative borders to keep false positives down.
  • Threaded through publishSurface + reviseSurface (and the per-surface append/replace/remove/reorder paths) into every surface-write response.
  • Non-blocking: intentional designs are warned but never rejected. Other surface kinds are untouched.

Tests

  • test/surfaceLint.test.ts — detector unit tests (hex/rgb/hsl/named, <style> blocks, var() incl. fallback, SVG/border exclusion, cap, 1-based labels).
  • test/api.test.ts — integration: publishing a hardcoded surface returns warnings; a token-driven surface returns none; revising into hardcoded colors warns too.
  • npm test (413), npm run typecheck, npm run lint, npm run format:check all green.

🤖 Generated with Claude Code

An html surface that sets a background/text color to a literal (hex, rgb,
hsl, white/black) instead of a --color-* theme token renders washed-out on
a board in the opposite scheme — e.g. a `background:#fff` note on a dark
board. The guide already forbids this ("dark mode is mandatory"), but the
renderer can't fix it (it can't tell an accidental light card from a
deliberate one), so it goes unnoticed until a human sees the clash.

Flag it back to the author at publish/revise time as a non-blocking
`warnings` array in the API response (same channel as `userFeedback`),
pointing at the theme tokens. Token-driven surfaces and non-html kinds are
unaffected; intentional designs are warned but never blocked.

- server/surfaceLint.ts: findHardcodedColors / lintSurfaces (bg+color only,
  skips var(), SVG fill/stroke, decorative borders)
- thread warnings through publishSurface/reviseSurface + every surface-write
  response
- unit tests (surfaceLint) + API integration tests (publish/revise)

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

1 participant