Add the new endpoints to contracts/openapi.yaml and docs/05-api-contract.md (return-preview, the four rule-specific data-quality resolution endpoints, search, integration status, scheduled-scan), document the role matrix and the audit before/after exposure in docs/12-security-and-audit.md, document each rule type's actual resolution flow in docs/07-data-quality.md (including the deliberate evidence-fingerprint simplification and the reopened_from/previous_decision recurrence link), document the preview/ commit relationship in docs/08-return-workflow.md, and update README.md's scope/integration-status/quality-gate sections to match what's actually implemented and verified now. Also drops docs/05-api-contract.md's mention of GET /api/v1/system/status, which was never implemented.
3.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 an inspection or maintenance reading below the canonical odometer. Never lower the canonical value automatically.
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 (updates a named related booking's reading and the
vehicle's canonical odometer together). A correct_reading value below the current
canonical is rejected, since it would not resolve the regression, not silently applied.
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
availablewhile an active booking exists; - status
rentedwithout an active booking; - status
availablewhile critical open quality issue exists; - status
maintenancewith 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 — the CSV
seed rows don't carry a stable evidence fingerprint, so the literal
(..., evidence fingerprint) scheme from an earlier draft of this rule was dropped as
unworkable for seeded data; re-implementing it would need to reconcile with that. 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.