high priority low complexity testing pending testing specialist Tier 2

Acceptance Criteria

Test file located at test/features/mileage/domain/services/auto_approval_evaluator_test.dart
All tests pass with flutter test — no skipped or pending tests
Path 1: distance=40, threshold=50, no attachment → auto_approved
Path 2: distance=40, threshold=50, attachment present → pending_review
Path 3: distance=50, threshold=50 (at boundary) → pending_review
Path 4: distance=60, threshold=50 → pending_review
Path 5: distance=0, threshold=50, no attachment → auto_approved
Path 6: null orgConfig → pending_review (safe default)
Path 7: orgConfig.autoApprovalThresholdKm=0 → pending_review for any positive distance
Path 8: multiple attachments present + distance below threshold → pending_review
Each test uses a descriptive name matching the business rule being verified
Test suite completes in under 300 ms

Technical Requirements

frameworks
Flutter
flutter_test
Dart
data models
AutoApprovalEvaluator
MileageClaim
OrgConfiguration
ClaimStatus
performance requirements
Full test suite executes in < 300 ms
No async operations
security requirements
Null orgConfig test must assert pending_review — never auto_approved

Execution Context

Execution Tier
Tier 2

Tier 2 - 518 tasks

Can start after Tier 1 completes

Implementation Notes

Build minimal test-only factory helpers at the top of the test file to construct MileageClaim and OrgConfiguration with sensible defaults. This makes each test a one-liner asserting only the variable under test. Example: expect(evaluator.evaluate(buildClaim(distanceKm: 40), buildOrgConfig(threshold: 50)), ClaimStatus.auto_approved). Validate that the test names are readable as a specification document — a non-technical reviewer should understand each test case from its description alone.

Consider using a parameterised test approach with a list of (input, expected) tuples to cover all 8 paths with minimal duplication.

Testing Requirements

Pure unit tests using flutter_test. Use factory helper functions (buildClaim({distanceKm, attachments}), buildOrgConfig({threshold})) to reduce boilerplate. Group tests into: group('auto_approved paths', ...), group('pending_review paths', ...), group('boundary conditions', ...), group('null/missing config', ...). Each group should have clear test names that read as business rules.

No mocks needed. 100% branch coverage of evaluate() method required.

Component
Auto-Approval Threshold Evaluator
service low
Epic Risks (3)
high impact medium prob security

Supabase Row Level Security policies for mileage_claims may require complex join conditions to distinguish peer mentor (own claims only) from coordinator (chapter-scoped claims) access. If the RLS policy is misconfigured, coordinators could see claims outside their chapter scope or peer mentors could read other users' data, causing a data privacy incident.

Mitigation & Contingency

Mitigation: Write RLS policy SQL as part of this epic with explicit test cases for each role. Use Supabase's built-in policy testing tools and add integration tests that assert cross-user data isolation before merging.

Contingency: If RLS configuration proves too complex to test reliably within the epic, add an application-layer guard in the adapter that filters query results by authenticated user ID as a defence-in-depth measure while the policy is corrected.

medium impact low prob scope

Norwegian tax authority reimbursement rounding rules may change or may not be publicly documented in machine-readable form. Using the wrong rounding convention could cause systematic over- or under-payment, leading to compliance issues for the organisation.

Mitigation & Contingency

Mitigation: Source the exact rounding specification from HLF's finance team before implementing MileageCalculationService. Document the rule as a comment in the source code and link to the authoritative reference.

Contingency: If the rule is ambiguous, implement both truncation and half-up rounding behind a configuration flag so the organisation can switch without a code release.

low impact low prob technical

SharedPreferences reads and writes are asynchronous. If the distance prefill service (built in the next epic) calls LocalDistanceCache concurrently with a post-submission write, a race condition could result in the cache returning a stale or partially written value, causing the next form load to show an incorrect default.

Mitigation & Contingency

Mitigation: Wrap all SharedPreferences access in LocalDistanceCache with sequential async operations and document the non-concurrent usage contract in the class API.

Contingency: If race conditions are observed in testing, introduce a simple mutex pattern using a Completer to serialise cache operations.