critical priority medium complexity backend pending backend specialist Tier 1

Acceptance Criteria

A numeric field whose value equals the configured minimum produces no ValidationIssue (at-threshold is compliant)
A numeric field whose value exceeds the configured minimum produces no ValidationIssue
A numeric field whose value is strictly below the configured minimum produces exactly one ValidationIssue with severity 'warning' and ruleClass 'threshold'
The warning message includes the actual value, the minimum threshold, and the human-readable category name
A numeric field not present in BufdirThresholdConfig produces no ValidationIssue (field is unconstrained)
A null numeric field that has a configured minimum produces a ValidationIssue with severity 'warning' (null is treated as zero for threshold purposes)
BufdirThresholdConfig is injectable at construction time and supports per-organization minimum overrides
The evaluator handles both int and double field values without type errors
The evaluator is stateless and pure Dart with no Flutter SDK dependencies
Minimum config entries use a type-safe model (fieldKey → ThresholdEntry with minimum and categoryLabel)

Technical Requirements

frameworks
Dart
data models
BufdirReportSectionModel
ValidationIssue
BufdirThresholdConfig
ThresholdEntry
performance requirements
Evaluation of a section with 30 numeric fields completes in under 2ms
security requirements
Threshold configuration values are read-only after injection — do not expose mutable config state
Field values must not be written to logs

Execution Context

Execution Tier
Tier 1

Tier 1 - 540 tasks

Can start after Tier 0 completes

Implementation Notes

Define ThresholdEntry as an immutable value object: class ThresholdEntry { final num minimum; final String categoryLabel; }. BufdirThresholdConfig wraps a Map with a const constructor. In the evaluator, cast field values to num using a safe helper (return null on cast failure rather than throwing) to avoid runtime errors on unexpected types. Use string interpolation for message formatting to match the specified format: 'Activity count ($actual) is below the required minimum of $minimum for category $categoryLabel.' This evaluator should implement the same RuleEvaluator interface as the completeness evaluator to remain polymorphic in the orchestrator.

Testing Requirements

Unit tests using flutter_test. Test class: ThresholdComplianceRuleEvaluatorTest. Required scenarios: (1) value == minimum → no issue, (2) value > minimum → no issue, (3) value < minimum → warning issued with correct message content, (4) field not in config → no issue, (5) null value with configured minimum → warning issued treating null as zero, (6) integer field value evaluated correctly, (7) double field value evaluated correctly, (8) multiple fields below threshold → one issue per field, (9) override config (org-specific lower threshold) applied correctly. Assert message content (actual value, minimum, category label) in scenario 3.

Minimum 90% line coverage.

Component
Bufdir Field Validation Service
service medium
Epic Risks (2)
medium impact medium prob scope

The exact minimum threshold values required by Bufdir guidelines (e.g., minimum participant counts per section) may not be formally documented in machine-readable form. If thresholds must be researched or negotiated during implementation, the validation service will be delayed and may launch with incomplete rules, reducing its effectiveness.

Mitigation & Contingency

Mitigation: Compile threshold rules from the Bufdir reporting guidelines PDF before sprint start. Store rules in a separate configuration file (not hardcoded in the service class) so they can be updated without a service rewrite. Treat unknown thresholds as 'no minimum' to avoid false errors.

Contingency: Launch with completeness and anomaly validation only, shipping threshold compliance rules as a follow-on config update once rules are confirmed with Bufdir. Flag this as a known limitation in the coordinator help text.

high impact low prob technical

BufdirPreviewService coordinates three async operations (fetch aggregated data, map structure, run validation). Race conditions or partial failures in this chain could produce an inconsistent preview model — e.g., a model with field values but no validation results — which would silently mislead coordinators into thinking the report is clean.

Mitigation & Contingency

Mitigation: Model the orchestration as a single BLoC/Cubit state machine with explicit states (Loading, Loaded, Error) and ensure validation is always run atomically after mapping, never in parallel. Write integration tests that simulate network failure at each step of the chain.

Contingency: If a partial failure state reaches production, detect it via the missing validation summary field in the preview model and show a full-screen error state rather than an incomplete preview, prompting the coordinator to retry.