high priority low complexity frontend pending frontend specialist Tier 2

Acceptance Criteria

Divergent fields render with the design token amber warning surface background (AppColors.warningAmberSurface or equivalent token) and a dark foreground text color
Matching fields render with muted foreground text (AppColors.textTertiary or equivalent) and no background highlight
Color contrast of divergent field text on amber background meets WCAG 2.2 AA minimum (4.5:1 for normal text)
Color contrast of matching field muted text on panel background meets WCAG 2.2 AA minimum (4.5:1)
A legend row appears at the top of DuplicateComparisonPanel containing a small amber swatch icon and the text 'Highlighted fields differ between the two activities'
Each divergent FieldRow is wrapped in a Semantics widget with a label in the form: '{fieldName} differs: left {valueA}, right {valueB}'
Matching FieldRow Semantics labels omit the 'differs' qualifier: '{fieldName}: {value}'
VoiceOver/TalkBack test: navigating through the panel announces all divergent fields with their differ label before their values
No hardcoded colors — all colors reference design token constants
Golden test updated to reflect styled divergent and matching states

Technical Requirements

frameworks
Flutter
Design token system (AppColors, AppTypography, AppSpacing)
flutter_test Semantics testing
data models
FieldDiffResult (isDivergent, valueA, valueB)
performance requirements
Highlight styling must not trigger unnecessary widget rebuilds — use const color references from design tokens
security requirements
Semantics labels for divergent fields must not include raw contact IDs or internal system identifiers — use human-readable display values only
ui components
FieldRow (updated with divergent/matching conditional styling)
DiffLegendRow (new stateless widget for legend at top of panel)
DivergentFieldHighlight (optional thin wrapper Container with amber surface color)

Execution Context

Execution Tier
Tier 2

Tier 2 - 518 tasks

Can start after Tier 1 completes

Implementation Notes

Update `FieldRow` to accept `isDivergent`, `valueA` (String), and `valueB` (String) parameters. When `isDivergent` is true, wrap the row's `Container` with `color: AppColors.warningAmberSurface`. Apply `TextStyle(color: AppColors.textPrimary)` for divergent text and `TextStyle(color: AppColors.textTertiary)` for matching text. Wrap each `FieldRow` in `Semantics(label: isDivergent ?

'${fieldName} differs: left ${valueA}, right ${valueB}' : '${fieldName}: ${valueA}', child: ExcludeSemantics(child: ...))` to provide a single clean Semantics node instead of fragmented label/value nodes. For the `DiffLegendRow`, use a `Row` with a 12x12 `Container(color: AppColors.warningAmberSurface)` square and `Text('Highlighted fields differ...', style: AppTypography.labelSmall)`. Verify amber token contrast: NHF and HLF both have users with visual impairments — Blindeforbundet has screen-reader-dependent users — so accessibility compliance here is non-negotiable. Do not use amber color alone as the sole differentiator; also apply a subtle left border or bold text weight as a redundant visual cue for users who cannot perceive color differences (color-blindness support).

Testing Requirements

Widget tests: render DuplicateComparisonPanel with known divergent fields and assert amber background Container is present for those rows. Assert muted text color on matching rows. Assert DiffLegendRow is rendered at top. Semantics test: use `tester.getSemantics()` to find divergent FieldRow Semantics nodes and verify label contains 'differs'.

Verify matching rows do not contain 'differs' in their label. Contrast test: compute contrast ratio of design token values programmatically in a test and assert >= 4.5. Golden test: update golden image to include styled panel. Accessibility audit: run `flutter_test` `SemanticsController` traversal and verify no field is skipped.

Component
Duplicate Comparison Panel
ui 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.