Integrate audit runner into CI pipeline gate
epic-navigation-and-gesture-accessibility-service-and-audit-task-012 — Configure the CI pipeline (GitHub Actions or equivalent) to run the AccessibilityAuditRunner integration test as a required check. The pipeline step must: start a Flutter integration test session targeting the audit runner entry point, assert exit code 0 only when the violation report contains zero violations, archive the JSON report as a build artifact on every run, and block PR merge on failure. Include documentation of how to interpret the report and suppress false positives with inline annotations.
Acceptance Criteria
Technical Requirements
Execution Context
Tier 6 - 158 tasks
Can start after Tier 5 completes
Implementation Notes
The CI workflow step for violation checking should use a shell script: `VIOLATIONS=$(jq '.totalViolations' build/accessibility-audit-report.json); if [ "$VIOLATIONS" != '0' ]; then echo 'Accessibility violations found: '$VIOLATIONS; exit 1; fi`. For the false-positive suppression mechanism, use a SemanticsSuppression annotation class that the audit runner reads from the widget tree via the SemanticsConfiguration.tagForChildren mechanism — this avoids string-scanning source files. The PR comment step should only run when the audit fails (if: failure()) to avoid noise on passing PRs. Ensure the Flutter integration test is run with --dart-define=ACCESSIBILITY_REPORT_PATH=build/...
rather than relying on shell env var export to avoid cross-platform issues. This gate enforces WCAG 2.2 AA compliance continuously — a commitment to all three client organizations (NHF, Blindeforbundet, HLF) who specified accessibility as a MUST HAVE in Phase 1.
Testing Requirements
Manual verification: create a PR with a known accessibility violation and confirm the CI step fails and posts a comment; create a PR with no violations and confirm the step passes and the report is still archived. Automated test for the report-parsing shell script: provide a sample JSON with totalViolations=0 and assert exit 0; provide one with totalViolations=3 and assert exit 1; provide malformed JSON and assert exit 1. Document the test in the CI workflow file as inline comments. Regression test: after adding a suppression annotation, confirm the suppressed violation no longer appears in the report.
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.