Validation Rules

Validation Rules

Purpose: This document catalogues every data validation rule enforced across the ML Incident Response platform. It is the single source of truth for what constitutes a valid record at each layer: API payloads, feature batches, and pipeline outputs.

The programmatic implementations of these rules live in:

  • API layer: api/models.py (Pydantic schemas)
  • Batch / unit layer: validation/schema_checks.py
  • Data layer: Great Expectations checkpoints (run by the Airflow DAG)

Enforcement status legend

  • ENFORCED — implemented in code, covered by tests
  • ⚠️ PARTIAL — rule exists in code but test coverage is incomplete
  • 🔲 PLANNED — documented here, implementation pending

1. Incident Record Rules

Applied on every POST /incidents request and on batch imports.

FieldRuleError / WarningStatus
incident_idMust match pattern INC-[0-9]{4,}Warning: incident_id does not match expected pattern
titleNon-empty string, ≤ 200 charactersError: title must not be empty / title exceeds 200 characters
severityOne of: SEV-1, SEV-2, SEV-3, SEV-4Error: Unsupported severity
categoryOne of: api, data_quality, model_drift, cost_spike, pipeline_failure, securityError: Unsupported category
statusOne of: OPEN, INVESTIGATING, MITIGATING, RESOLVED, CLOSEDError: Unsupported status
summaryNon-empty string, ≤ 2000 charactersError: summary must not be empty / summary exceeds 2000 characters
created_atISO 8601 timestamp with UTC offsetWarning: should be ISO 8601 with UTC offset
resolved_atISO 8601; must be >= created_atError: resolved_at cannot precede created_at
updated_atISO 8601; must be >= created_atError: updated_at cannot precede created_at
acknowledged_atISO 8601 format check (if present)Warning: format violation

Batch enforcement: validation/schema_checks.pyvalidate_incident_record()ValidationResult(valid=False). API enforcement: api/models.py (Pydantic) → HTTP 422 on violation.


2. Feature Batch Rules

Applied by validate_feature_batch_record() and the Great Expectations checkpoint before a feature batch is written to the feature store.

CheckThresholdAction on failureStatus
Row count ≥ FEATURE_BATCH_MIN_ROW_COUNT (1)ConfigurableError; quarantine batch
Null rate per required feature column≤ 5%Error; quarantine batch; open SEV-2
PSI per feature vs training baseline< 0.20Error; open SEV-2 drift incident
schema_fingerprint present and non-emptyNon-empty stringWarning; schema drift undetectable
psi_scores dict non-emptyAt least 1 entryWarning; drift cannot be computed
No new unexpected columnsExact schema matchQuarantine batch; open SEV-3🔲 (GE suite)
Column type unchanged vs schemaExact type matchQuarantine batch; open SEV-2🔲 (GE suite)

Programmatic enforcement: validation/schema_checks.pyvalidate_feature_batch_record(). Pipeline enforcement: Great Expectations suite daily_feature_validation, scheduled via orchestration/ml_incident_dag.py.


3. API Response Rules

All API responses are validated by Pydantic before serialisation.

FieldRuleStatus
Pagination pageInteger ≥ 1
Pagination page_sizeInteger 1–100; default 20
Cursor before_idPositive integer or null
Datetime fieldsSerialised as ISO 8601 with UTC offset
Enum fieldsAlways serialised as string values, never integers

4. Token / Auth Rules

Applied on every authenticated request in api/auth.py.

RuleBehaviour on violationStatus
JWT signature valid (RS256 in prod, HS256 in dev/CI)HTTP 401 invalid_token
JWT exp claim not expiredHTTP 401 token_expired
JWT jti not in Redis denylistHTTP 401 token_revoked + counter increment
sub claim presentHTTP 401 missing_subject
/auth/refresh rate limit ≤ 5/minHTTP 429
Brute-force counter per user (Redis INCR, 60s TTL)HTTP 429 after threshold

5. State Machine Transitions

Enforced by validate_state_transition(current_state, next_state) in validation/schema_checks.py. Any transition not in this table is an error.

FromAllowed Next StatesNotes
OPENINVESTIGATINGAcknowledgement required before investigation
INVESTIGATINGMITIGATING, RESOLVEDDirect to RESOLVED if no mitigation phase needed
MITIGATINGRESOLVEDMitigation must complete before resolution
RESOLVEDCLOSEDPIR must be completed before CLOSED (policy, not enforced in code)
CLOSED(none)Terminal state

6. Batch Validation Helper

validate_batch(records) in validation/schema_checks.py runs validate_incident_record() across a list of records and tags each ValidationResult with a context string (e.g. record[3]) for traceability. Use this in ETL pipelines and integration tests for the cursor pagination routes (OPEN-02).

from validation.schema_checks import validate_batch
 
results = validate_batch(incident_list)
failed = [r for r in results if not r.valid]
for r in failed:
    print(r.context, r.errors)

7. Adding a New Rule

  1. Document the rule in the appropriate section above with enforcement status.
  2. Implement it in api/models.py (API layer) or validation/schema_checks.py (batch/unit layer).
  3. Add a test in tests/unit/test_validation.py covering both the passing and failing case.
  4. If the rule produces a new metric (e.g. a failure counter), register it in observability/alert_rules.yml.
  5. Update the enforcement status column in this document to ✅ ENFORCED.