Implement PeerMentorAggregationService parallel fetch
epic-peer-mentor-detail-screen-bloc-and-assembly-task-002 — Implement PeerMentorAggregationService using Future.wait to fetch data from PeerMentorRepository, CertificationRecordRepository, MentorActivityLogRepository, and AssignmentHistoryRepository in parallel. Merge results into PeerMentorDetailModel. Propagate per-source errors without failing the entire aggregation — a failed assignment fetch must not blank mentor profile data for HLF coordinators who do not use assignments.
Acceptance Criteria
Technical Requirements
Execution Context
Tier 1 - 540 tasks
Can start after Tier 0 completes
Implementation Notes
Use `Future.wait([f1, f2, f3, f4], eagerError: false)` is NOT suitable here because it short-circuits on first error. Instead, wrap each repository call in a helper that returns `Either
After awaiting, inspect each result and build the model. Distinguish fatal vs. non-fatal sources: PeerMentorRepository is fatal — if it fails, throw immediately. The other three are non-fatal — populate the error map.
Define a sealed class `AggregationError` with subtypes per source for type-safe error handling downstream. Use `AsyncValue` from Riverpod for each source result internally if you want to reuse Riverpod's error/loading pattern. Register the service as a `Provider` (not `FutureProvider`) because it exposes a method, not reactive state. Avoid caching at this layer — caching is the BLoC's responsibility.
Testing Requirements
Unit tests (flutter_test): (1) All-success scenario — mock all 4 repositories returning fixture data, assert merged model fields. (2) Assignment failure — mock AssignmentHistoryRepository to throw, assert model is returned with empty assignments and error map contains DataSource.assignments key. (3) Certification failure — same pattern. (4) Profile failure — assert service rethrows or wraps as fatal error, no partial model returned.
(5) Parallelism test — use Completer-based mocks that each complete after a delay; measure total elapsed time is < sum of delays. (6) Timeout test — mock one repository to never complete, assert Future.timeout fires within 10 s. Minimum 90% branch coverage on PeerMentorAggregationService. No integration tests against live Supabase in CI.
The parallel Future.wait aggregation pattern may produce race conditions or incorrect merged state when some repositories resolve significantly faster than others, particularly if the BLoC receives a RefreshDetail event while a prior fetch is still in flight.
Mitigation & Contingency
Mitigation: Implement cancellation token pattern in the aggregation service to abort in-flight fetches on new events. Add BLoC test scenarios for rapid successive refresh events to validate state consistency.
Contingency: If race conditions persist, switch to a sequential-with-timeout fetch strategy for the first release and profile the performance impact before deciding whether parallel fetch optimization is worth the complexity.
Integrating PeerMentorDetailScreenWidget into the existing StatefulShellRoute navigation structure may conflict with the Contacts tab's existing route hierarchy, requiring changes to navigation-route-config that could affect other teams' features.
Mitigation & Contingency
Mitigation: Coordinate with the Contact List and Contact Detail feature teams before adding the new route. Review the existing StatefulShellRoute configuration and confirm the peer mentor detail route can be nested under the Contacts branch without path conflicts.
Contingency: If route conflicts arise, temporarily implement the peer mentor detail as a modal overlay (push route) rather than a shell route child, preserving functionality while the navigation architecture conflict is resolved.
The course enrollment screen that the certification alert banner links to may not yet exist or may be implemented in a separate feature epic, leaving a broken navigation tap for HLF users in the initial release.
Mitigation & Contingency
Mitigation: Check the certification management feature implementation status before finalizing Epic 4 scope. If the enrollment screen is not available, design the tap action to open the HLF course enrollment URL in an external browser as an interim solution.
Contingency: Implement the CTA as a configurable action: if the enrollment route exists in the router, push it; otherwise, launch the configured org-specific enrollment URL via url_launcher, ensuring HLF users can always take action on expired certifications.