Skip to content

feat(api): backfill vehicles.vin from the DIMO VIN VC (pull-once)#86

Merged
JamesReate merged 1 commit into
mainfrom
feat/vin-vc-sync
Jul 10, 2026
Merged

feat(api): backfill vehicles.vin from the DIMO VIN VC (pull-once)#86
JamesReate merged 1 commit into
mainfrom
feat/vin-vc-sync

Conversation

@JamesReate

Copy link
Copy Markdown
Member

Why

vehicles.vin is only populated from uploaded registration documents (LicensePlateSyncService scraping dimo.document.vehicle.registration), so most of the fleet shows no VIN. Almost all vehicles already carry a DIMO VIN verifiable credential, readable directly from telemetry-api — and our vehicle-JWT exchange already requests privilege 5 (GetVINCredential), so no permission or config changes are needed.

What

  • TelemetryAPIService.VINFromVCquery { vinVCLatest(tokenId: N) { vin } } through the existing per-vehicle-JWT GraphQL path. Null VC / blank VIN → found=false; GraphQL errors surface as errors (callers skip + retry later).
  • LicensePlateSyncService — VC fallback after the registration-document pass whenever the VIN is still unknown, plus a lean SyncVINOnly (no fetch-api pull) for backfill. Fill-if-missing — an existing VIN is never overwritten.
  • import-group-attestations -vin-only — one-shot, dry-run-able backfill restricted in SQL to vin IS NULL OR vin = ''. The regular cron pass converges new vehicles via the fallback.

Pull-once by construction: VIN is immutable, so everything gates on the VIN being absent — once cached, a vehicle never costs another telemetry query (DCX). Total spend ≈ one query per VIN-less vehicle, once.

No migration, no config, no frontend changes (/vehicles already returns vin; quick-view VIN row, list column, and search already render it). Plan doc: docs/VIN_SYNC_PLAN.md.

Verification (live, mainnet)

  • -vin-only -dry-run -token-id 191347 → resolved LSH14J7C2SA820026 from the VC, logged would cache vin from vc, no write
  • Live run → VIN persisted to vehicles.vin
  • Immediate re-run → checked: 0 — the filled vehicle is excluded by the SQL gate before any telemetry call (pull-once proven)
  • go build / go vet / go test / golangci-lint run all clean; parseVINVCResponse unit-tested (present / null / blank / whitespace / malformed)

After merge

One manual backfill per env:

kubectl exec -n prod deploy/fleet-lite-app -c fleet-lite-app -- /fleet-lite-app import-group-attestations -vin-only -dry-run   # inspect
kubectl exec -n prod deploy/fleet-lite-app -c fleet-lite-app -- /fleet-lite-app import-group-attestations -vin-only            # backfill

🤖 Generated with Claude Code

https://claude.ai/code/session_01UxoaxTXSLqUwkYfewdwGBM

vehicles.vin was only ever filled from uploaded registration documents, so
it stayed NULL for most of the fleet. Almost every vehicle carries a DIMO
VIN verifiable credential, readable via telemetry-api's vinVCLatest { vin }
with privilege 5 — which our vehicle-JWT exchange already requests.

- TelemetryAPIService.VINFromVC: one vinVCLatest query per vehicle through
  the existing per-vehicle-JWT GQL path; null VC / blank vin = found=false.
- LicensePlateSyncService: VC fallback after the registration-document pass
  whenever the VIN is still unknown, and a lean SyncVINOnly that skips the
  fetch-api pull entirely. Fill-if-missing — never overwrites; VIN is
  immutable, so the vin IS NULL gate makes every path pull-once (bounds DCX
  cost to a one-time backfill plus one read per new vehicle).
- import-group-attestations -vin-only: one-shot backfill restricted to
  vehicles with no VIN, dry-run-able; the normal cron pass now converges
  new vehicles via the fallback.

No migration, no config, no frontend changes (/vehicles already returns
vin). Plan: docs/VIN_SYNC_PLAN.md. Live-verified on mainnet: dry-run
resolves the VC VIN, live run caches it, re-run checks 0 vehicles.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01UxoaxTXSLqUwkYfewdwGBM
@JamesReate JamesReate merged commit 912af32 into main Jul 10, 2026
3 checks passed
@JamesReate JamesReate deleted the feat/vin-vc-sync branch July 10, 2026 02:26
JamesReate added a commit that referenced this pull request Jul 10, 2026
Ships #85 (IndexedDB paint cache, shared freshness loader in list view,
remove global Live Tracking) and #86 (vehicles.vin backfill from the DIMO
VIN VC).

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01UxoaxTXSLqUwkYfewdwGBM
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant