Implement empty field explicit representation in structure mapper
epic-bufdir-report-preview-foundation-task-007 — Extend BufdirReportStructureMapper so that when the aggregated data has no value for a required field, the field is still represented in the output structure with an explicit zero or null sentinel — never omitted. Implement `buildOrderedFieldList(BufdirReportData data) -> List<BufdirFieldEntry>` that iterates all canonical fields in order, populates each with its data value or the empty sentinel, and returns the complete ordered list ready for rendering.
Acceptance Criteria
Technical Requirements
Execution Context
Tier 2 - 518 tasks
Can start after Tier 1 completes
Implementation Notes
Build a lookup Map from BufdirReportData first (fieldKey → value), then iterate kBufdirSections in order to produce BufdirFieldEntry objects — this keeps the function O(n). Use a numeric zero sentinel (0) for mandatory numeric fields and null for optional fields, distinguishing them via BufdirFieldDefinition.isMandatory. BufdirFieldEntry should be an immutable data class. This function is the primary adapter between raw aggregated data and the render layer — keep it free of any UI or formatting logic.
Testing Requirements
Unit tests: assert output length equals sum of all fields in kBufdirSections for any input. Test with empty BufdirReportData — all entries must have isEmpty = true. Test with fully populated data — no entries have isEmpty = true. Test with partial data — only fields with values have isEmpty = false.
Test output ordering matches kBufdirSections ordering by asserting sectionIndex and fieldIndex sequences. Edge case: test with a BufdirReportData that has extra unknown fields — they must not appear in output.
The preview repository depends on aggregated data produced by the Bufdir Data Aggregation feature. If the aggregation RPC schema or Supabase view columns change during parallel development, the repository's typed Dart models will break, causing compile errors or runtime null-dereference failures.
Mitigation & Contingency
Mitigation: Define a shared Dart interface (abstract class) for the aggregated data contract early and have both features code against it. Use Supabase typed generated clients so schema mismatches surface at code generation time rather than runtime.
Contingency: If the aggregation schema changes after the repository is complete, run `supabase gen types dart` immediately, update the repository model, and run repository unit tests before unblocking UI development. Keep a mock data fixture so UI work can continue during the fix.
The BufdirReportStructureMapper must map internal activity category IDs to the exact label strings used on the official Bufdir reporting form. If the mapping is incomplete or uses outdated labels, coordinators will see mismatches when cross-referencing the preview with the paper form, potentially leading to incorrect submissions.
Mitigation & Contingency
Mitigation: Obtain the current Bufdir reporting form PDF directly from Bufdir (Norse Digital Products has an existing Bufdir dialogue). Extract all field labels and section names into a static constants file reviewed by at least one coordinator from NHF or HLF before implementation begins.
Contingency: If incorrect labels are discovered during UAT on TestFlight, update the static constants file and redeploy. Because the mapper is a pure Dart class with no database storage, corrections require no migration — only a new build.