H4: NamespaceReconciler.reconcileMirror builds an ad-hoc SourceReconciler
to delegate mirror creation. The previous version left APIReader and
CircuitBreaker as nil, which silently disabled freshness verification
on the namespace-driven path (a label change to a target namespace
would mirror cached, possibly stale source data) and bypassed circuit
breaker accounting for those reconciles.
Construction extracted into newSourceReconciler so the forwarding is
covered by a unit test that pins both fields by identity.
H1: --verify-source-freshness used to default to false, so any source
update whose annotation was still in the informer cache (5-20s lag)
would resolve the wrong target list. cleanupOrphanedMirrors then ran
against the stale list and missed orphans (manifested in e2e as
'Orphaned mirror in kubemirror-e2e-app-1 not deleted within timeout'
after target-namespaces was changed). Defaulting to true fixes the
race; the trade-off is one extra API read per stale-cache reconcile.
M2: ResolveTargetNamespaces glob branch checked filter.IsAllowed but
not the opt-out map, so a namespace labeled allow-mirrors=false would
still receive a mirror through patterns like 'app-*'. The 'all' branch
already had the guard; the glob branch now does too. Direct namespace
listings still bypass opt-out by design (explicit author intent).