critical priority medium complexity backend pending backend specialist Tier 1

Acceptance Criteria

NavigationRouteConfig class exists and compiles without warnings in the Dart/Flutter project
Class exposes a method or getter that returns a typed List<RouteDescriptor> covering all routes declared in the GoRouter instance
RouteDescriptor contains at minimum: routePath (String), routeName (String?), isModal (bool), isRoot (bool), isNonRoot (bool), widgetBuilder reference or type token
Root routes (top-level GoRoute entries) are correctly classified as isRoot=true, isModal=false, isNonRoot=false
Non-root routes (nested GoRoute entries under a parent) are correctly classified as isRoot=false, isModal=false, isNonRoot=true
Modal routes (routes presented via showDialog, showModalBottomSheet, or GoRouter's fullscreenDialog flag) are correctly classified as isModal=true
Routes with StatefulShellRoute (used for bottom nav tabs) are included and classified correctly as root-level shell routes
The reader handles GoRouter instances with at least 10 routes without performance degradation
The returned list is deterministic — same GoRouter config always produces the same list order and values
No runtime exceptions thrown when GoRouter has zero routes (returns empty list)
Unit tests pass for all route classification scenarios
The class is accessible from both NavigationAccessibilityService and AccessibilityAuditRunner without circular imports

Technical Requirements

frameworks
Flutter
GoRouter (go_router package)
apis
GoRouter.configuration
RouteBase
GoRoute
ShellRoute
StatefulShellRoute
data models
RouteDescriptor (new typed value object)
GoRouter configuration tree
performance requirements
Route tree introspection must complete in under 50ms for trees with up to 50 routes
RouteDescriptor list construction must be side-effect free (no setState, no async operations)
security requirements
No route metadata must be logged in release builds — all debug output behind kDebugMode guard
RouteDescriptor must not expose widget constructor parameters that could contain PII

Execution Context

Execution Tier
Tier 1

Tier 1 - 540 tasks

Can start after Tier 0 completes

Implementation Notes

GoRouter exposes its route tree via `GoRouter.configuration.routes` (a `List`). Traverse this list recursively: a `GoRoute` at depth 0 is root, at depth > 0 is non-root, and any `GoRoute` with `fullscreenDialog: true` or detected via a `fullscreenDialogTransitionBuilder` is modal. `ShellRoute` and `StatefulShellRoute` entries should be classified as root and their children processed recursively. Define `RouteDescriptor` as a Dart `@immutable` value class (or `freezed` if the project already uses it) — avoid using plain Maps as return types to maintain type safety downstream.

Do not attempt to instantiate or pump widgets during introspection — work only with the configuration objects. If the project's GoRouter instance is provided via Riverpod, accept a `GoRouter` parameter in the constructor rather than using a global to keep the class testable.

Testing Requirements

Unit tests using flutter_test. Test suite must cover: (1) empty GoRouter config returns empty list, (2) flat list of root GoRoutes all classified as isRoot, (3) nested routes classified as isNonRoot, (4) fullscreenDialog:true GoRoute classified as isModal, (5) StatefulShellRoute children classified correctly, (6) mixed tree with all three route types produces correct classification for each. No integration tests required for this task — the reader is a pure data extraction utility. Target 100% branch coverage on the classification logic.

Component
Navigation Route Configuration
infrastructure 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.