high priority low complexity infrastructure pending infrastructure specialist Tier 2

Acceptance Criteria

Every `GoRoute` in `NavigationRouteConfig` has an associated `RouteMetadata` entry in a `_metadataMap` (or equivalent) keyed by route path
A public `RouteMetadata? routeMetadataFor(String location)` function (or static method) returns the correct metadata for any declared route path
`routeMetadataFor` returns `null` for unknown routes — callers must handle the null case gracefully
`routeMetadataFor` strips query parameters and path parameters before lookup (e.g., `/contacts/detail/123` resolves to the metadata for `/contacts/detail/:id`)
All `semanticsLabel` strings are in Norwegian Bokmål (the app's primary locale) and pass a manual screen reader review
`suppressSwipeBack` is `true` for every route without exception — confirmed by iterating `_metadataMap` in a test
`semanticsIdentifier` values match the stable identifiers defined in task-004 — no new identifiers are invented here
The lookup function does not import GoRouter — it operates only on string path matching
WCAG 2.2 AA: `semanticsLabel` values announce the destination screen name (e.g., 'Hjem', 'Kontakter', 'Legg til') not technical route names

Technical Requirements

frameworks
Flutter
Dart
data models
RouteMetadata
RouteConstants
performance requirements
`routeMetadataFor` must resolve in O(1) or O(n) where n is the number of route segments — not a full route tree traversal
Metadata map is constructed once at startup (const or lazy singleton), never rebuilt on each navigation event
security requirements
No user-specific or role-specific data stored in route metadata — metadata is static and the same for all users

Execution Context

Execution Tier
Tier 2

Tier 2 - 518 tasks

Can start after Tier 1 completes

Implementation Notes

Implement `routeMetadataFor` using a two-pass approach: first try exact match, then attempt path-pattern matching by replacing path segments that look like IDs (UUID pattern or numeric) with the `:param` placeholder from the declared route pattern. A simple regex `RegExp(r'[0-9a-f-]{8,}|\d+')` on each segment is sufficient. Keep `_metadataMap` as a `const Map` where possible — all values are compile-time constants if `RouteMetadata` uses a `const` constructor. The `NavigationAccessibilityService` (a separate component) will call this function on every `GoRouter` `routerDelegate.currentConfiguration` change — keep the lookup fast.

Norwegian labels must be reviewed with a native speaker; use the organization's own terminology from the workshop notes (e.g., 'Aktiviteter' not 'Arbeid' if that is what HLF uses).

Testing Requirements

Unit tests in `test/navigation/route_metadata_test.dart`: (1) Call `routeMetadataFor` for each of the five tab roots and assert non-null result with correct `semanticsLabel`. (2) Call `routeMetadataFor('/contacts/detail/abc123')` and assert it matches the parameterized route metadata. (3) Call `routeMetadataFor('/unknown/path')` and assert `null` return. (4) Iterate all entries in the metadata map and assert `suppressSwipeBack == true` for every entry (regression guard).

(5) Assert `semanticsIdentifier` values are non-empty and contain no whitespace. Coverage target: 100% of the lookup function's branches.

Component
Navigation Route Configuration
infrastructure medium
Epic Risks (2)
high impact medium prob technical

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.

medium impact medium prob technical

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.