# Class BSV::Overlay::LookupResolver <a id="class-BSV-Overlay-LookupResolver"></a>

**Inherits:** `Object`

Resolves LookupQuestions by discovering competent overlay hosts via SLAP
trackers and querying them in parallel.

## Host discovery

For any service other than `ls_slap`, the resolver first queries the
configured SLAP trackers to discover which hosts advertise competence for that
service. Discovery results are cached with a configurable TTL (default: 5
minutes) to avoid redundant network round-trips.

## Host overrides and additional hosts

`host_overrides` replaces SLAP discovery entirely for a named service.
`additional_hosts` supplements discovered (or overridden) hosts. Both maps
require service names that begin with `ls_`.

## Parallel querying

All competent hosts are queried concurrently using Ruby threads. Responses are
collected, outputs are merged, and duplicates are removed by
+"#{txid}.#{output_index}"+ key.

## Reputation tracking

Hosts are ranked before querying via +HostReputationTracker#rank_hosts+, and
success/failure outcomes (with latency) are recorded after each query.

Thread-safe via an internal Mutex on the hosts cache.

## Constants
### `QUERY_GRACE_SECONDS` <a id="constant-QUERY_GRACE_SECONDS"></a> <a id="QUERY_GRACE_SECONDS-constant"></a>
Grace window (seconds) after the first valid response arrives during which
other in-flight host queries may still contribute their outputs.

### `SLAP_TRACKER_TIMEOUT` <a id="constant-SLAP_TRACKER_TIMEOUT"></a> <a id="SLAP_TRACKER_TIMEOUT-constant"></a>
Timeout applied when querying SLAP trackers for host discovery.

## Public Instance Methods
### `find_competent_hosts(service)` <a id="method-i-find_competent_hosts"></a> <a id="find_competent_hosts-instance_method"></a>
Discover competent hosts for `service` via SLAP trackers.

Results are cached for `cache_ttl` seconds. Concurrent callers for the same
service will each trigger their own SLAP query (no in-flight coalescing in
this implementation).
- **@param** `service` [String] lookup service name (e.g. +'ls_foo'+)
- **@return** [Array<String>] array of host URLs

### `initialize(network_preset: = :mainnet, facilitator: = nil, slap_trackers: = nil, host_overrides: = {}, additional_hosts: = {}, reputation_tracker: = nil, cache_ttl: = 300)` <a id="method-i-initialize"></a> <a id="initialize-instance_method"></a>
- **@param** `network_preset` [Symbol] :mainnet, :testnet, or :local
- **@param** `facilitator` [LookupFacilitator, nil] injectable facilitator
- **@param** `slap_trackers` [Array<String>, nil] override default tracker list
- **@param** `host_overrides` [Hash{String=>Array<String>}]
- **@param** `additional_hosts` [Hash{String=>Array<String>}]
- **@param** `reputation_tracker` [HostReputationTracker, nil] injectable tracker
- **@param** `cache_ttl` [Integer] seconds before cached hosts expire
- **@return** [LookupResolver] a new instance of LookupResolver

### `query(question, timeout: = nil)` <a id="method-i-query"></a> <a id="query-instance_method"></a>
Resolve a LookupQuestion by discovering competent hosts and querying them.
- **@param** `question` [LookupQuestion] the question to resolve
- **@param** `timeout` [Integer, nil] per-host query timeout in seconds
- **@raise** [NoCompetentHostsError] if no hosts can be found or all fail
- **@return** [LookupAnswer] merged and deduplicated answer
