Files
MobilityOps/docs/07-data-quality.md
NuklearRabbit 81e3fd63bd
MobilityOps acceptance / backend (push) Failing after 19s
MobilityOps acceptance / frontend (push) Successful in 25s
MobilityOps acceptance / e2e (push) Skipped
M54: harden operations and demo resilience
2026-08-24 03:31:03 +02:00

4.2 KiB

Data-quality rules

Run rules after seed/import, after relevant commands and through an explicit scan service. Rules must be deterministic and explainable.

DQ-01 Possible duplicate customer

Signals and example weights:

  • exact normalized email: 60;
  • exact normalized phone: 50;
  • exact postal code: 10;
  • strong normalized full-name similarity: up to 30.

Open an issue at score >= 70. Store individual signals; do not expose a mysterious AI-only confidence.

Resolution:

  • merge into selected survivor;
  • reject as not duplicate;
  • defer.

Merge rewires booking references, preserves the loser as a tombstone and audits before/after values.

DQ-02 Missing required field

Required for active customers: first name, last name and at least one of email or phone. Required for active vehicles: registration number, make, model and location.

Resolution: POST /provide-fields accepts only the fields the entity type actually requires (rejects anything else), applies them, and re-runs the same missing-field check. The issue resolves only once nothing required remains missing; a partial submission updates the record and its evidence but leaves the issue open.

DQ-03 Odometer regression

Flag a newly recorded checkout, return-inspection or maintenance reading below the canonical odometer. The deterministic import scan compares booking, inspection and maintenance readings in chronological order. A return inspection's actual completion time is authoritative over the booking's planned end, so an early return cannot be mistaken for a later regression. Never lower the canonical value automatically.

When another regression is recorded while the vehicle already has an open DQ-03 issue, append the new source reference and signal to that issue. Do not silently discard the new evidence and do not open parallel issues for the same vehicle.

Resolution: POST /resolve-odometer-regression offers exactly two bounded decisions — retain_canonical (the submitted reading is treated as erroneous; canonical is untouched) or correct_reading. The correction option is offered only for an explicitly named, correctable booking reading; checkout-only and maintenance-only issues can only retain the canonical value. A corrected return updates the booking, its related return inspection and the vehicle's canonical odometer in one transaction. A correct_reading value below the current canonical is rejected, since it would not resolve the regression, not silently applied. When one open issue contains several source readings, correcting one removes only that booking/inspection evidence and keeps the issue open until every remaining signal has received a bounded decision.

DQ-04 Booking overlap

Flag overlapping reserved or active bookings for one vehicle. Normal write APIs reject new overlaps; the seed/import path may create one controlled legacy conflict.

Resolution: POST /resolve-overlap blocks one of the two named overlapping bookings (minimal safe resolution, not a scheduling calendar) and re-verifies no reserved/active overlap remains among the issue's related bookings before resolving.

DQ-05 Vehicle status conflict

Examples:

  • status available while an active booking exists;
  • status rented without an active booking;
  • status available while critical open quality issue exists;
  • status maintenance with an active booking.

Resolution: POST /apply-recommended-status computes a recommendation from one authoritative function mirroring the conditions above, applies it, and re-runs the same function to confirm the conflict is actually gone before resolving.

Lifecycle

Detection is idempotent by (rule_type, entity_type, entity_id) while open. Source-aware rules additionally store stable evidence identity. For DQ-03 this is the tuple (source_type, later_ref, later_km): an explicit retain_canonical decision suppresses only that exact fact on later scans. A changed reading or a different source is actionable again. Resolved issues remain historical. Reintroduced evidence creates a new issue whose evidence carries reopened_from (the prior issue's reference) and previous_decision (its resolved status), so a repeat problem is never presented as if no decision was ever made.