critical priority high complexity testing pending testing specialist Tier 7

Acceptance Criteria

Unit tests exist for scope computation for all three role types: coordinator (scoped to single chapter), national admin (scoped to all units), and peer mentor (scoped to assigned units only)
isUnitInScope returns true for all units within a coordinator's assigned chapter and false for all units outside that chapter
isUnitInScope returns true for all units when called with a national admin role
isUnitInScope returns true only for directly assigned units when called with a peer mentor role
Scoped query helper is injected with correct filter predicates matching the active role's scope boundaries
JWT claims synchronization test verifies that scope changes update JWT claims within the expected latency window
Cross-scope data leakage test: a coordinator authenticated for chapter A cannot retrieve data belonging exclusively to chapter B
All tests use mock repositories implementing the same interfaces as production repositories — no real Supabase calls
Test coverage for AccessScopeService reaches at least 90% line coverage and 85% branch coverage
Edge case: user with no assigned units returns empty scope without throwing exceptions
Edge case: user simultaneously holds multiple roles is handled deterministically (most permissive or most restrictive, per defined policy)
Test suite completes in under 30 seconds on CI

Technical Requirements

frameworks
Flutter
flutter_test
BLoC
Mockito or mocktail for Dart mocking
apis
Supabase Auth (mocked)
JWT claims API (mocked)
data models
UserRole
OrganizationalUnit
AccessScope
JwtClaims
performance requirements
Full test suite runs in under 30 seconds
Each individual test completes in under 500ms
No real network calls — all I/O mocked
security requirements
Tests must explicitly verify that cross-scope data leakage is impossible
JWT claims synchronization tests must cover token expiry edge cases
Mock repositories must not expose any real credentials or connection strings

Execution Context

Execution Tier
Tier 7

Tier 7 - 84 tasks

Can start after Tier 6 completes

Implementation Notes

Start by mapping out every public method on AccessScopeService and listing the distinct behavioral cases for each. Use a table (role × unit relationship × expected outcome) to drive test case design before writing any code. Mock the repository layer at the interface boundary, not at the Supabase client level, to keep tests fast and decoupled from infrastructure. For JWT claims synchronization, mock a clock/timer so you can simulate token expiry without real delays.

The cross-scope leakage tests are the highest-value tests here: structure them as 'given user A's scope, attempt to retrieve data known to belong only to user B's scope, assert empty/forbidden result'. If AccessScopeService uses streams or BLoC, use the bloc_test package's emitsInOrder helpers for async assertions. Document the multi-role policy decision as a comment in the test file header so future maintainers understand the expected behavior.

Testing Requirements

All tests are pure unit tests using flutter_test. Use mocktail or mockito to mock repository interfaces. Structure tests in groups: (1) scope computation per role type, (2) isUnitInScope boundary cases, (3) scoped query helper injection, (4) JWT claims sync, (5) cross-scope leakage scenarios. Each group should have at least 3-5 test cases covering happy path, edge cases, and error states.

Aim for >90% line coverage on AccessScopeService. Run tests with `flutter test --coverage` and enforce thresholds in CI. Include a regression test for the multi-role determinism policy once it is defined.

Component
Access Scope Service
service high
Epic Risks (3)
high impact medium prob security

If the AccessScopeService and the Supabase RLS policies use different logic to determine accessible units, a coordinator could see data in the client that RLS blocks server-side, causing confusing empty states, or worse, RLS could block data the scope service declares accessible.

Mitigation & Contingency

Mitigation: Define the canonical scope computation in a single Supabase Postgres function shared by both the RLS policies and the RPC endpoint called by AccessScopeService. The client-side service calls this RPC rather than reimplementing the logic, ensuring a single source of truth.

Contingency: Add integration tests that execute the same access decision through both the RLS policy path and the AccessScopeService path and assert identical results. Use these as regression guards in the CI pipeline.

medium impact medium prob integration

When a user switches active chapter via the ChapterSwitcher, widgets that are already built may not receive the context-change event if they subscribe incorrectly to the ActiveChapterState BLoC, leading to stale data being displayed under the new chapter context.

Mitigation & Contingency

Mitigation: Use Riverpod's ref.watch on the active chapter provider at the root of each scoped data subtree rather than at individual leaf widgets. Trigger a global data refresh by invalidating all scoped providers when the chapter changes.

Contingency: Add an app-level chapter-change listener that forces a full navigation stack reset to the home screen on chapter switch, guaranteeing all widgets rebuild from scratch with the new context. Accept the UX cost of navigation reset for correctness.

medium impact medium prob scope

Non-technical organization administrators may find the hierarchy management interface too complex for the structural changes they need to make frequently (e.g., chapter renaming, coordinator reassignment), leading to low adoption and continued reliance on manual processes.

Mitigation & Contingency

Mitigation: Conduct usability testing with at least one NHF administrator before finalizing the admin portal screen layout. Prioritize the most common operations (rename, reparent, add child) as primary actions in the UI. Include inline help text and confirmation dialogs with plain-language descriptions of consequences.

Contingency: Provide a simplified 'quick edit' mode that exposes only the three most common operations (rename, deactivate, add child) and hides advanced structural operations behind an 'Advanced' toggle.