openpencil/apps
Fini 0bbdb0bf35 fix(ai): button contrast resolves \$color refs via built-in semantic palette
Codex flagged the previous fix (1c08ac3f, "skip on unresolved ref")
as too conservative: a sub-agent's button with `\$color-accent` bg
and a text child WITHOUT a fill ended up with no fill at all when
doc.variables hadn't been seeded yet — text falls back to black,
which is invisible on a dark accent button.

Better fix: extend `resolveColorMaybeRef` with a step-2 fallback
into the built-in semantic palette (`getSemanticPaletteHex`). Every
core token (`color-accent`, `color-bg`, `color-text-primary`, etc.)
has a known hex for both `Light` and `Dark` modes, so the cascade
now is:
  1. Doc-seeded variables (user's palette).
  2. Built-in semantic palette for the requested mode.
  3. Original ref string (unresolvable) — caller bails.

In the food-app + GPT-5.5 path, step 1 already worked because
`seedDocVariablesFromStyleGuide` runs before the sub-agents.
The fallback is for paths that bypass seeding (test fixtures,
external MCP callers, mid-flight states), not the common case.

Skip-on-NaN behavior stays — it now only triggers for genuinely
unknown tokens (`\$color-foobar` or similar), where any guess is
worse than leaving the model's existing fill alone.

Tests:
- New: `\$color-accent` ref resolves to #2563EB via semantic palette
  even with no doc.variables, contrast pass picks white fg correctly
  for the unfilled text child.
- New: `\$color-mystery-token` (not in palette) — step-2 misses,
  contrast pass skips, existing text fill survives.
- Replaces the prior "skips on unresolved" test which over-asserted
  the conservative path.
2026-05-05 12:22:49 +08:00
..
cli Merge origin/v0.8.0 into feat/rust-ification 2026-05-03 21:00:00 +08:00
desktop Merge origin/v0.8.0 into feat/rust-ification 2026-05-03 21:00:00 +08:00
web fix(ai): button contrast resolves \$color refs via built-in semantic palette 2026-05-05 12:22:49 +08:00