Review follow-up on two defects in the original change:
- The throwing-hook fallback wrote to #lastDiscoveryWarnings, which is only
ever read to dedup a logger.warn inside #warnProviderDiscoveryFailure. No
log line was emitted, so a broken extension degraded invisibly, and the
shared key could mask a later discovery failure for the same provider. Log
via logger.warn with its own dedup map.
- #refreshRuntimeDiscoveries starts from the already-projected #models, and
the overlay merge only replaces matching provider+id pairs, so a hook's
projection-only entries survived and were fed back into it. An append-style
hook duplicated its output on every refresh. Drop each modifier provider
before the merge so it re-seeds from the unprojected overlays.
(cherry picked from commit b6f841e080d4882a08b8d713de009461b6acc6fe)