Süper Panel VIN Decode Observability Module (SP-VIN-001) prerequisite.
The dashboard needs provider chain + cache + fallback context the
frontend can't see — emit those events from the backend.
VehiclesService.decodeVin now emits, at every terminal path:
1. provider_response_received (one per provider that ran)
- provider, response_time_ms, status (success/no_data), cached,
vin_brand, vin_sanitized, attempt_in_chain
- Derived from ctx.timings.{pcat,emex,pl24,vin_api}; only providers
that actually executed get an event.
2. provider_fallback_triggered (between consecutive attempts)
- from_provider, to_provider, reason (timeout if budget aborted,
else no_data), auto, attempt_number.
3. vin_decode_succeeded — winning provider, cache_hit, cache_source,
response_time_ms, partial_result, fallback_used, provider_attempts,
pl24_circuit_open, vin_sanitized.
4. vin_decode_failed — error_code (BUDGET_EXCEEDED | UNKNOWN_VIN),
error_message, provider_attempted, response_time_ms, vin_sanitized.
Wired at three terminal points:
- DB cache hit (existing vehicle, no chain run)
- Unknown VIN failure (chain returned null)
- Full chain success (savedVehicle return)
Notes:
- VINs are sanitized (`WAUZZZ8K****`) before leaving the backend.
- Emission is wrapped in try/catch; a PostHog hiccup never breaks a
user-facing decode.
- Frontend's legacy `vin_decoded` / `vin_decode_success` /
`vin_decode_error` events stay as-is. The new backend events live
alongside them with richer props.
- ML decoder fields default to false — VAG ML pipeline lands later.
Spec updated to pass the new PostHogService mock.
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>