Inline Contextual Help Widget implementation
epic-cognitive-accessibility-foundation-task-014 — Implement the InlineContextualHelpWidget Flutter widget that displays context-sensitive help text from the HelpContentRegistry. Renders as a small info icon that expands inline (not a modal) to show ≤80-word plain-language explanation. Fully accessible with semantic labels, keyboard focus management, and screen reader announcements. Help content is resolved via PlainLanguageContentService with org-specific terminology overrides applied automatically.
Acceptance Criteria
Technical Requirements
Execution Context
Tier 2 - 518 tasks
Can start after Tier 1 completes
Implementation Notes
Use a StatefulWidget (not a Cubit) because the expanded/collapsed state is purely local UI state with no persistence or cross-widget coordination needed — this keeps the widget self-contained. Use AnimatedSize wrapped around the help text container for smooth height animation without requiring an explicit animation controller. To move focus to the help text on expand, call FocusScope.of(context).requestFocus(helpTextFocusNode) inside a post-frame callback (WidgetsBinding.instance.addPostFrameCallback) so the widget is fully laid out before focus is applied. Do NOT use a Tooltip widget for this feature — Flutter Tooltips are shown on long-press only and are not accessible on touch-primary devices.
The ≤80-word constraint should be enforced at registry load time (a lint/test), not at render time, so the widget does not need truncation logic.
Testing Requirements
Write flutter_test widget tests covering: (1) widget renders icon-only when collapsed, (2) tap expands panel and shows resolved help text, (3) second tap collapses panel, (4) Semantics label changes between 'Show help' and 'Hide help' based on state, (5) focus moves to help text node on expansion (use FocusManager in test), (6) widget renders SizedBox.shrink() when helpKey has no registry entry, (7) text scale factor 2.0 does not cause overflow, (8) icon touch target bounding box is ≥44dp in both axes. Include a golden test for both collapsed and expanded states at 1.0 and 1.5 text scale. Target 100% line coverage.
The error message registry and help content registry both depend on bundled JSON assets loaded at startup. If asset loading fails silently (e.g. malformed JSON, missing pubspec asset declaration), the entire plain-language layer falls back to empty strings or raw error codes, breaking the accessibility guarantee app-wide.
Mitigation & Contingency
Mitigation: Implement eager validation of both assets during app initialisation with an assertion failure in debug mode and a structured error log in release mode. Add integration tests that verify asset loading in the Flutter test harness on every CI run.
Contingency: Ship a hardcoded minimum-viable fallback message set directly in Dart code so the app always has at least a safe generic message, preventing a blank or code-only error surface.
The AccessibilityDesignTokenEnforcer relies on dart_code_metrics custom lint rules. If the lint toolchain is not already configured in the project's CI pipeline, integrating a new linting plugin may cause unexpected build failures or require significant CI configuration work beyond the estimated scope.
Mitigation & Contingency
Mitigation: Audit the existing dart_code_metrics configuration in the project before starting implementation. Scope the lint rules to a separate Dart package that can be integrated incrementally, starting with the most critical rule (hard-coded colors) and adding others in subsequent iterations.
Contingency: Fall back to Flutter test-level assertions (using the cognitive-accessibility-audit utility) to catch violations in CI if the lint plugin integration is delayed, preserving enforcement coverage without blocking the epic.
WizardDraftRepository must choose between shared_preferences and Hive for local persistence. Choosing the wrong store for the data volume (e.g. shared_preferences for complex nested wizard state) can lead to serialisation bugs or performance degradation, particularly on lower-end Android devices used by some NHF members.
Mitigation & Contingency
Mitigation: Define a clean repository interface first and implement shared_preferences as the initial backend. Profile serialisation round-trip time with a realistic wizard state payload (≈10 fields) before committing to either store.
Contingency: Swap the persistence backend behind the repository interface without touching wizard UI code, which is possible precisely because the repository abstraction isolates the storage detail.
The AccessibilityDesignTokenEnforcer scope could expand significantly if a large portion of existing widgets use hard-coded values. Discovering widespread violations during this epic would force either a major refactor or a decision to exclude legacy components, potentially reducing the enforcer's coverage and value.
Mitigation & Contingency
Mitigation: Run a preliminary audit of existing widgets using a simple grep for hard-coded hex colors and raw pixel values before implementation begins. Use the results to set a realistic remediation boundary for this epic and log all out-of-scope violations as tracked tech-debt items.
Contingency: Scope the enforcer to new and modified components only (via file-path filters in dart_code_metrics config), shipping a partial but immediately valuable coverage rather than blocking the epic on full-codebase remediation.