critical priority high complexity testing pending testing specialist Tier 5

Acceptance Criteria

Happy path test: given valid org_id, period, and mocked sub-services returning success, the orchestrator returns a BufdirExportArtifact with a non-null file_path and download URL
Happy path test: audit record status transitions from 'initiated' → 'processing' → 'completed' and is verified after orchestrator resolves
Activity query failure test: when the activity repository fake throws an ActivityQueryException, the orchestrator aborts immediately and does not call column mapper or file storage
Activity query failure test: audit record status is set to 'failed' with a non-empty error_message field containing the exception description
Column mapper validation error test: when the mapper fake returns a ValidationResult with errors, the orchestrator returns a PartialFailureReport listing all failed row indices
Column mapper validation error test: audit record status is set to 'partial_failure' and the error_message enumerates the failed columns
File storage failure test: when the storage fake throws a StorageUploadException, the orchestrator rolls back to 'failed' audit status
File storage failure test: no file_path or download URL is present on the returned artifact in the storage failure scenario
All four scenarios produce a terminal audit status ('completed', 'failed', or 'partial_failure') — no test leaves the audit record in a transient state
Each test uses a fresh in-memory fake for every sub-service; no shared mutable state leaks between test cases
Test file compiles without warnings under `flutter test` and all cases pass in CI with zero flakiness over 10 consecutive runs

Technical Requirements

frameworks
flutter_test
mocktail or manual fakes (no mockito code generation)
apis
BufdirExportOrchestratorService internal API
ExportAuditRepository fake
BufdirActivityRepository fake
BufdirColumnMapperService fake
BufdirExportFileStorage fake
data models
BufdirExportArtifact
ExportAuditRecord
PartialFailureReport
ValidationResult
BufdirActivityQueryResult
performance requirements
Each individual test case must complete within 2 seconds
Total test suite for this file must complete within 15 seconds
security requirements
Fake implementations must not make real network calls to Supabase or any external service
Test org_id values must be synthetic UUIDs not matching any production organisation

Execution Context

Execution Tier
Tier 5

Tier 5 - 253 tasks

Can start after Tier 4 completes

Implementation Notes

Structure fakes as simple Dart classes implementing the service interface rather than using code-generated mocks — this avoids build_runner overhead in CI. Define a shared TestFixtures class with static factory methods for valid and invalid input data to keep test bodies readable. The orchestrator likely uses async/await chains; wrap orchestrator calls in expectLater or await and then assert sequentially. For the rollback scenario, verify the audit repository fake received exactly two calls: one INSERT (initiated) and one UPDATE (failed) — recording call order is important.

Use addTearDown inside each test to reset fake call logs. Follow the Arrange–Act–Assert pattern strictly; avoid logic inside the assert phase. If the orchestrator accepts a dependency-injected clock, inject a fixed DateTime in tests to make created_at assertions deterministic.

Testing Requirements

Integration tests only — no unit tests for individual service methods in this task. Use flutter_test with a group() block per scenario (happy_path, activity_failure, mapper_validation_failure, storage_failure). Each group contains setUp() that constructs fresh fakes and a tearDown() asserting no unexpected interactions. Assert both the returned value type and the audit record final state for every scenario.

Do not use real Supabase connections; all I/O is intercepted by fakes. Coverage target: 100% of orchestrator public method branches exercised across the four groups.

Component
Bufdir Export Orchestrator Service
service high
Epic Risks (2)
medium impact medium prob scope

Bufdir's column schema may have per-field business rules (conditional required fields, cross-field validation, organisation-specific category taxonomies) that cannot be expressed in a simple key-value mapping configuration. If the configuration model is too simple, supporting NHF's specific requirements will require hardcoded organisation logic, undermining the configuration-driven design.

Mitigation & Contingency

Mitigation: Design the column configuration schema as a full JSON document supporting field-level transformation rules, conditional expressions, and org-specific value enumerations. Validate the design against a real NHF Bufdir Excel template before implementation begins.

Contingency: If the configuration model cannot express all required rules, implement a thin transformation plugin interface where org-specific logic can be added as a named Dart class registered against the organisation ID, with the JSON config covering only the common cases.

high impact medium prob technical

For large organisations like NHF with potentially tens of thousands of activity records, the full export pipeline (query + map + generate + bundle + upload) may exceed Supabase Edge Function execution time limits (typically 150s), causing silent timeouts that leave audit records in a pending state indefinitely.

Mitigation & Contingency

Mitigation: Implement the orchestrator as a background Dart isolate with progress streaming rather than a synchronous Edge Function call. Use chunked processing for the query and mapping phases to reduce peak memory usage. Profile against realistic NHF data volumes in a staging environment.

Contingency: If processing time cannot be reduced below the timeout threshold, implement an asynchronous job model where the export is queued, processed in the background, and the user is notified via push notification when the download is ready — treating it as an eventual rather than synchronous operation.