Customer entered VXKUPHNKSP4032040 (2023 Corsa F) and got a bare 'Marka desteklenmiyor' — VXK was missing from all three WMI maps, so identifyBasic could not even name the brand. PL24's opel_parts catalog ends at CORSA-E (2015-2019, verified via the model-picker page), so the catalog itself stays a gap, but the user now gets the honest 'Opel 2023 olarak tanındı, katalog henüz mevcut değil' message and the miss is logged for the coverage backlog. - WMI_BRAND_MAP + PL24_WMI_SERVICE_MAP + EMEX CATALOG_MAP: VXK -> Opel - DECODE_CHAIN_VERSION 2 -> 3 (brand-mapping change; invalidates the stale negative cache for the customer's VIN) - vin-cache-keys.spec: lock-key assertion checked the bare version char, which now appears inside the test VIN — assert the ✌️ segment instead Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
43 lines
1.7 KiB
TypeScript
43 lines
1.7 KiB
TypeScript
/**
|
|
* Redis key builders for the VIN resolve cache, namespaced by decode-chain version.
|
|
*
|
|
* Bump DECODE_CHAIN_VERSION whenever a change to the decode chain (sources,
|
|
* routing, dispatch, gating, brand mapping) could turn a previously-cached
|
|
* "unknown" into a hit. Bumping instantly invalidates every stale positive and
|
|
* negative entry on deploy: without it, the negative cache keeps serving the old
|
|
* miss for its full TTL and a real fix looks like it "didn't work" until the
|
|
* cache ages out. This was the single biggest source of phantom-undecoded VINs
|
|
* (see undecoded-vin-rca.md §2/§6 — ~17 of 124 historical misses already
|
|
* decoded but were masked by a stale 6h negative cache).
|
|
*
|
|
* Both the decode path (VehiclesService) and the admin cache-buster
|
|
* (InternalVehiclesService) MUST build keys through here so they stay in sync.
|
|
*/
|
|
export const DECODE_CHAIN_VERSION = "3";
|
|
|
|
export function vinResolveCacheKeys(vin: string): {
|
|
cacheKey: string;
|
|
negKey: string;
|
|
lockKey: string;
|
|
} {
|
|
const v = DECODE_CHAIN_VERSION;
|
|
return {
|
|
cacheKey: `vin:resolve:${v}:${vin}`,
|
|
negKey: `vin:resolve:neg:${v}:${vin}`,
|
|
// The in-flight lock is transient (60s) and version-independent — keep it
|
|
// un-namespaced so concurrent decoders still dedupe across a deploy boundary.
|
|
lockKey: `vin:lock:${vin}`,
|
|
};
|
|
}
|
|
|
|
/**
|
|
* Server-side stash for a multi-candidate decode: maps the opaque candidate
|
|
* keys returned to the client back to the provider-specific selection
|
|
* (parts-catalogs car id / EMEX list index). Exists so the client never has to
|
|
* carry decode-source details between the decode and the candidate-pick
|
|
* requests.
|
|
*/
|
|
export function vinCandidateStashKey(vin: string): string {
|
|
return `vin:candidates:${DECODE_CHAIN_VERSION}:${vin}`;
|
|
}
|