fix(design): canvas token SSOT → WCAG-AA + contrast CI gate (core#2742) #2753

Merged
devops-engineer merged 1 commits from fix/canvas-ssot-aa-contrast into main 2026-06-13 18:47:38 +00:00
Member

Why

The canvas light @theme good #0c8a52 / bad #c2403c fail WCAG AA 4.5:1 on their own 10%-tint badges (axe: 3.87 / 4.46). molecule-app's a11y e2e caught this when it adopted the SSOT (issue #48), so it had to keep a divergent exception — breaking true SSOT convergence.

Fix

Darken to the values that actually pass — good #2a6e44→5.33, bad #b0463f→4.79, ink-soft #656871→4.84 (verified by the new gate). These are the same values molecule-app already uses, so all three surfaces (canvas / mobile-web palette.ts / molecule-app) now converge byte-for-byte on one accessible SSOT. Mobile palette.ts follows in lockstep; palette.ssot.test.ts stays green. Dark mode unchanged (already AA).

CI-wiring

New globals.a11y.test.ts parses globals.css and computes WCAG contrast for the at-risk pairs (text-good/bg-good-10, text-bad/bg-bad-10, ink-soft/surface) — fails CI if the SSOT ever regresses to inaccessible values. Runs in the existing gated canvas vitest suite (no Playwright). 247 mobile + 6 new tests green.

Follow-on

molecule-app can now DROP its AA-exception comment (values already match) — the cross-repo drift gate (#86) will enforce the converged set.

🤖 Generated with Claude Code

## Why The canvas light `@theme` `good #0c8a52` / `bad #c2403c` **fail WCAG AA 4.5:1** on their own 10%-tint badges (axe: **3.87 / 4.46**). molecule-app's a11y e2e caught this when it adopted the SSOT (issue #48), so it had to keep a *divergent* exception — breaking true SSOT convergence. ## Fix Darken to the values that actually pass — **`good #2a6e44`→5.33, `bad #b0463f`→4.79, `ink-soft #656871`→4.84** (verified by the new gate). These are the **same values molecule-app already uses**, so all three surfaces (canvas / mobile-web `palette.ts` / molecule-app) now **converge byte-for-byte on one accessible SSOT**. Mobile `palette.ts` follows in lockstep; `palette.ssot.test.ts` stays green. Dark mode unchanged (already AA). ## CI-wiring New `globals.a11y.test.ts` parses `globals.css` and computes WCAG contrast for the at-risk pairs (text-good/bg-good-10, text-bad/bg-bad-10, ink-soft/surface) — fails CI if the SSOT ever regresses to inaccessible values. Runs in the existing gated canvas vitest suite (no Playwright). 247 mobile + 6 new tests green. ## Follow-on molecule-app can now DROP its AA-exception comment (values already match) — the cross-repo drift gate (#86) will enforce the converged set. 🤖 Generated with [Claude Code](https://claude.com/claude-code)
core-devops added 1 commit 2026-06-13 18:42:36 +00:00
fix(design): make the canvas token SSOT WCAG-AA + add a contrast CI gate (core#2742)
CI / Python Lint & Test (pull_request) Successful in 5s
E2E Peer Visibility (literal MCP list_peers) / detect-changes (pull_request) Successful in 5s
Block internal-flavored paths / Block forbidden paths (pull_request) Successful in 8s
Handlers Postgres Integration / detect-changes (pull_request) Successful in 6s
Lint forbidden tenant-env keys / Scan workspace_secrets writers for forbidden env keys (pull_request) Successful in 5s
Harness Replays / detect-changes (pull_request) Successful in 6s
Lint forbidden tenant-env keys / Scan for repo-host token write into tenant workspace surface (pull_request) Successful in 8s
Secret scan / Scan diff for credential-shaped strings (pull_request) Successful in 7s
sop-checklist / review-refire (pull_request_target) Has been skipped
E2E Peer Visibility (literal MCP list_peers) / E2E Peer Visibility (local) (pull_request) Has been skipped
Handlers Postgres Integration / Handlers Postgres Integration (pull_request) Successful in 3s
reserved-path-review / reserved-path-review (pull_request_target) Successful in 8s
Harness Replays / Harness Replays (pull_request) Successful in 1s
E2E Peer Visibility (literal MCP list_peers) / E2E Peer Visibility (pull_request) Successful in 6s
E2E Chat / detect-changes (pull_request) Successful in 18s
E2E API Smoke Test / detect-changes (pull_request) Successful in 19s
sop-checklist / all-items-acked (pull_request) acked: 0/7 — missing: comprehensive-testing, local-postgres-e2e, staging-smoke, +4 — body-unfilled: comprehensive-testing, local-postgres-e2
gate-check-v3 / gate-check (pull_request_target) Failing after 14s
sop-checklist / na-declarations (pull_request) N/A: (none)
lint-required-no-paths / lint-required-no-paths (pull_request) Successful in 17s
sop-checklist / all-items-acked (pull_request_target) Successful in 11s
E2E Staging Canvas (Playwright) / detect-changes (pull_request) Successful in 22s
CI / Detect changes (pull_request) Successful in 24s
E2E API Smoke Test / E2E API Smoke Test (pull_request) Successful in 2s
E2E Chat / E2E Chat (pull_request) Successful in 3s
E2E Staging Canvas (Playwright) / Canvas tabs E2E (pull_request) Successful in 3s
CI / Platform (Go) (pull_request) Successful in 2s
CI / Shellcheck (E2E scripts) (pull_request) Successful in 2s
Local Provision Lifecycle E2E / Local Provision Lifecycle E2E (stub) (pull_request) Successful in 31s
Local Provision Lifecycle E2E / Local Provision Lifecycle E2E (real image + MiniMax LLM, advisory) (pull_request) Successful in 46s
CI / Canvas (Next.js) (pull_request) Successful in 3m41s
CI / Canvas Deploy Status (pull_request) Successful in 1s
CI / all-required (pull_request) Successful in 4s
reserved-path-review / reserved-path-review (pull_request_review) Successful in 7s
security-review / approved (pull_request_target) Approved via pull_request_review trigger
qa-review / approved (pull_request_target) Approved via pull_request_review trigger
security-review / approved (pull_request_review) Successful in 11s
qa-review / approved (pull_request_review) Successful in 13s
audit-force-merge / audit (pull_request_target) Successful in 6s
bce9fd3a04
The light @theme good #0c8a52 / bad #c2403c failed WCAG AA 4.5:1 on their own
10%-tint badges (axe: 3.87 / 4.46) — molecule-app's a11y e2e caught it after
adopting the SSOT (issue #48), forcing it to keep a divergent exception.

Darken to the values that actually pass (good #2a6e44 → 5.33, bad #b0463f →
4.79, ink-soft #656871 → 4.84) — the SAME values molecule-app already uses, so
all three surfaces (canvas / mobile-web palette / molecule-app) now CONVERGE
byte-for-byte on one accessible SSOT. Mobile palette.ts follows; its
palette.ssot.test stays green. Dark unchanged (already AA).

Adds globals.a11y.test.ts — a vitest gate that parses globals.css and computes
WCAG contrast for the at-risk pairs, so the SSOT can never regress to
inaccessible tokens again (runs in the gated canvas suite, no Playwright).

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
agent-reviewer-cr2 approved these changes 2026-06-13 18:47:11 +00:00
agent-reviewer-cr2 left a comment
Member

APPROVED on head bce9fd3a.

5-axis review:

  • Correctness: canvas light SSOT now uses the same AA-safe values molecule-app already converged on: good #2a6e44, bad #b0463f, ink-soft #656871. Mobile palette follows the canvas good/text3 values, keeping cross-surface parity.
  • Robustness: the new globals.a11y.test parses globals.css and gates the exact regression-prone pairs: text-good on bg-good/10, text-bad on bg-bad/10, and ink-soft on surface/elevated. I independently recalculated the ratios: good 5.33, bad 4.79, ink-soft >5.0, all above WCAG AA 4.5.
  • Security: design-token/test-only surface; no auth, secret, SSRF, or input-validation exposure.
  • Performance: unit-level CSS parsing/contrast math in vitest only; no runtime cost.
  • Readability: comments clearly document the prior failing values, new ratios, and SSOT intent.

Most PR code checks were green at review time, including Platform, shellcheck, E2E smoke/chat/staging canvas, handlers postgres, harness replays, peer visibility, secret scan, and tenant-env lint. CI / Canvas (Next.js) was still pending during review, so keep the merge gate tied to final CI status.

/sop-ack

APPROVED on head bce9fd3a. 5-axis review: - Correctness: canvas light SSOT now uses the same AA-safe values molecule-app already converged on: good #2a6e44, bad #b0463f, ink-soft #656871. Mobile palette follows the canvas good/text3 values, keeping cross-surface parity. - Robustness: the new globals.a11y.test parses globals.css and gates the exact regression-prone pairs: text-good on bg-good/10, text-bad on bg-bad/10, and ink-soft on surface/elevated. I independently recalculated the ratios: good 5.33, bad 4.79, ink-soft >5.0, all above WCAG AA 4.5. - Security: design-token/test-only surface; no auth, secret, SSRF, or input-validation exposure. - Performance: unit-level CSS parsing/contrast math in vitest only; no runtime cost. - Readability: comments clearly document the prior failing values, new ratios, and SSOT intent. Most PR code checks were green at review time, including Platform, shellcheck, E2E smoke/chat/staging canvas, handlers postgres, harness replays, peer visibility, secret scan, and tenant-env lint. CI / Canvas (Next.js) was still pending during review, so keep the merge gate tied to final CI status. /sop-ack
devops-engineer merged commit e14d41bed0 into main 2026-06-13 18:47:38 +00:00
Member

Post-merge audit for PR #2753 (merged head bce9fd3a04c8b3e091780e89d8a2916751fa0ffc): CLEAN.

I independently checked the design-token SSOT contrast changes and the CI gate after merge. The changed light-token ratios all clear WCAG AA 4.5:1: good on bg-good/10 = 5.326, bad on bg-bad/10 = 4.788, ink-soft on surface = 4.839, and ink-soft on elevated white = 5.567. The mobile palette mirror now uses the same AA-hardened ink-soft/good values, so this resolves the canvas-side drift that molecule-app #85 had to document around core#2742.

CI on the merged head includes CI / all-required successful, Canvas Next.js successful, plus the new canvas/src/app/__tests__/globals.a11y.test.ts unit gate. I did not find a contrast or legacy-blue regression in the merged diff.

Post-merge audit for PR #2753 (merged head `bce9fd3a04c8b3e091780e89d8a2916751fa0ffc`): CLEAN. I independently checked the design-token SSOT contrast changes and the CI gate after merge. The changed light-token ratios all clear WCAG AA 4.5:1: `good` on `bg-good/10` = 5.326, `bad` on `bg-bad/10` = 4.788, `ink-soft` on surface = 4.839, and `ink-soft` on elevated white = 5.567. The mobile palette mirror now uses the same AA-hardened `ink-soft`/`good` values, so this resolves the canvas-side drift that molecule-app #85 had to document around core#2742. CI on the merged head includes `CI / all-required` successful, Canvas Next.js successful, plus the new `canvas/src/app/__tests__/globals.a11y.test.ts` unit gate. I did not find a contrast or legacy-blue regression in the merged diff.
Sign in to join this conversation.
No Reviewers
3 Participants
Notifications
Due Date
No due date set.
Dependencies

No dependencies set.

Reference: molecule-ai/molecule-core#2753