feat(core): add color/contrast-aa rule - #202
Conversation
|
Here is the review from the general-purpose reviewer for the local diff ( Plumb Code Review —
|
| Check | Status |
|---|---|
No new unsafe outside plumb-cdp |
PASS |
No unwrap/expect/panic! in library crates |
PASS |
No println!/eprintln! outside plumb-cli |
PASS |
No SystemTime::now/Instant::now in plumb-core |
PASS |
No HashMap/HashSet in observable output |
PASS — IndexMap used throughout |
No todo!/unimplemented!/dbg! |
PASS |
| Rule has golden test | PASS — golden_color_contrast_aa.rs + committed snapshot |
Rule registered in register_builtin |
PASS |
docs/src/rules/color-contrast-aa.md present |
PASS |
MCP RULE_DOCS table updated |
PASS |
| SARIF snapshot updated | PASS — ruleIndex incremented correctly |
Layer discipline (plumb-core imports only) |
PASS |
doc_url slug matches explain.rs |
PASS |
| No AI-vocabulary in docs | PASS |
| No commented-out code / open-ended TODOs | PASS |
Correctness
- WCAG 2.1 luminance formula is correct (
palettesRGB linearisation →0.2126R + 0.7152G + 0.0722B). - Large-text cutoffs are correct:
24.0 px(18 pt) and≈18.667 px(14 pt bold, using14 × 96/72). - Boundary fixture exhaustively covers 18 px / 18.6 px / 19 px at
font-weight: 700— all three snapshot entries are consistent with computed ratios. - Porter-Duff compositing is correct; background walk stops at the first opaque ancestor.
- Determinism:
IndexMapthroughout, three-run determinism test present, output sorted by(rule_id, viewport, selector, dom_order). - At most one violation per node per viewport — satisfied.
min_contrast_ratioconfig knob is a floor (ratio.max(...)), not a replacement — confirmed by theconfig.a11y.min_contrast_ratio = Some(7.0)test case.
Verdict: APPROVE
…292) * fix(ci): unstick Preflight + tolerate Dogfood warnings/nextjs flake PR #287 deleted docs/src/ci/release-prep.md and removed the matching guard in tests/install-smoke-validate.sh, but missed the parallel guard in tests/release-security-validate.sh. The validator has been failing on every CI run since 2026-05-07, skipping every downstream job (MSRV, deny, Test, Size, Coverage, Determinism, Docs). Drop the stale RELEASE_PREP_DOC declaration and the corresponding sentinel-grep block. The Homebrew + npm contracts are still validated authoritatively against dist-workspace.toml and install-smoke.yml in sections 5 and 6 of the same script. Two follow-on dogfood fixes since the daily run has been red since 2026-05-02 (after the Phase 7 rule additions in #202/#204/#207): - lint-canonical-docs now tolerates exit 3 (warnings/info only) alongside exit 0, mirroring the test-sites leg in the same workflow. Errors still fail. The 318-violation steady state on the live docs site is a separate content/theme cleanup, not a CI bug. - nextjs leg gets continue-on-error on both plumb invocations to mirror the e2e-sites stance on the upstream chromiumoxide WebSocket flake tracked in #233. Also drops the dead docs/src/ci/release-prep.md reference from the install-smoke.yml header comment. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com> * test(cdp): gate macos_candidate ordering test to unix The `macos_candidate_order_lists_system_apps_then_user_apps` test in crates/plumb-cdp/src/chrome_path.rs asserts that paths returned by `macos_candidates` start with `/Users/example/Applications/...` — forward slashes against `Path::display()`. On Windows, `Path::join` uses `\`, so display[3] becomes `/Users/example\Applications\Google Chrome.app\...` and the starts_with check fails. `detect_with` short-circuits to `None` on non-macOS targets, so the function is never reached in production on Windows. Gate the test to `#[cfg(unix)]` to keep the existing Linux coverage and drop the unreachable Windows leg. This test was previously masked because Preflight has been failing on every CI run since 2026-05-07, which skipped Test (windows-latest) entirely. Surfacing now as a side effect of the validator fix in this same PR. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com> * fix(cdp): gate macos_candidates import to unix in tests Follow-up to 890b14c. Gating the test to `#[cfg(unix)]` left `macos_candidates` as an unused import on Windows, breaking the `Test (windows-latest)` build with `error: unused import: \`macos_candidates\``. Mirror the gate on the import. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com> --------- Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Spec
Closes #68
Summary
color/contrast-aainplumb-corewith WCAG 2.1 AA thresholds, large-text classification, relative-luminance contrast math, and composited background resolution from existing computed styles onlyexplain_ruletableValidation
Confirmed in this environment:
cargo test -p plumb-core --test golden_color_contrast_aa --features test-fake -- --nocapturecargo test -p plumb-core --all-featurescargo test -p plumb-mcp explain -- --nocapturecargo clippy -p plumb-core --all-targets --all-features -- -D warningscargo fmt --all -- --checkcargo check --workspace --all-featuresgit diff --checkEnvironment blockers:
cargo test -p plumb-corewithout--all-featuresfails in this repo because integration tests callPlumbSnapshot::canned(), which is gated behindplumb-core/test-fakecargo xtask pre-releasefails here because Python lacks theyamlmodule required by the runbook validatorjust validatecannot run here becausejustis not installedBreaking change?
Anything reviewers should double-check
a11y.min_contrast_rationow acts as a stricter global floor on top of WCAG AA defaults; the default behavior remains fixed at4.5:1for normal text and3.0:1for large text.