critical priority medium complexity frontend pending frontend specialist Tier 2

Acceptance Criteria

A DeclarationAcknowledgementCubit is implemented with sealed states: AcknowledgementInitial, AcknowledgementSubmitting, AcknowledgementSuccess, AcknowledgementError
On submit button tap, the cubit receives the ISO 8601 timestamp recorded in task-006 and the declaration ID from the route parameter
The cubit calls DeclarationAcknowledgementService.recordAcknowledgement(declarationId, driverId, timestamp) with the authenticated driver's user ID from Supabase Auth current session
In AcknowledgementSubmitting state, the submit button shows a loading spinner and is disabled, and a Semantics live region announces 'Submitting your acknowledgement...'
In AcknowledgementSuccess state, a live region announces 'Acknowledgement recorded successfully', and the screen navigates back to the driver assignment list using router.pop() after a 300ms delay
On successful navigation back, the driver assignment list refreshes and the relevant assignment's DeclarationStatusBadge updates to 'acknowledged' status
In AcknowledgementError state, an accessible error message is displayed inline (not a dialog), the submit button is re-enabled, and a live region announces 'Failed to record acknowledgement. Please try again.'
The declaration_acknowledgement record written to the database includes: declaration_id, driver_id (from authenticated session), acknowledged_at (UTC ISO 8601), fully_scrolled = true
Unit tests cover all cubit state transitions with mocked DeclarationAcknowledgementService
Widget tests verify UI reflects each state and that navigation occurs on success

Technical Requirements

frameworks
Flutter
BLoC
Riverpod
apis
DeclarationAcknowledgementService (recordAcknowledgement)
Supabase Auth (currentUser.id)
Supabase PostgreSQL 15 (declaration_acknowledgement insert)
data models
declaration_acknowledgement
confidentiality_declaration
performance requirements
Service call must complete or timeout within 10 seconds — implement a timeout on the Future
Navigation back and list refresh must complete within 500ms of success response
security requirements
Driver ID must be sourced exclusively from Supabase Auth current session — never from route parameters or widget state passed from parent
The acknowledgement record must be inserted via a server-side Supabase Edge Function or RLS-protected table insert — the mobile client must not be able to forge another driver's acknowledgement
Supabase RLS policy must restrict insert on declaration_acknowledgement to rows where driver_id = auth.uid()
Timestamp must be validated server-side to be within a reasonable window (e.g., not more than 1 hour before submission) to prevent replay of stale acknowledgements
ui components
DeclarationAcknowledgementCubit
Semantics live region (SemanticsService.announce)
AppButton (submit with loading state)
InlineErrorWidget
DeclarationStatusBadge (refreshed on success)

Execution Context

Execution Tier
Tier 2

Tier 2 - 518 tasks

Can start after Tier 1 completes

Implementation Notes

The cubit's submitAcknowledgement(String declarationId, DateTime timestamp) method should: (1) emit AcknowledgementSubmitting, (2) fetch driverId from Supabase Auth (supabase.auth.currentUser?.id) — if null, emit AcknowledgementError immediately, (3) call the service, (4) emit AcknowledgementSuccess or AcknowledgementError. For the list refresh on navigation back, use a Riverpod invalidate on the driver assignment list provider (e.g., ref.invalidate(driverAssignmentListProvider)) before calling router.pop() — this triggers a data refresh when the list screen regains focus. Do not use a GlobalKey or a callback to refresh the parent — the Riverpod invalidation pattern is cleaner. For the 300ms navigation delay on success, use Future.delayed(const Duration(milliseconds: 300), () => router.pop()) to let the success announcement be heard by screen readers before the screen disappears.

Testing Requirements

Unit tests for DeclarationAcknowledgementCubit using bloc_test. State transition tests: initial → submitting → success, initial → submitting → error, error → submitting → success (retry). Mock DeclarationAcknowledgementService and Supabase Auth using Mockito or Mocktail. Widget tests: (1) submit triggers AcknowledgementSubmitting state, (2) success state triggers navigation pop, (3) error state shows inline error and re-enables button, (4) live region semantics announcements present in each state.

Integration test verifying Supabase insert creates a valid declaration_acknowledgement record with correct fields is recommended as a separate test file.

Epic Risks (3)
high impact medium prob technical

The declaration acknowledgement screen has the most complex accessibility requirements of any screen in this feature: scrollable long-form legal text, a conditional checkbox that is only enabled after reading, and a timestamp capture. Incorrect focus management or missing semantics annotations could fail VoiceOver navigation or cause the screen reader to announce the checkbox as available before the driver has scrolled, undermining the legal validity of the acknowledgement.

Mitigation & Contingency

Mitigation: Build the acknowledgement screen against the WCAG 2.2 AA checklist from the start, not as a post-hoc audit. Use semantics-wrapper-widget and live-region-announcer from the platform's accessibility toolkit. Include a VoiceOver test session in the acceptance criteria with a tester using the screen reader.

Contingency: If WCAG compliance cannot be fully achieved within the sprint, ship the screen with a documented list of accessibility gaps and a follow-up sprint commitment. Do not block the declaration workflow launch if the core interaction works but a non-critical semantics annotation is missing.

medium impact medium prob integration

Drivers receive a push notification with a deep link to the declaration acknowledgement screen for a specific assignment. If the deep link handler does not correctly route to the right screen and assignment context — particularly when the app is launched cold from the notification — the driver may see a blank screen or the wrong declaration.

Mitigation & Contingency

Mitigation: Implement and test all three notification scenarios: app foregrounded, app backgrounded, and cold start. Use the platform's existing deep-link-handler infrastructure. Add integration tests that simulate notification tap events and assert correct screen and data loading.

Contingency: If cold-start deep link routing proves unreliable, implement a notification-centre fallback where the driver can find the pending declaration from the notification centre screen, ensuring the workflow can always complete even if the direct deep link fails.

medium impact low prob technical

If the driver-feature-flag-guard has any rendering edge case — such as a brief flash of driver UI before the flag value is loaded, or a guard that fails open on a flag service error — driver-specific UI elements could be momentarily visible to coordinators in organizations that have not opted in, causing confusion and potentially a support escalation.

Mitigation & Contingency

Mitigation: Default the guard to rendering nothing (not a loading indicator) until the flag value is definitively resolved. Treat flag service errors as flag-disabled to fail closed. Write widget tests covering the loading, disabled, and enabled states including the error case.

Contingency: If fail-closed cannot be guaranteed within the sprint, add a server-side RLS check on the driver assignment endpoints so that even if the UI guard leaks, the data layer refuses to return driver data for organizations without the flag enabled.