critical priority high complexity integration pending integration specialist Tier 3

Acceptance Criteria

BLoC correctly transitions through all states: idle → checking (on save intercept) → duplicate_found (when candidates exist) → resolving (on user action) → resolved or cancelled
BLoC transitions idle → resolved directly when DuplicateDetectionService finds no candidates, allowing the activity wizard to proceed without user interruption
Activity wizard save button triggers CheckForDuplicates BLoC event; BLoC blocks wizard navigation until state is resolved or cancelled
Proxy registration path (coordinator registering on behalf of peer mentor) correctly passes the peer mentor's identity to DuplicateDetectionService, not the coordinator's
Bulk registration consolidated summary flow batches all detected duplicates and presents them in the DeduplicationQueueScreen rather than interrupting each registration individually
Analytics events are emitted for: duplicate_detected, resolution_keep_both, resolution_cancel, resolution_replace, and coordinator_queue_resolved
Audit trail events are written for every resolution path as defined in DuplicateResolutionHandler
E2E test: self-registration — peer mentor saves activity, no duplicate found, proceeds normally
E2E test: same-day duplicate — peer mentor saves activity identical to an existing one, DuplicateWarningBottomSheet appears, user selects 'Proceed Anyway', activity saved with duplicate_reviewed=true
E2E test: proxy overlap — coordinator registers for a peer mentor who already has an activity that day, duplicate detected, coordinator resolves via REPLACE
E2E test: coordinator queue resolution — bulk registration creates 5 duplicates, coordinator navigates to DeduplicationQueueScreen, bulk-dismisses all, audit log contains 5 entries
All E2E tests run against a real Supabase test project instance (not mocked)

Technical Requirements

frameworks
Flutter
BLoC
flutter_test
Riverpod
apis
Supabase PostgreSQL REST API
Supabase Realtime WebSocket
Supabase Edge Functions (Deno)
data models
activity
assignment
bufdir_export_audit_log
claim_event
performance requirements
BLoC state transition from checking → duplicate_found must complete within 1.5 seconds
Full E2E test suite must complete within 5 minutes
BLoC must handle concurrent duplicate checks without race conditions
security requirements
Proxy registration path must validate that the coordinator has an active assignment to the peer mentor before registering on their behalf
BLoC must not store raw activity draft data beyond the current state — clear on resolved/cancelled to prevent PII leakage in state history
Analytics events must contain no PII — use anonymized IDs only
ui components
DuplicateWarningBottomSheet (task-008)
DeduplicationQueueScreen (task-009)
Activity wizard save intercept hook

Execution Context

Execution Tier
Tier 3

Tier 3 - 413 tasks

Can start after Tier 2 completes

Implementation Notes

Model the BLoC state machine as a Dart sealed class hierarchy: DuplicateDetectionIdle, DuplicateDetectionChecking, DuplicateDetectionFound({required List candidates}), DuplicateDetectionResolving({required ResolutionType type}), DuplicateDetectionResolved, DuplicateDetectionCancelled. Use BLoC's EventTransformer.sequential() for CheckForDuplicates to prevent race conditions on rapid taps. Wire the save intercept in the activity wizard as a middleware function that dispatches CheckForDuplicates and awaits a non-checking state before allowing navigation — use a Completer or stream.firstWhere(). For proxy path, read the selected peer mentor from the assignment context (assignment table, status='active') and inject it into the detection event.

For bulk registration, detect the bulk context flag in the event and route duplicates directly to the coordinator queue rather than the bottom sheet. Analytics events should use a thin AnalyticsService abstraction (no direct SDK calls in BLoC). For E2E tests, use flutter_test integration_test package with a dedicated Supabase test project seeded via a setup script that inserts test organizations, users, and activities before each test scenario.

Testing Requirements

Unit tests: test all BLoC state transitions with mocked services. Test that proxy path sends peer mentor identity to detection service. Test that bulk registration batches duplicates instead of interrupting. Test analytics event emission for each resolution path.

Test concurrent CheckForDuplicates events are queued, not dropped. Integration tests (real Supabase test project): E2E scenario 1 — self-registration, no duplicate. E2E scenario 2 — same-day duplicate, KEEP_BOTH resolution, verify duplicate_reviewed=true in database and audit log entry exists. E2E scenario 3 — proxy overlap, REPLACE resolution, verify candidate deleted and new activity persisted.

E2E scenario 4 — bulk registration with 5 duplicates, coordinator bulk-dismisses, verify 5 audit log entries. Verify RLS prevents cross-organization data access in all scenarios. Minimum 90% branch coverage on BLoC.

Component
Duplicate Detection BLoC
infrastructure medium
Dependencies (4)
Implement the DeduplicationQueueScreen Flutter UI for coordinators to review, compare, and resolve queued duplicate records. Support bulk-dismiss action for NHF group event scenarios. Use DuplicateComparisonPanel for each item, integrate DeduplicationQueueService for data, and display consolidated duplicate summary for bulk registration flows rather than one-at-a-time interruptions. epic-duplicate-activity-detection-state-management-task-009 Create the DuplicateDetectionService that encapsulates the matching algorithm: same peer mentor + overlapping date/time window + same activity type constitutes a candidate duplicate. Implement configurable similarity thresholds, cross-chapter detection for NHF multi-chapter members, and proxy submission detection. Service depends on DuplicateCheckRepository. epic-duplicate-activity-detection-state-management-task-005 Create the DuplicateResolutionHandler service that processes user decisions: KEEP_BOTH (proceed with save, flag as reviewed), CANCEL (abort current activity), or REPLACE (delete candidate, save new). Emit structured audit trail events for each decision path. Integrate with the duplicate-reviewed-flag middleware to prevent re-detection. Depends on DuplicateCheckRepository and DuplicateDetectionService. epic-duplicate-activity-detection-state-management-task-007 Implement the DuplicateWarningBottomSheet Flutter widget that intercepts the activity wizard save action and presents the duplicate candidate with action buttons (Proceed Anyway, Cancel, View Details). Uses DuplicateComparisonPanel for detail view. Must support screen readers, cognitive accessibility guidelines, and plain-language error messaging per NHF requirements. epic-duplicate-activity-detection-state-management-task-008
Epic Risks (2)
medium impact high prob technical

For bulk registration with many participants, running duplicate checks sequentially before surfacing the consolidated summary could introduce a multi-second delay as each peer mentor is checked individually against the RPC. This degrades the bulk submission UX significantly.

Mitigation & Contingency

Mitigation: Issue all duplicate check RPC calls concurrently using Dart's `Future.wait` or a bounded parallel executor (max 5 concurrent calls to avoid Supabase rate limits). The BLoC collects all results and emits a single BulkDuplicateSummary state with the consolidated list.

Contingency: If concurrent RPC calls hit Supabase connection limits or rate limits, implement a batched sequential approach with a progress indicator showing 'Checking participant N of M' so the coordinator understands the delay is expected and bounded.

high impact medium prob integration

In proxy registration, the peer mentor's ID must be used as the duplicate check parameter, not the coordinator's ID. If the proxy context is not correctly threaded through the BLoC and service layer, duplicate checks will silently run against the wrong person, missing actual duplicates.

Mitigation & Contingency

Mitigation: Define a `SubmissionContext` model that carries the effective `peer_mentor_id` (distinct from `submitter_id`) and pass it explicitly through the BLoC event payload. The DuplicateDetectionService always reads peer_mentor_id from SubmissionContext, never from the authenticated user session.

Contingency: If SubmissionContext threading proves difficult to retrofit into the existing proxy registration BLoC, add an assertion in DuplicateDetectionService that throws a descriptive error when peer_mentor_id is null or matches the coordinator's own ID in a proxy context, making the bug immediately visible in testing.