high priority low complexity testing pending testing specialist Tier 2

Acceptance Criteria

write(orgId, labelMap) followed by read(orgId) returns an identical Map<String, String>
read(orgId) on a never-written key returns null
clear(orgId) followed by read(orgId) returns null
JSON serialization round-trip preserves keys/values containing special characters: Norwegian characters (æøå), emojis, quotes, backslashes, and newlines
write('org-a', mapA) and write('org-b', mapB) store independently; read('org-a') returns mapA, read('org-b') returns mapB with no cross-contamination
clear('org-a') does not affect the cached value for 'org-b'
write() stores a timestamp (cachedAt as ISO8601 string) alongside the label map in the serialized JSON
read() returns the stored timestamp alongside the label map (as a CachedTerminologyEntry or equivalent typed object)
Tests cover both the SharedPreferences backend and the Hive backend if both are implemented — each backend has its own test group
All tests pass without any real file system access — SharedPreferences is mocked via `SharedPreferences.setMockInitialValues({})`, Hive is mocked via a fake box implementation
Test file passes `flutter test --coverage` with ≥ 95% line coverage on TerminologyCacheAdapter

Technical Requirements

frameworks
Flutter
flutter_test
shared_preferences (with test mock)
hive / hive_flutter (if used as secondary backend)
data models
TerminologyCacheAdapter
CachedTerminologyEntry {labelMap: Map<String,String>, cachedAt: DateTime}
JSON serialization (dart:convert)
performance requirements
All tests run synchronously or with minimal async overhead — no real I/O
Test suite must complete in under 3 seconds
security requirements
Tests must not write to the real device SharedPreferences — always call SharedPreferences.setMockInitialValues({}) in setUp()
No sensitive data in test fixtures — use placeholder org IDs like 'test-org-1'

Execution Context

Execution Tier
Tier 2

Tier 2 - 518 tasks

Can start after Tier 1 completes

Implementation Notes

The contract test pattern (shared test function called for each backend) is the recommended approach — it avoids duplicating 8+ test cases for each backend and ensures consistent behavior. If TerminologyCacheAdapter wraps both SharedPreferences and Hive behind a single interface, define an abstract `CacheBackend` interface and test each concrete implementation independently. For JSON serialization, use `jsonEncode` / `jsonDecode` from `dart:convert`; do not use `toString()` on the map. Timestamp storage: serialize as `DateTime.toUtc().toIso8601String()` and deserialize with `DateTime.parse(...).toLocal()` — document the UTC convention in a code comment.

Ensure `setUp()` in each test group resets both the mock storage AND any in-memory state the adapter may hold.

Testing Requirements

Use `SharedPreferences.setMockInitialValues({})` in setUp() to reset state between tests. For Hive, use a fake in-memory box (implement a mock Box or use hive's own test utilities). Group tests by backend implementation. Write a shared behavior contract as a function `void runCacheAdapterContractTests(TerminologyCacheAdapter Function() factory)` and invoke it for each backend — this ensures both implementations satisfy the same contract.

Special character test: create a map with key `'norsk.æøå'` and value `'Norsk tekst: «hei» ny linje'` and assert round-trip fidelity. Timestamp test: capture DateTime.now() before write(), read back cachedAt, assert it is within 1 second of the captured time.

Component
Terminology Local Cache Adapter
data low
Epic Risks (2)
high impact medium prob integration

The labels JSONB column in organization_configs may lack a consistent schema across organizations, causing deserialization failures or silent missing keys when a new organization is onboarded with a differently structured map.

Mitigation & Contingency

Mitigation: Define and enforce a canonical JSONB schema via a Supabase check constraint and a migration script. Validate the schema in TerminologyRepository at parse time and emit structured errors for any key-type mismatches.

Contingency: If schema drift is discovered post-deployment, LabelKeyResolver's fallback logic ensures the app continues to function with English defaults while a data migration is prepared to normalize the offending organization's config.

medium impact low prob technical

Device local storage corruption or platform-specific SharedPreferences serialization bugs could render a cached terminology map unreadable, causing the app to fall back to English defaults unexpectedly for an organization with custom terminology.

Mitigation & Contingency

Mitigation: Wrap all cache reads in try/catch, validate the deserialized map against a minimum-required-keys check, and evict corrupted entries automatically before re-fetching from Supabase.

Contingency: Surface a non-blocking in-app warning to the coordinator that terminology may be in default English until the next sync completes; trigger an immediate background sync.