Wire TabStateManager into GoRouter shell navigator
epic-navigation-and-gesture-accessibility-foundation-task-010 — Connect the TabStateManager Riverpod provider to the StatefulShellRoute navigator index. The shell's onNavigationStateChange callback must call tabStateManager.setActiveTab() and tabStateManager.updateStackSnapshot() so router state and Riverpod state remain in sync. Consume the activeTabIndex stream in the bottom navigation bar widget to keep the selected tab indicator current without redundant setState calls.
Acceptance Criteria
Technical Requirements
Execution Context
Tier 3 - 413 tasks
Can start after Tier 2 completes
Implementation Notes
Use ref.listen inside the shell ConsumerStatefulWidget to react to GoRouter's currentConfiguration changes, rather than overriding didChangeDependencies — this avoids double-build issues. The onNavigationStateChange callback in StatefulShellRoute fires before the page animation completes, so updateStackSnapshot should capture the committed route list from the branch navigator's pages list, not from an in-progress transition. Guard against index-out-of-range if GoRouter emits a configuration before TabStateManager is fully hydrated by reading the current state synchronously before subscribing to the stream. Avoid wrapping the entire shell in a rebuild-heavy Consumer; instead, use select() to observe only the integer index so the shell itself does not rebuild when unrelated Riverpod state changes.
Testing Requirements
Unit tests (covered by task-011) verify TabStateManager logic in isolation. Integration tests for this wiring task should use flutter_test with a mock GoRouter and a fake TabStateManager to assert that every navigation event triggers the correct manager calls. Specifically: (1) tap tab 2 → setActiveTab(2) called once, (2) push sub-route on tab 2 → updateStackSnapshot called with correct stack, (3) pop back → updateStackSnapshot updated, (4) navigate to same tab → no duplicate setActiveTab call. Widget tests should pump the shell scaffold and verify the bottom nav selectedIndex matches the stream value without any setState.
StatefulShellRoute branch navigator state can interact unexpectedly with GoRouter's imperative navigation (go, push, replace), causing state snapshots to desync from actual route stacks. This could manifest as a user returning to a tab and seeing a different screen than expected, breaking the core motor-fatigue promise.
Mitigation & Contingency
Mitigation: Write integration tests that simulate cross-tab navigation with nested pushes before any UI layer is built. Pin go_router to a tested minor version and review the StatefulShellRoute changelog before upgrading.
Contingency: If branch navigator state consistently desyncs, fall back to a manual stack snapshot strategy using a custom NavigatorObserver that records and replays navigation events independently of StatefulShellRoute internals.
Persisted navigation stacks in shared_preferences can become stale or corrupt if route paths are renamed during development, causing app crashes or infinite redirect loops on cold start for users who have an old snapshot.
Mitigation & Contingency
Mitigation: Version the persisted schema with a format key. On app start, validate that all stored route paths exist in the current route config before restoring; silently discard invalid entries rather than crashing.
Contingency: Implement a safe-mode cold start that skips state restoration after a detected crash (via a dirty-launch flag written at startup and cleared on successful first frame), falling back to the default root tab.