The 17-char speculative pre-decode fired a POST /vehicles/decode and discarded
the result, then the button click fired a second identical decode — two
requests per VIN. Keep the pre-decode promise and have runDecode reuse it on the
first attempt (awaiting it if still in flight), so the click navigates off the
already-running decode. Retries and the sub-350ms "clicked before warm" case
fall back to a fresh decode; a failed warm retries once.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>