Implement debug console warning surface
epic-navigation-and-gesture-accessibility-service-and-audit-task-006 — Implement the debug-mode warning dispatcher in NavigationAccessibilityService that surfaces all collected AccessibilityViolation records to the development console using flutter/foundation debugPrint with structured formatting. In release builds this code path must be entirely stripped (kDebugMode guard). Warnings should include route name, violation type, and a plain-language remediation hint.
Acceptance Criteria
Technical Requirements
Execution Context
Tier 5 - 253 tasks
Can start after Tier 4 completes
Implementation Notes
The kDebugMode constant from flutter/foundation is a compile-time constant in release builds, so the Dart compiler and tree-shaker will eliminate the entire block — but only if the guard is structured as `if (kDebugMode) { ... }` and not stored in a variable first. Do not use `assert(() { ... }())` as this can behave differently from kDebugMode in profile mode.
For the runAllChecksAndWarn() convenience method, collect all three violation lists into a combined list and call dispatchWarnings once to allow a single summary header line before the individual violations. Consider prefixing each line with a severity indicator (🔴 for critical accessibility violations, 🟡 for high) — but only if the team's debug console convention already uses emoji; otherwise use plain ASCII prefixes like [CRITICAL] and [HIGH] to maintain consistency with the rest of the codebase.
Testing Requirements
Unit tests using flutter_test. Scenarios: (1) dispatchWarnings([]) in debug mode → zero debugPrint calls, (2) dispatchWarnings([violation]) in debug mode → one debugPrint call containing route path, violation type, and remediation hint, (3) dispatchWarnings([v1, v2, v3]) → three separate debugPrint calls, each containing correct violation data, (4) simulate release mode (override kDebugMode or extract the guard into a testable helper) → zero output for non-empty list, (5) runAllChecksAndWarn() with no violations → zero output, (6) runAllChecksAndWarn() with known mock violations from all three verifiers → correct combined output. Use a captured output buffer or a spy on debugPrint to assert output content without relying on stdout parsing.
Flutter's SemanticsController used in integration tests is an internal or semi-internal API that can break between Flutter stable releases. If the audit runner relies heavily on undocumented semantics tree traversal, a Flutter upgrade could silently disable the audit checks without a build failure, creating false confidence.
Mitigation & Contingency
Mitigation: Use only the public flutter_test accessibility APIs (meetsGuideline, SemanticsController.ensureSemantics) and wrap all SemanticsController calls in a versioned helper class with explicit assertions that the expected semantics tree shape is still available. Pin the Flutter SDK range in pubspec.yaml.
Contingency: If SemanticsController APIs break on a Flutter upgrade, fall back to widget-level golden tests that include the semantics tree snapshot, combined with manual Switch Access and VoiceOver QA checklists executed before each release.
Flutter integration tests that simulate Switch Access traversal on multiple screens can be slow (30–120 seconds per test flow), which may make the audit runner impractical to run on every CI commit if the test suite already has long run times.
Mitigation & Contingency
Mitigation: Scope the audit runner to a dedicated integration test target that runs on pull requests targeting main and on nightly builds, not on every push. Parallelise test shards in CI to keep wall-clock time acceptable. Profile audit run times during development and trim any flows that duplicate coverage.
Contingency: If CI run times exceed acceptable thresholds, split the audit runner into a fast smoke suite (touch targets and semantic labels only, runs on every PR) and a thorough traversal suite (Switch Access simulation, runs nightly), with the nightly failure blocking the release branch rather than every PR.