Memoizes the interceptor chain resolution per execution tree, keyed by
(app_id, service, op). The FIRST hooked-eligible op pays the one chain query;
every later op reuses it — so N kv::sets in a script with no interceptors now
issue ONE resolve, not N (the dominant, zero-marker case caches an empty chain).
InterceptorCacheScope is an RAII scope entered in execute_ast next to the
emission budget, same re-entrancy model: a synchronous invoke/interceptor
re-entry shares the cache, and it is cleared at the outermost boundary so a
pooled thread never serves a foreign app's cache. Pinned by an executor-core
test: 25 sets → 1 resolve, and a fresh execution → a new resolve.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>