Files
MobilityOps/docs/07-data-quality.md
T
NuklearRabbit c981aad2a3 docs(release): update contracts and docs for functional-completion changes
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.
2026-08-02 07:10:37 +02:00

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 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 — 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.