high priority medium complexity backend pending backend specialist Tier 4

Acceptance Criteria

NavigationAccessibilityService has a verifyNoHorizontalSwipe() method (or equivalent) that returns List<AccessibilityViolation>
A route containing a GestureDetector with onHorizontalDragUpdate/onHorizontalDragEnd produces at least one HorizontalSwipeViolation
A route containing a PageView with scrollDirection: Axis.horizontal produces at least one HorizontalSwipeViolation
A route using a CupertinoPageRoute or swipe-back transition that enables edge-swipe navigation produces at least one HorizontalSwipeViolation
A route with a PageView that uses scrollDirection: Axis.vertical produces zero violations (vertical scroll is permitted)
A route with no gesture detectors or horizontal scroll produces zero violations
Violation records use ViolationType.HorizontalSwipeDetected and include the route path and a description of the specific widget type found
remediationHint references the workshop requirement: 'Replace gesture-based navigation with explicit button controls per accessibility guidelines'
All three verifiers (modal, back, swipe) can be called in sequence on the same service instance and their violation lists are independent
Unit tests pass covering all detected and non-detected scenarios

Technical Requirements

frameworks
Flutter
apis
GestureDetector (onHorizontalDragUpdate, onHorizontalDragEnd)
PageView (scrollDirection)
CupertinoPageRoute
Dismissible (direction: DismissDirection.horizontal)
NavigationRouteConfig (task-002)
data models
AccessibilityViolation (shared)
ViolationType.HorizontalSwipeDetected
RouteDescriptor
performance requirements
Swipe detection across up to 30 routes must complete in under 150ms
Detection logic must not instantiate or pump any widgets
security requirements
No widget state or user-visible content included in violation records
Output gated behind kDebugMode (enforced in task-006)

Execution Context

Execution Tier
Tier 4

Tier 4 - 323 tasks

Can start after Tier 3 completes

Implementation Notes

Horizontal swipe detection without live widget pumping is most reliably achieved via the registration pattern: swipe-using widgets register themselves at startup (or the team adds a lint rule / static analysis check). If widget introspection is chosen, call the route builder with a mock context and walk the tree checking widget runtimeType. The workshop document (likeperson.md, section 1.2) explicitly states 'tilbakeknapp fremfor sidelengs-sveip' and 'vertikal scroll er normen' — this is a hard accessibility requirement driven by motor and cognitive accessibility needs of NHF, Blindeforbundet, and HLF users. Note that the StatefulShellRoute bottom tab bar uses horizontal tab switching internally in Flutter — this should be explicitly excluded from the check via a known-exempt widget registry to prevent false positives on the standard tab navigation pattern.

Testing Requirements

Unit tests using flutter_test. Scenarios: (1) route with GestureDetector(onHorizontalDragEnd) → one violation, (2) route with PageView(scrollDirection: Axis.horizontal) → one violation, (3) route with Dismissible(direction: DismissDirection.horizontal) → one violation, (4) route with PageView(scrollDirection: Axis.vertical) → zero violations, (5) route with GestureDetector(onVerticalDragEnd only) → zero violations, (6) route with no gesture detectors → zero violations, (7) CupertinoPageRoute usage → one violation, (8) multiple routes with mixed swipe usage → correct violation count per route. Test that violation descriptions identify the specific widget type found (PageView vs GestureDetector vs CupertinoPageRoute).

Component
Navigation Accessibility Service
service medium
Epic Risks (2)
high impact medium prob dependency

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.

low impact medium prob resource

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.