Generate machine-readable violation report
epic-navigation-and-gesture-accessibility-service-and-audit-task-011 — Implement the violation report serializer in AccessibilityAuditRunner that aggregates all violation records (traversal, keyboard, touch target, navigation contract) into a structured JSON report written to a file path configurable via environment variable. The report schema must include: run timestamp, total violation count, per-category breakdown, and per-violation detail (type, severity, route, widget, description). This file is consumed by the CI pipeline.
Acceptance Criteria
Technical Requirements
Execution Context
Tier 4 - 323 tasks
Can start after Tier 3 completes
Implementation Notes
Define the report schema as a Dart model class (AccessibilityViolationReport) with a toJson() method — do not build the JSON map manually. Use jsonEncode with a custom indent encoder or the json_serializable package if already in the project. Map violation severity to WCAG criteria using a static const map in a WcagCriteriaMapper helper. Read ACCESSIBILITY_REPORT_PATH via Platform.environment['ACCESSIBILITY_REPORT_PATH'] ??
'build/accessibility-audit-report.json'. Wrap each category's serialization in a try/catch and populate the error fields on failure. The runTimestamp should be ISO-8601 UTC. Include appVersion from the package_info_plus package if available, otherwise default to 'unknown'.
This report format will be used by the CI gate in task-012 and must be stable once defined — treat it as a public API.
Testing Requirements
Unit tests: verify schema correctness by deserializing the output and checking all required fields; verify the environment variable path override works; verify directory creation when path does not exist; verify graceful handling of a category with an error (no crash, error field present). Integration test: run a full AccessibilityAuditRunner execution against a test app, call the serializer, read the output file, parse JSON, and assert violation counts match the in-memory AuditResult. Coverage target: 95% of serialization logic. Edge case: test with 0 violations, test with 1000 violations (performance), test with a null wcagCriteria mapping (should default to 'Unknown').
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.