feat(api): identify-but-no-catalog fallback instead of a bare "unsupported"
When no catalog source can decode a VIN, the decode dead-ended with "Şase
numarası tanınamadı. Marka desteklenmiyor." even for valid, recognizable cars.
Now, before that error, run a best-effort identification (offline Corgi WMI +
NHTSA); if it yields a brand/model/year, tell the dealer what the car is and that
the request was logged ("Bu araç X olarak tanındı, ancak ... katalog henüz yok.
Talebiniz kaydedildi."). Logged distinctly (identified_no_catalog) so the coverage
backlog can be mined. Skipped on budget-abort.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -121,8 +121,32 @@ export class VehiclesService {
|
|||||||
const resolved = await this.resolveVin(vin, pcatCarId, emexCarIndex, userId, ctx);
|
const resolved = await this.resolveVin(vin, pcatCarId, emexCarIndex, userId, ctx);
|
||||||
|
|
||||||
if (!resolved) {
|
if (!resolved) {
|
||||||
const finalSource = ctx.timings.aborted ? "aborted" : "none";
|
const aborted = !!ctx.timings.aborted;
|
||||||
const errMsg = ctx.timings.aborted
|
// No catalog source has this VIN. Best-effort identification (offline Corgi
|
||||||
|
// WMI + NHTSA) so we don't dead-end with a bare "unsupported" — at least tell
|
||||||
|
// the dealer what car it is. The miss is logged (with wmi) for the coverage
|
||||||
|
// backlog either way. Skip on budget-abort (already a timeout, don't pile on).
|
||||||
|
if (!aborted) {
|
||||||
|
const basic = await this.identifyBasic(vin);
|
||||||
|
if (basic) {
|
||||||
|
ctx.timings.identified_no_catalog = 1;
|
||||||
|
await this.logQuery(
|
||||||
|
userId,
|
||||||
|
vin,
|
||||||
|
null,
|
||||||
|
"none",
|
||||||
|
false,
|
||||||
|
Date.now() - startTime,
|
||||||
|
`No catalog — identified as ${basic}`,
|
||||||
|
ctx.timings,
|
||||||
|
);
|
||||||
|
throw new BadRequestException(
|
||||||
|
`Bu araç ${basic} olarak tanındı, ancak bu şase için parça kataloğu henüz mevcut değil. Talebiniz kaydedildi.`,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
const finalSource = aborted ? "aborted" : "none";
|
||||||
|
const errMsg = aborted
|
||||||
? `Decode budget exceeded (${VehiclesService.RESOLVE_BUDGET_MS}ms)`
|
? `Decode budget exceeded (${VehiclesService.RESOLVE_BUDGET_MS}ms)`
|
||||||
: "Unknown VIN/brand";
|
: "Unknown VIN/brand";
|
||||||
await this.logQuery(
|
await this.logQuery(
|
||||||
@@ -500,6 +524,31 @@ export class VehiclesService {
|
|||||||
return "timeout";
|
return "timeout";
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Best-effort identification for VINs no catalog could decode: offline Corgi WMI
|
||||||
|
* → brand, NHTSA → model/year. Returns a display string ("Renault Clio 2018") or
|
||||||
|
* null if even the brand is unknown. Only used to give the user a meaningful
|
||||||
|
* "identified but no catalog yet" message instead of a bare "unsupported".
|
||||||
|
*/
|
||||||
|
private async identifyBasic(vin: string): Promise<string | null> {
|
||||||
|
const corgi = this.corgiService.decodeVin(vin);
|
||||||
|
let brand: string | null = corgi?.isKnown ? corgi.brandName : null;
|
||||||
|
let model: string | null = null;
|
||||||
|
let year: string | number | null = corgi?.modelYear ?? null;
|
||||||
|
try {
|
||||||
|
const nhtsa = await this.vinApiService.decodeVin(vin);
|
||||||
|
if (nhtsa) {
|
||||||
|
brand = brand || nhtsa.make || null;
|
||||||
|
model = nhtsa.model || null;
|
||||||
|
year = year || nhtsa.modelYear || null;
|
||||||
|
}
|
||||||
|
} catch {
|
||||||
|
// NHTSA is best-effort; a brand from Corgi alone is still useful.
|
||||||
|
}
|
||||||
|
if (!brand && !model) return null;
|
||||||
|
return [brand, model, year].filter(Boolean).join(" ").trim() || null;
|
||||||
|
}
|
||||||
|
|
||||||
/** Actual decode chain — does NOT touch the cache or lock. */
|
/** Actual decode chain — does NOT touch the cache or lock. */
|
||||||
private async doResolveVin(
|
private async doResolveVin(
|
||||||
vin: string,
|
vin: string,
|
||||||
|
|||||||
Reference in New Issue
Block a user