WMI caches make VIN tools fast: three characters in, manufacturer and country out, no NHTSA round-trip. They also freeze marketing names. When a maker restyles "General Motors LLC" as "GENERAL MOTORS LLC", splits a brand, or NHTSA refreshes the directory wording, your cache keeps serving yesterday's string until something notices.
This post is about detecting manufacturer renames against cached WMI data: normalize for comparison, flag semantic changes, and refresh without breaking SEO pages that keyed off the old label.
Why renames hurt quietly
Symptoms show up weeks late:
- Faceted search shows duplicate makers that are the same company
- "Make mismatch" flags fire because the listing says Toyota and your cache says TOYOTA MOTOR CORPORATION with different punctuation
- GEO pages that slugify manufacturer names 404 or duplicate after a refresh
- Support asks why two VINs with the same WMI render different manufacturer lines after a deploy
The WMI did not change. The string attached to it did.
Cache record with provenance
Store more than wmi -> name:
type WmiManufacturerRecord = {
wmi: string;
manufacturerRaw: string;
manufacturerKey: string; // normalized compare key
source: "nhtsa" | "manual";
fetchedAt: number;
previousRaw?: string;
renameDetectedAt?: number;
};
export function manufacturerKey(raw: string): string {
return raw
.normalize("NFKC")
.toUpperCase()
.replace(/[.,'"()\-]/g, " ")
.replace(/\b(LLC|INC|LTD|CO|CORP|CORPORATION|COMPANY)\b/g, "")
.replace(/\s+/g, " ")
.trim();
}
manufacturerKey collapses legal suffixes and punctuation so "Ford Motor Company" and "FORD MOTOR CO" compare equal. Keep manufacturerRaw for display when you trust the latest upstream wording.
Diff on every refresh
When you re-fetch WMI directory rows (or sample decode responses that include manufacturer), compare keys -- not raw equality.
type RenameEvent =
| { kind: "unchanged"; wmi: string }
| { kind: "cosmetic"; wmi: string; from: string; to: string }
| { kind: "rename"; wmi: string; from: string; to: string; fromKey: string; toKey: string }
| { kind: "new"; wmi: string; to: string };
export function detectManufacturerChange(
prev: WmiManufacturerRecord | undefined,
nextRaw: string,
wmi: string,
): RenameEvent {
if (!prev) return { kind: "new", wmi, to: nextRaw };
if (prev.manufacturerRaw === nextRaw) return { kind: "unchanged", wmi };
const fromKey = prev.manufacturerKey;
const toKey = manufacturerKey(nextRaw);
if (fromKey === toKey) {
return { kind: "cosmetic", wmi, from: prev.manufacturerRaw, to: nextRaw };
}
return {
kind: "rename",
wmi,
from: prev.manufacturerRaw,
to: nextRaw,
fromKey,
toKey,
};
}
Cosmetic means casing, commas, or LLC noise. Safe to adopt silently and bump fetchedAt. Rename means the compare key moved: queue for review or dual-publish aliases.
Apply policy, not blind overwrite
export function applyManufacturerRefresh(
prev: WmiManufacturerRecord | undefined,
nextRaw: string,
wmi: string,
now = Date.now(),
): WmiManufacturerRecord {
const event = detectManufacturerChange(prev, nextRaw, wmi);
if (event.kind === "new" || !prev) {
return {
wmi,
manufacturerRaw: nextRaw,
manufacturerKey: manufacturerKey(nextRaw),
source: "nhtsa",
fetchedAt: now,
};
}
if (event.kind === "unchanged") {
return { ...prev, fetchedAt: now };
}
if (event.kind === "cosmetic") {
return {
...prev,
manufacturerRaw: nextRaw,
fetchedAt: now,
};
}
// rename: keep previousRaw for redirects / admin UI
return {
wmi,
manufacturerRaw: nextRaw,
manufacturerKey: manufacturerKey(nextRaw),
source: "nhtsa",
fetchedAt: now,
previousRaw: prev.manufacturerRaw,
renameDetectedAt: now,
};
}
Product choices once kind === "rename":
- Emit a metric and Slack/admin alert with WMI + from/to
- Keep serving
previousRawon consumer UI for a grace period if slugs depend on it - Add an alias table:
aliasKey -> canonicalWmiso facets merge - Re-decode a sample VIN for that WMI to confirm vPIC agrees
Do not confuse make and manufacturer
vPIC exposes both Make and Manufacturer-style fields depending on endpoint. WMI directories often speak in manufacturer/legal entity language; consumer UI wants Make ("Chevrolet" vs a corporate string). Renames on the manufacturer line should not auto-rewrite Make badges. Gate display fields separately:
- Cache WMI manufacturer for plant/geography context
- Prefer decode
Makefor listing cards - Soft-flag only when Make and manufacturer key disagree across a known map -- not on every LLC tweak
Refresh cadence without stampeding
Pull WMI directory updates on a slow schedule (daily/weekly) and always through the detector above. On decode paths, optionally refresh a single WMI when the decode manufacturer's key disagrees with cache for N consecutive hits -- that catches silent directory drift without re-fetching the world.
Log rename events with WMI and fingerprints of the strings (or the strings themselves; manufacturer names are not VINs). Retain previousRaw until aliases and redirects are in place.
Product rules
- Store raw + normalized key + fetchedAt on every WMI row.
- Cosmetic vs rename is a key comparison, not string equality.
- Renames alert humans; cosmetics auto-adopt.
- Preserve
previousRawlong enough for slug and facet migration. - Keep Make UI on decode Make, not on WMI legal names.
Takeaway
Cached WMI manufacturer strings go stale in wording long before the WMI itself is reassigned. Normalize for comparison, classify cosmetic edits versus real renames, and apply refresh policies that protect facets and GEO slugs. Your cache stays fast -- and stops inventing a second car company out of a punctuation change.
I maintain VIN Lookup, a free VIN decode based on NHTSA data.
Top comments (0)