high priority low complexity testing pending testing specialist Tier 1

Acceptance Criteria

All typed fields (hoursVolunteered, contactsReached, estimatedLivesImproved, economicValue, etc.) round-trip correctly through toJson/fromJson with no data loss or type coercion
fromJson correctly handles null or missing optional fields by applying defaults rather than throwing
Two BenefitCalculationResult instances with identical field values are equal (== returns true) and produce the same hashCode
Two instances differing in any single field are not equal and produce different hashCodes
copyWith returns a new instance (not the same reference) with only specified fields changed; unchanged fields retain original values
copyWith with no arguments produces an instance equal to the original
toString output contains at minimum all non-null field names and values in a human-readable format
JSON serialization handles numeric precision correctly for economic value (e.g., double fields don't lose fractional parts)
fromJson on a JSON map with extra unknown keys does not throw (forward-compatibility)
All test cases pass with zero external dependencies using only flutter_test

Technical Requirements

frameworks
flutter_test
data models
BenefitCalculationResult
performance requirements
All tests complete in under 1 second total
No async operations required — model is pure Dart
security requirements
Do not log or print sensitive personal metrics in test output

Execution Context

Execution Tier
Tier 1

Tier 1 - 540 tasks

Can start after Tier 0 completes

Implementation Notes

Import only 'package:flutter_test/flutter_test.dart' and the model file. Use const constructors where possible in test fixtures for clarity. Define a single canonical 'baseline' instance at the top of the test file and derive variants from it via copyWith to keep tests DRY. For the JSON round-trip, assert field-by-field after deserialization rather than equality on the whole map to produce clear failure messages.

Ensure the test file mirrors the model file path (e.g., test/models/benefit_calculation_result_test.dart). Register the test file in the CI test suite.

Testing Requirements

Pure unit tests using flutter_test. Group tests into four describe blocks: (1) JSON serialization/deserialization round-trips covering all fields individually and as a complete object, (2) equality and hashCode with identical instances, single-field differences, and null-vs-value differences, (3) copyWith with full override, partial override, and no override, (4) toString format validation using contains/matches checks. Aim for 100% branch coverage of the model class. No mocks or fakes required — instantiate BenefitCalculationResult directly.

Epic Risks (2)
medium impact medium prob integration

Supabase organisation configuration table may not yet have the five multiplier columns, requiring a migration. If the migration is not coordinated with other teams touching the same table, schema conflicts could delay delivery.

Mitigation & Contingency

Mitigation: Add multiplier columns in a dedicated, non-destructive ALTER TABLE migration script. Review the organisation config table schema with the backend team before writing the migration. Use nullable columns with defaults so existing rows are unaffected.

Contingency: If the migration cannot be deployed in time, stub the repository to return hardcoded default multiplier values from a local config file, allowing parallel development. Swap in the real Supabase fetch once the migration is live.

low impact medium prob scope

The ActivitySummaryAggregator depends on activity records already persisted in the database. For newly onboarded peer mentors with no activity history, the aggregator will return zero counts, which could make the calculator appear broken on first use.

Mitigation & Contingency

Mitigation: Design the pre-fill value object to distinguish between 'no data yet' and 'zero activities'. The calculator input panel should display empty inputs (not zero) when no history exists, with placeholder text guiding the user to enter values manually.

Contingency: If the distinction cannot be surfaced cleanly in the UI timeline, fall back to always showing empty inputs and document the manual-entry path as the primary UX until activity data accumulates.