Repository navigation
A11Y-001: an icon-only control's icon is visible at 3:1 - #1011
Conversation
WCAG 1.4.11: a control whose only visible form is its icon needs 3:1 against the page. 24 icon-only buttons (row delete, star, "more", rename, autopay, mark paid) painted their icon --muted at 40-60%: 1.76-2.44:1 in the light theme. They are full --muted now (5:1 or better); hover still lifts them to their action colour. The bills autopay toggle showed whether it is on only by colour; it says so now (aria-pressed). tests/an-icon-only-control-is-visible.test.ts finds, with the TypeScript parser, every button or link with no text whose icon is text-muted/NN and fails any under 3:1 but the sidebar's pin button (not changed here). It names exactly these 24 on main. tests/helpers/faded-text.ts is the same file #1010 adds. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01TRY21ZKsFrfB3qtoP972A4
|
The latest updates on your projects. Learn more about Vercel for GitHub. |
|
Audit ownership dependency at410be11678a9f066ff805caf59c924020a2ec461: tests/helpers/faded-text.ts duplicates #1010's helper, whose disabled/aria-hidden scanner semantics are already linked to the existing #1009 repair task6106505026 via #1010 receipt6106617757. Please preserve one owner for that shared helper and its scanner fixtures, then integrate the same reviewed repair across the dependent branches. This is a dependency receipt, not a third parallel implementation assignment. Keep the existing limitation on plain-ground arithmetic and unmeasured actual consumer states explicit. Source review of the separate icon-control edits is continuing. No merge, deployment or production changes. |
…ive or hidden; calendar chips keep contrast on hover Owner round 6106505026 on #1009. 1. The scanner moves to tests/helpers/faded-text.ts, shared by #1010 and #1011 (the same file in each). It exempts an element only when aria-hidden or disabled is written bare, "true" or {true}; false and dynamic values are scanned, and cursor-not-allowed alone is a look, not a state. It follows a class held in a same-file const, or a const map of them; imports, functions and run-time strings are outside it, and say so. New fixture tests run each case through the real scanner. Two sites it now finds: - check-in: busy === s && 'opacity-60' never applied (the button is disabled then, and its disabled:opacity-50 wins); removed. - photos upload area: the busy fade is tied to the state it marks, aria-disabled:opacity-60 and aria-disabled:cursor-not-allowed. 2. Calendar chips: hover:brightness-110 brightens the chip's own layer, its ink and its 20% tint, but not the page behind the tint. Rendered in Chromium on the light theme it took medication from 4.75 to 4.14, general 4.95 to 4.38 and school 5.08 to 4.49. The three chips lift with hover:shadow-md, which changes neither colour. The test reads every category from CATEGORY_COLORS, takes the light palette from globals.css and the dark one from Tailwind, composes each over every ground, and its control reproduces exactly those three under the old filter. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01TRY21ZKsFrfB3qtoP972A4
|
Exact-head CI follow-up for the existing icon-control owner: 410be11 run38121836268 has Core job114417980051 failing at unit step11. Database/mobile passed; E2E114417979939 was still running when checked. Metadata does not establish the cause. Please diagnose using your authorized test/evidence access, preserve the assertions, and return the failing case plus any repair commit and exact-head rerun. Keep shared faded-text helper changes coordinated through6106737047 and the existing #1009/#1010 scanner task rather than creating another implementation. The scoped source review found no new semantic/permission regression in the24 color replacements and autopay pressed state. The icon guard still excludes custom Button components, treats screen-reader-only labels as visible text, and its self-test does not exercise the full scanner; retain those coverage limits. No blocked-log reroute, merge, deployment or production changes requested. |
… and #1010 tests/helpers/faded-text.ts is the same file in #1009, #1010 and #1011, so they merge in any order. Its exemptions are now literal-only (aria-hidden or disabled written true) and it follows same-file const aliases; this PR's icon guard uses only carriesText and the contrast arithmetic from it, and still names the same 24 controls on main. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01TRY21ZKsFrfB3qtoP972A4
… disabled; trust-matrix defaults in full colour Owner round 6106617757 on #1010. tests/helpers/faded-text.ts is now the one scanner #1009, #1010 and #1011 share (the same file in each): an element is exempt only when aria-hidden or disabled is written bare, "true" or {true}; false and dynamic values are scanned; cursor-not-allowed is not a state; same-file const aliases are followed, imports and functions are not. Fixture tests run literal, false and dynamic states through the real scanner. Two sites it now finds: - Trust matrix: a manager's cells are buttons, and a role default was drawn faint (deny at --muted 40%: 1.76:1; allow at green 50% and approval at amber 60%: 2.3 and 3.5 in light). Defaults already differ from overrides by background and border; they are full colour now, and the cell's hover:brightness-125 is a shadow. - An unavailable plan write-back: allowed, since its faint style applies only when !o.available, which also disables the button (pinned). Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01TRY21ZKsFrfB3qtoP972A4
…resolves a class name by its scope Owner round 6106866711 on #1009. - disabled exempts only an element it disables: a native form control, or the design system's <Button>, which renders a <button>. <p disabled> stays visible and is scanned (new fixtures: <p>, <span disabled={true}> found; <button>, <Button> exempt). - A name in a className resolves to its nearest binding by lexical scope, not to one file-wide map. Two components' same-named consts each answer for their own component, whichever comes first; an inner const shadows the module's; a nearer parameter, loop or destructured binding is that binding and leaves the name outside the guard rather than "clear". A ?: of literal strings is read in both arms. Fixtures cover each. The repo-wide guard finds no new site. tests/helpers/faded-text.ts is the same file in #1010 and #1011. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01TRY21ZKsFrfB3qtoP972A4
…plate; the shared helper follows #1009 CI (run 38122416679, job 114419835471) failed account-creation-integrity: its ratchet forbids {t('key') inside a template literal, the shape that once mailed a key name verbatim, and this PR's self-test wrote one as a fixture string. The fixture uses {label} now; it tests the same thing (a control with words beside its icon is not icon-only). tests/helpers/faded-text.ts is again the same file as #1009 and #1010 (exemptions limited to controls that can be disabled; names resolved by scope). This PR's guard uses only carriesText and the arithmetic, and still names the same 24 controls on main. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01TRY21ZKsFrfB3qtoP972A4
|
Re 6106802902 and 6106737047: the failure was this PR's, fixed in The failing case. Core (run 38121836268, job 114417980051, and again in run 38122416679, job 114419835471) failed
One helper owner. Coverage limits, kept and stated
Checks at Generated by Claude Code |
A11Y-001, WCAG 1.4.11 (non-text contrast): a control whose only visible form is its icon needs 3:1 against the page.
The defect
24 icon-only buttons painted their icon
--mutedat 40–60%. In the light theme that reads 1.76:1 (at 40%), 2.05 (at 50%) and 2.44 (at 60%), at the worst ground.The fix
--muted(5:1 or better). Hover still lifts them to their action colour (danger, emerald,--fg). Hover-revealed buttons keep A11Y-001: a row action revealed on hover also shows on keyboard focus and touch #1005's reveal classes.aria-pressed.Tests
tests/an-icon-only-control-is-visible.test.ts:button, link,ButtonLinkorsummarythat renders no text and whose icon (or itself) is paintedtext-muted/NN. Any below 3:1 on a plain ground in either theme fails. The only exception is the sidebar's pin button, which I have not touched, so it is your call.--mutedat 40, 50 and 60%, and at full strength.aria-pressed.tests/helpers/faded-text.tsis the one scanner helper shared with #1009 and #1010, byte-identical; its exemption and scope rules are reviewed on #1009. This guard uses only itscarriesTextand contrast arithmetic.mainebe03c2tests/, incl.account-creation-integrity(5d8acb8)npm run lintmainCI. The first two heads failed
account-creation-integrity, which was mine: a self-test fixture wrote{t('delete')}inside a template literal, the shape that ratchet forbids. Fixed in5d8acb8with{label}; no assertion changed.Coverage limits
button, links,ButtonLinkandsummary, but not the design system's<Button>or other custom components.sr-onlyspan counts as text, so a control whose only words are screen-reader-only is not treated as icon-only.carriesText, not the whole scanner.No migration, configuration or dependency change.
🤖 Generated with Claude Code
https://claude.ai/code/session_01TRY21ZKsFrfB3qtoP972A4