critical priority low complexity backend pending backend specialist Tier 0

Acceptance Criteria

ValidationSeverity enum defined with values: error, warning, info
ValidationRuleClass enum defined with values: completeness, threshold, anomaly
ValidationIssue is an immutable Dart class (final fields, const constructor) with: severity (ValidationSeverity), fieldKey (String), humanReadableMessage (String), ruleClass (ValidationRuleClass)
ValidationIssue implements == and hashCode based on all four fields for reliable set/list deduplication
ValidationIssue has a copyWith method for easy test fixture creation
ValidationResult is an immutable class with: issues (List<ValidationIssue>), passed (bool)
ValidationResult.passed is true if and only if issues contains no ValidationIssue with severity == ValidationSeverity.error
ValidationResult has a convenience constructor or factory: ValidationResult.fromIssues(List<ValidationIssue> issues) that auto-computes passed
BufdirValidationRule is an abstract class with a single method: ValidationResult validate(Map<String, dynamic> reportData)
All types are exported from a single barrel file (e.g., bufdir_validation_models.dart) for clean imports
All classes are documented with Dart doc comments explaining each field's purpose
No dependency on Flutter framework — pure Dart only, usable in tests without MaterialApp

Technical Requirements

frameworks
Dart
data models
ValidationIssue
ValidationResult
ValidationSeverity
ValidationRuleClass
BufdirValidationRule
performance requirements
All types are value objects — no mutable state, safe for use in BLoC state without defensive copying
ValidationResult.fromIssues should compute passed in O(n) time using .any() not .where().isEmpty
security requirements
humanReadableMessage must not include raw field values from report data — only structural messages (e.g., 'Field X is required') to avoid accidental PII leakage in UI or logs
fieldKey should reference schema field names, not user-input strings

Execution Context

Execution Tier
Tier 0

Tier 0 - 440 tasks

Implementation Notes

Use Dart's built-in immutability patterns — all fields final, constructor const where possible. For == and hashCode, implement manually or use package:equatable if it is already in pubspec.yaml: `class ValidationIssue extends Equatable { ... @override List get props => [severity, fieldKey, humanReadableMessage, ruleClass]; }`. Do not add equatable as a new dependency just for this — check first.

ValidationResult.passed computation: `bool get passed => !issues.any((i) => i.severity == ValidationSeverity.error)` — warnings and infos do not block submission. BufdirValidationRule interface: keep the validate() signature generic (`Map reportData`) to allow rules to inspect any field without coupling to a specific report DTO at this layer. Concrete rule implementations will be added in subsequent tasks. Place all files under lib/features/bufdir/validation/models/.

The barrel export file should be lib/features/bufdir/validation/models/bufdir_validation_models.dart.

Testing Requirements

Pure Dart unit tests (no flutter_test widgets needed): (1) ValidationResult.passed is false when any issue has severity=error; (2) ValidationResult.passed is true when all issues are warning or info; (3) ValidationResult.passed is true when issues list is empty; (4) ValidationIssue equality: two instances with identical fields are equal (==) and have same hashCode; (5) ValidationIssue.copyWith produces correct new instance; (6) BufdirValidationRule can be implemented as a concrete class in tests and validate() returns ValidationResult. All tests in test/bufdir/validation/ directory.

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.