Implement WCAG 2.2 relative luminance algorithm in Dart
epic-visual-design-accessibility-foundation-task-008 — Implement the Contrast Ratio Validator core logic using the WCAG 2.2 relative luminance algorithm in Dart. The function must accept two Color values, compute relative luminance per the IEC 61966-2-1 formula, and return the contrast ratio as a double. This is the mathematical foundation for all subsequent validation.
Acceptance Criteria
Technical Requirements
Implementation Notes
Place the implementation in `lib/core/accessibility/contrast_ratio_calculator.dart` (or equivalent path under `src/`). Keep the file free of any Flutter widget imports so it can be used in CLI dart scripts — import only `dart:ui` for the Color type, or accept raw RGB int values and provide a factory constructor that takes a Flutter Color. The IEC 61966-2-1 linearization formula is the most commonly mis-implemented part: the exponent is 2.4, not 2.2, and the threshold is 0.04045, not 0.03928 (the older WCAG 2.0 value). Use the 2.4/0.04045 values for WCAG 2.2 compliance.
Avoid using `dart:math` `pow()` in a hot loop — it is fine here since this is not called in build methods, but document the performance characteristic. Consider exposing both `relativeLuminance` and `contrastRatio` as top-level functions (not class methods) for ease of use in tests and scripts.
Testing Requirements
Write flutter_test unit tests covering: (1) white (#FFFFFF) on black (#000000) = 21.0 ±0.001, (2) black on white = 21.0 ±0.001 (symmetric), (3) mid-grey (#777777) on white — compute expected value manually and assert within 0.01, (4) identical colors = 1.0, (5) WCAG sample pair #595959 on white = 7.0 (AA large pass), (6) negative: #AAAAAA on white = ~2.32 (AA fail). Use `closeTo` matcher for all floating-point assertions. 100% branch coverage on the linearization branch (<=0.04045 vs >0.04045 paths).
The WCAG 2.2 relative luminance formula requires gamma-corrected sRGB calculations. Floating-point rounding differences between Dart and reference implementations could produce off-by-one classifications for near-threshold color pairs, resulting in pairs that just pass or just fail in CI but behave differently at runtime.
Mitigation & Contingency
Mitigation: Implement the algorithm directly from the WCAG 2.2 specification using the exact linearisation constants. Validate the Dart implementation against the W3C reference test vectors and against a known-good JavaScript implementation for at least 50 color pairs spanning the compliance boundaries.
Contingency: If discrepancies are found, add a configurable tolerance margin (e.g., ±0.005 on the ratio) and flag near-threshold pairs as warnings rather than hard failures, escalating to the design team for manual review.
The token manifest is a static data file. If developers add new color tokens to the design-token-provider without updating the manifest, the manifest becomes stale and the CI validator produces false negatives — passing builds that contain unvalidated color pairs.
Mitigation & Contingency
Mitigation: Add a CI step that cross-references every token constant exported by the design-token-provider against the manifest at build time, failing if any token is present in the provider but absent from the manifest. Document this requirement clearly in the contributing guide.
Contingency: If drift is detected post-merge, run a full manifest regeneration script and treat the resulting manifest diff as a blocking pull request with mandatory accessibility review.
The flutter_accessibility_lints package (or custom lint rules) may produce false positives on patterns the team deliberately uses — for example, decorative icon widgets that intentionally omit semantic labels. Excessive false positives will lead developers to add blanket ignore comments, undermining the entire lint strategy.
Mitigation & Contingency
Mitigation: Audit the full lint rule set against the existing codebase before enabling rules. Create a documented list of approved ignore-comment patterns with mandatory justification comments. Restrict ignore patterns to decorative-only contexts.
Contingency: If false positive rates exceed 10% of lint output, disable the highest-noise individual rules and replace them with targeted custom lint rules scoped to the specific patterns the team controls.