# Class BSV::Wallet::Engine::AnchorLivenessCache <a id="class-BSV-Wallet-Engine-AnchorLivenessCache"></a>

**Inherits:** `Object`

Anchor-liveness orchestrator for the persistent verification cache (HLR #516
Sub 6.1).

Per-verify-walk collaborator: constructed fresh for each +BeefImporter#import+
so the batched `known_roots_for_heights` memo cannot leak across walks. The
tick-scoped `current_height` memo lives elsewhere (chain-tracker instance);
this class only memoises the height→root map for the walk it was built to
serve — necessary for re-org safety, not merely for throughput.

Collaborators are supplied by the caller (explicit DI); no engine
back-reference.

## Public Instance Methods
### `filter_trusted(wtxids)` <a id="method-i-filter_trusted"></a> <a id="filter_trusted-instance_method"></a>
Filter `wtxids` to the subset the wallet may still trust.

Pipeline:
    1. Read the heights of the verified proofs backing this
       wtxid set (one indexed query, no anchor invalidation yet).
    2. Ask the chain_tracker for the current wire-order root at
       each height — one batched call, memoised for the life of
       this instance so the walk cannot double-fetch.
    3. Hand the +{ height => root }+ map to
       +Store#invalidate_stale_anchors!+ (pure writer). Returns
       the invalidated anchor +action_ids+.
    4. HLR #516 Sub 6.2 — walk the structural descent from those
       anchors via +Store#descendant_action_ids_of+ and coarse-
       clear all verified descendants via
       +Store#invalidate_verification+. The UPDATE inside the
       shared primitive is gated on +verified_via IS NOT NULL+,
       so unmarked structural descendants (adversarial or
       benign) are walked but never written. Steps 3 + 4 share
       one +db.transaction+ block: an anchor cleared while
       descendants remain +'spv'+ is the state the atomic
       combined invalidation exists to prevent.
    5. Re-query +Store#verified_wtxids+ so the caller receives a
       Set that already reflects both anchor and descendant
       invalidation. The read is trivially cheap under the
       covering index.

Chain-tracker unreachable (network error, unknown height, empty tracker)
surfaces as `nil` entries in the resolved map and does NOT invalidate — only
genuine root mismatches clear rows. Transient outages leave the trust set
intact, and the descent walk is skipped when the anchor set is empty.
- **@param** `wtxids` [Array<String>] 32-byte binary wtxids
- **@return** [Set<String>] the surviving trust set

### `initialize(store:, chain_tracker:)` <a id="method-i-initialize"></a> <a id="initialize-instance_method"></a>
- **@param** `store` [BSV::Wallet::Store]
- **@param** `chain_tracker` [#known_roots_for_heights] a tracker that
supports the batched merkle-root lookup — production
choices are +BSV::Network::ChainTracker+ and
+BSV::Network::SpvHeaderChainTracker+. Never wire
+BSV::Wallet::TrustedSelfChainTracker+ here (it stubs every
height to "unknown" — safe but useless).
- **@return** [AnchorLivenessCache] a new instance of AnchorLivenessCache

### `stats()` <a id="method-i-stats"></a> <a id="stats-instance_method"></a>
Snapshot of per-instance counters. Returns `nil` when
`BSV_WALLET_VERIFY_TRACE` is not set — deliberate, so a caller enabling
instrumentation adds no allocation to the default hot path.

When set, the returned Hash carries:
    :chain_tracker_calls  — invocations of +known_roots_for_heights+
    :cache_hits           — heights answered from the per-walk memo
    :cache_misses         — heights that needed a fresh tracker call
    :invalidated_anchors  — action_ids the anchor UPDATE cleared
    :walked_descendants   — total ids the descent walk visited
- **@return** [Hash{Symbol => Integer}, nil]
