high priority medium complexity testing pending testing specialist Tier 2

Acceptance Criteria

Unit test file exists for Role-Aware Notification Filter Service with all scenarios passing
Unit test file exists for Notification Read State Service with all scenarios passing
Tests cover predicate output for all three role scopes: peer_mentor, coordinator, and org_admin
Tests verify in-memory filter includes only notifications matching the active type and read-state predicate
Tests verify in-memory filter excludes notifications not matching the predicate (both type and read-state dimensions)
Tests verify optimistic update is emitted (Stream emits updated item) before repository async call resolves
Tests verify rollback is triggered when the repository throws or returns a failure
Tests verify read_at timestamp on the returned notification matches the server-returned value, not a client-generated value
Tests verify mark-all-read bulk path updates all items in the provided list
Line coverage on Role-Aware Notification Filter Service is >= 90%
Line coverage on Notification Read State Service is >= 90%
All tests are deterministic and pass consistently without timing dependencies
Tests use mocktail for all repository and external dependencies

Technical Requirements

frameworks
Flutter
flutter_test
mocktail
bloc_test (if stream-based service testing needed)
apis
Supabase (mocked via mocktail)
data models
Notification
NotificationFilter
UserRole (peer_mentor, coordinator, org_admin)
NotificationReadStateService
Role-Aware Notification Filter Service
performance requirements
All unit tests must complete in under 5 seconds total
No real network calls — all Supabase interactions mocked
security requirements
Tests must verify that role scope filtering cannot be bypassed by passing a filter predicate from an unauthorized role

Execution Context

Execution Tier
Tier 2

Tier 2 - 518 tasks

Can start after Tier 1 completes

Implementation Notes

For testing the optimistic update emission sequence, use a StreamController or a fake repository that delays resolution. Emit from the service, capture emitted values in a list via stream.listen(), then resolve the fake repository — assert the optimistic value appeared before the repository resolved. For rollback, use mocktail's when().thenThrow() to simulate repository failure, then verify the service emits the rollback signal. For role scope tests, construct NotificationFilter predicates for each role and assert that notifications outside the role's scope are excluded.

Use const constructors for test notification fixtures to keep tests readable. Group tests with descriptive group() labels: 'role scope filtering', 'type predicate', 'read-state predicate', 'optimistic update', 'rollback', 'mark-all-read'. Use setUp() to reset mocks between tests.

Testing Requirements

Pure unit tests using flutter_test and mocktail. No widget or integration tests in this task. Test structure: one test file per service class, grouped with group() blocks per scenario category. For Role-Aware Notification Filter Service: test each role scope independently, test type filters (assignment_reminder, certification_expiry, pause_status, scenario_prompt), test read-state filters (all/unread/read), test combined type+read-state predicates, test empty input list.

For Notification Read State Service: test optimistic stream emission ordering using StreamController fakes, test rollback on mock repository .throws(), test read_at extraction from mock response, test mark-all-read with list of 0, 1, and N items. Use lcov or flutter test --coverage to verify 90%+ line coverage.

Component
Role-Aware Notification Filter Service
service medium
Epic Risks (3)
medium impact medium prob technical

A Realtime INSERT event arriving during an in-flight mark-all-read operation can cause the new notification to be incorrectly marked read in the optimistic state update, silently hiding it from the user.

Mitigation & Contingency

Mitigation: Process Realtime events sequentially in the BLoC event queue using bloc_concurrency's sequential transformer. The mark-all-read event should only affect notifications whose IDs were fetched before the operation started.

Contingency: Add a reconciliation step after mark-all-read that re-fetches the unread count from the repository and corrects the BLoC state if it diverges from the server value.

medium impact medium prob technical

A coordinator assigned to many peer mentors may trigger a query returning hundreds or thousands of notifications. Without pagination and query optimisation, the initial load will be slow and memory-heavy.

Mitigation & Contingency

Mitigation: Enforce server-side pagination (50 items per page) in the Role-Aware Filter's query predicates. Add a composite index on (org_id, user_id, created_at DESC) and profile query plans before shipping.

Contingency: If query performance is insufficient for large coordinator scopes, introduce a server-side RPC function that pre-aggregates visible notification IDs and returns only the first page, deferring full scope resolution to lazy-load.

medium impact low prob scope

If the read-state optimistic update rolls back frequently due to intermittent connectivity, users will observe notifications toggling between read and unread, creating confusion and distrust of the feature.

Mitigation & Contingency

Mitigation: Queue failed mutations in a local retry store and re-attempt on next connectivity event using a connectivity-aware retry service. Show a non-intrusive banner if offline rather than applying optimistic updates.

Contingency: Disable optimistic updates for mark-as-read in low-connectivity scenarios detected by the connectivity provider, instead showing a loading indicator until server confirmation.