high priority medium complexity testing pending testing specialist Tier 4

Acceptance Criteria

DuplicateDetectionService unit tests achieve 100% branch coverage across RPC result mapping paths, including empty list, single candidate, and multi-candidate responses
Boundary value tests for blockable duplicate threshold pass at threshold-1, threshold, and threshold+1 similarity scores, asserting correct boolean output in each case
Null candidate list input to DuplicateDetectionService returns DuplicateCheckResult with hasDuplicates=false and empty candidates list without throwing
DeduplicationQueueService chapter-scoped filtering tests verify that items from other chapters are excluded, using mock Supabase client returning mixed-chapter data
Unresolved count from DeduplicationQueueService matches the exact number of records with duplicate_reviewed=false in the mocked dataset
forceResolve action in DeduplicationQueueService test verifies that the correct activity ID is passed to the repository update call and that the local state reflects resolution
DuplicateComparisonPanel widget test renders exactly two columns side-by-side for a mock pair of ActivityRecord objects
Divergent field rows in DuplicateComparisonPanel carry a highlight color token distinct from matching rows, verified via widget finder on the rendered Color/BoxDecoration
Matching field rows are rendered without highlight decoration, confirmed by asserting absence of the highlight color token
Screen reader semantics test verifies that divergent rows expose a Semantics node with a label describing the field name and both values (e.g., 'Date differs: 2025-01-01 vs 2025-01-03')
All tests run in isolation with no real network calls; Supabase client is fully mocked via a test double or mockito-generated mock
Test file follows project naming convention (*_test.dart) and is co-located with the source file under test/unit/ and test/widget/ respectively

Technical Requirements

frameworks
Flutter
flutter_test
mockito
bloc_test
apis
Supabase RPC (mocked)
coordinator_duplicate_queue view (mocked)
data models
DuplicateCandidate
DuplicateCheckResult
ActivityRecord
performance requirements
Full test suite for this task completes in under 30 seconds on CI
Widget tests use pumpAndSettle with a bounded timeout of 5 seconds
security requirements
No real Supabase credentials in test files; use environment-agnostic mock clients
Mock data must not contain real personal identifiers; use synthetic UUIDs and placeholder names
ui components
DuplicateComparisonPanel
divergent field row widget
matching field row widget

Execution Context

Execution Tier
Tier 4

Tier 4 - 323 tasks

Can start after Tier 3 completes

Implementation Notes

Inject the Supabase client through the constructor (or a repository abstraction) so tests can swap in a mock without reflection hacks. Use `bloc_test`'s `whenListen` / `expectLater` pattern if the services expose BLoC state streams. For widget tests, wrap DuplicateComparisonPanel in a minimal MaterialApp with the project's design token theme so that color comparisons resolve correctly against theme tokens rather than hard-coded hex values. When asserting Semantics, use `tester.getSemantics(find.byType(DivergentFieldRow))` and check the `label` property.

For the boundary value tests, parameterise the threshold value through a const and assert using `equals(true)` / `equals(false)` to make intent clear. Avoid `pump` loops — use `pumpAndSettle()` unless the widget has animations that need explicit frame stepping. Ensure mock Supabase returns typed responses matching the PostgrestList/PostgrestMap shapes the repositories expect, so fromJson paths are exercised.

Testing Requirements

Unit tests (flutter_test): DuplicateDetectionService — RPC mapping (happy path, empty list, null input), threshold boundary values (at-1, at, at+1). DeduplicationQueueService — chapter filter isolation, unresolved count, forceResolve side effect. Widget tests (flutter_test): DuplicateComparisonPanel — two-column layout assertion, highlight on divergent rows, no highlight on matching rows, Semantics labels on divergent rows. Use mockito for Supabase client injection.

Aim for 100% branch coverage on service classes. Run via `flutter test test/unit/duplicate_detection_service_test.dart test/unit/deduplication_queue_service_test.dart test/widget/duplicate_comparison_panel_test.dart`.

Component
Duplicate Detection Service
service medium
Epic Risks (2)
medium impact medium prob technical

If the duplicate check RPC fails due to a network error or Supabase outage, the service must decide whether to block submission entirely (safe but disruptive) or allow submission to proceed silently (functional but risks data duplication). An incorrect choice leads to either user frustration or data quality issues.

Mitigation & Contingency

Mitigation: Define an explicit error policy in the service: RPC failures result in a DuplicateCheckResult with status: 'check_failed' and no candidates. The caller treats this as 'allow submission, flag for async review'. Document this as the intended graceful degradation behaviour in the service interface contract.

Contingency: If stakeholders require blocking on RPC failure, expose a configurable `failMode` parameter in the service that can be toggled per organisation via the feature flag system without a code deployment.

medium impact medium prob scope

The DuplicateComparisonPanel must handle varying activity schemas across organisations (NHF, HLF, Blindeforbundet each have different activity fields). A rigid layout may not accommodate all field variations, causing truncation or missing data in the comparison view.

Mitigation & Contingency

Mitigation: Design the panel to render a dynamic list of key-value pairs rather than a fixed-column layout. Define a `ComparisonField` model that each service populates with only the fields relevant to the activity type and organisation, allowing the panel to adapt without schema knowledge.

Contingency: If dynamic rendering proves too complex within the timeline, ship a simplified panel showing only the five most critical fields (peer mentor, activity type, date, chapter, submitter) and log a follow-up ticket for full field rendering in a later sprint.