DEV Community

Vin Lookup
Vin Lookup

Posted on

Detecting Manufacturer String Renames in Cached WMI Data

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();
}
Enter fullscreen mode Exit fullscreen mode

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,
  };
}
Enter fullscreen mode Exit fullscreen mode

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,
  };
}
Enter fullscreen mode Exit fullscreen mode

Product choices once kind === "rename":

  • Emit a metric and Slack/admin alert with WMI + from/to
  • Keep serving previousRaw on consumer UI for a grace period if slugs depend on it
  • Add an alias table: aliasKey -> canonicalWmi so 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 Make for 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 previousRaw long 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)