The vector-prefilter-then-Jev split is a clean design and the cost table makes the case well. One thing I'd watch for once this runs in production: you're caching resolved phrase-to-token mappings permanently for cost, but your own first lesson was that most of Jev's misses came down to incomplete catalog descriptions, and fixing those improved the whole system's accuracy. A permanent cache keyed only on the phrase doesn't know the description behind a past resolution has since been corrected, so a wrong answer learned before a description fix can sit in the cache indefinitely and invisibly, while every fresh, uncached query benefits from the fix right away. Keying the cache to a description version, even just a hash of the description text, and invalidating on catalog edits would close that gap without giving up the cost win.