87 lines
4.2 KiB
Markdown
87 lines
4.2 KiB
Markdown
# 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.
|