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

**Inherits:** `Object`

Tracks per-host reputation for overlay query dispatch.

Records success and failure events per host, maintains an EWMA latency
estimate, applies exponential backoff after repeated failures, and ranks a
candidate host list so callers can prefer fast, reliable hosts.

Thread-safe via an internal Mutex.

An optional `store` adapter may be supplied for persistence. The adapter must
respond to +#get(key)+ and +#set(key, value)+. When provided, each updated
entry is persisted and unknown hosts are loaded on first access.

## Constants
### `BASE_BACKOFF_MS` <a id="constant-BASE_BACKOFF_MS"></a> <a id="BASE_BACKOFF_MS-constant"></a>
Starting backoff duration in milliseconds.

### `DEFAULT_LATENCY_MS` <a id="constant-DEFAULT_LATENCY_MS"></a> <a id="DEFAULT_LATENCY_MS-constant"></a>
Fallback latency used when no measurements exist yet, or when an invalid
(negative / non-finite) value is reported.

### `FAILURE_BACKOFF_GRACE` <a id="constant-FAILURE_BACKOFF_GRACE"></a> <a id="FAILURE_BACKOFF_GRACE-constant"></a>
Number of consecutive failures that are forgiven before backoff kicks in. A
host may fail this many times without being penalised with a backoff window.

### `FAILURE_PENALTY_MS` <a id="constant-FAILURE_PENALTY_MS"></a> <a id="FAILURE_PENALTY_MS-constant"></a>
Latency penalty added to a host's score per consecutive failure.

### `LATENCY_SMOOTHING_FACTOR` <a id="constant-LATENCY_SMOOTHING_FACTOR"></a> <a id="LATENCY_SMOOTHING_FACTOR-constant"></a>
EWMA smoothing factor (α). Higher values give more weight to recent
observations; lower values produce a smoother, more stable estimate.

### `MAX_BACKOFF_MS` <a id="constant-MAX_BACKOFF_MS"></a> <a id="MAX_BACKOFF_MS-constant"></a>
Maximum backoff duration in milliseconds (60 seconds).

### `SUCCESS_BONUS_MS` <a id="constant-SUCCESS_BONUS_MS"></a> <a id="SUCCESS_BONUS_MS-constant"></a>
Latency bonus subtracted from a host's score per recorded success, capped at
half the current average latency.

## Public Instance Methods
### `initialize(store: = nil)` <a id="method-i-initialize"></a> <a id="initialize-instance_method"></a>
- **@param** `store` [#get, #set, nil] optional persistence adapter
- **@return** [HostReputationTracker] a new instance of HostReputationTracker

### `rank_hosts(hosts, now = Time.now)` <a id="method-i-rank_hosts"></a> <a id="rank_hosts-instance_method"></a>
Ranks `hosts` for query dispatch.

Steps:
1.  Filter nil and empty-string entries.
2.  Deduplicate preserving first occurrence order.
3.  Compute a score for each host.
4.  Sort: available hosts first (score asc, then total_successes desc, then
    original position asc), followed by backed-off hosts (backoff_until asc).
- **@param** `hosts` [Array<String>] candidate host list
- **@param** `now` [Time] reference time (default: Time.now)
- **@return** [Array<String>]

### `record_failure(host, reason = nil)` <a id="method-i-record_failure"></a> <a id="record_failure-instance_method"></a>
Records a failed request to `host`.

Increments failure counters. Once consecutive failures exceed
`FAILURE_BACKOFF_GRACE`, an exponential backoff window is set.

DNS-level errors (`SocketError`, <code>Errno::ECONNREFUSED</code>, or messages
containing 'getaddrinfo' or 'Failed to fetch') skip the grace period entirely
— backoff is applied from the very first such failure.
- **@param** `host` [String] hostname or URL
- **@param** `reason` [Exception, String, nil] error that caused the failure

### `record_success(host, latency_ms)` <a id="method-i-record_success"></a> <a id="record_success-instance_method"></a>
Records a successful request to `host`.

Updates the EWMA latency estimate (first success sets the average directly;
subsequent successes apply smoothing). Resets consecutive failure count and
clears any active backoff window.
- **@param** `host` [String] hostname or URL
- **@param** `latency_ms` [Numeric] observed round-trip time in milliseconds

### `reset()` <a id="method-i-reset"></a> <a id="reset-instance_method"></a>
Clears all in-memory reputation data.

### `snapshot(host)` <a id="method-i-snapshot"></a> <a id="snapshot-instance_method"></a>
Returns a frozen copy of the internal entry hash for `host`, or `nil` if the
host is unknown and not in the store.
- **@param** `host` [String]
- **@return** [Hash, nil]
