Description
_ensure_fresh() in product-toolkit/mcp-servers/merchant-kb/server.py currently clears shared globals in place, then _load() re-populates them. A reader thread that starts iterating _index, _reviews, etc. during the clear+reload window could see empty or partial state.
Mitigation in place: threading.Lock serializes reload so concurrent reloads can't duplicate entries. The reader-window race is narrow (only when a new daily-sync commit lands and multiple requests arrive within the reload window).
Proper fix: refactor _load() to build fresh local structures, then atomically rebind globals (Python assignments are GIL-atomic at the attribute level). Requires restructuring _load() which currently mutates globals directly.
Flagged by codex in second-pass review of the cache-staleness fix (2026-04-16).