# `ExDataSketch.Hash.Validation`
[🔗](https://github.com/thanos/ex_data_sketch/blob/main/lib/ex_data_sketch/hash/validation.ex#L1)

Compatibility checks for hash configurations across merging sketches.

Two sketches may only be merged when their hashing configuration is provably
identical. This module centralizes that check and is used by all sketch
modules' `merge/2` operations from v0.8.0 onward.

The existing `ExDataSketch.Hash.validate_merge_hash_compat!/3` remains as a
thin compatibility shim that delegates here, so external callers do not
experience a breaking change.

## What counts as compatible?

- Same hash strategy (`:phash2 | :xxhash3 | :murmur3`).
- Same seed.
- Neither side uses `:custom` (closure-based hashes cannot be compared
  structurally and so cannot be proven compatible).

## What counts as compatible across metadata blocks?

When both sketches carry an `ExDataSketch.Hash.Metadata` block, the check is:

- same `algorithm`;
- same `seed`;
- same `sketch_family`;
- `sketch_family_version` compatible (equal, or both sides explicitly support
  forward compatibility — currently equal only).

`block_version`, `backend`, and `flags` are intentionally NOT part of the
equivalence relation: identical hash output across a Rust/Pure split or a
block-version bump is the whole point of the binary contract.

# `compatible_options?`

```elixir
@spec compatible_options?(Keyword.t(), Keyword.t()) :: boolean()
```

Returns `true` when the given two option sets describe compatible hashing,
`false` otherwise. Never raises.

Useful in code paths that want to make a decision without exception flow.

## Examples

    iex> ExDataSketch.Hash.Validation.compatible_options?([hash_strategy: :xxhash3], [hash_strategy: :xxhash3])
    true

    iex> ExDataSketch.Hash.Validation.compatible_options?([hash_strategy: :xxhash3], [hash_strategy: :phash2])
    false

# `validate_metadata!`

```elixir
@spec validate_metadata!(
  ExDataSketch.Hash.Metadata.t(),
  ExDataSketch.Hash.Metadata.t(),
  String.t()
) ::
  :ok
```

Validates that two `ExDataSketch.Hash.Metadata` blocks describe compatible
sketches.

Raises `ExDataSketch.Errors.IncompatibleSketchesError` on mismatch.
Returns `:ok` on success.

## Examples

    iex> a = ExDataSketch.Hash.Metadata.new(:xxhash3, 0, 1, 1, :pure)
    iex> b = ExDataSketch.Hash.Metadata.new(:xxhash3, 0, 1, 1, :rust)
    iex> ExDataSketch.Hash.Validation.validate_metadata!(a, b, "HLL")
    :ok

    iex> a = ExDataSketch.Hash.Metadata.new(:xxhash3, 0, 1, 1, :pure)
    iex> b = ExDataSketch.Hash.Metadata.new(:murmur3, 0, 1, 1, :pure)
    iex> try do
    ...>   ExDataSketch.Hash.Validation.validate_metadata!(a, b, "HLL")
    ...> rescue
    ...>   ExDataSketch.Errors.IncompatibleSketchesError -> :raised
    ...> end
    :raised

# `validate_options!`

```elixir
@spec validate_options!(Keyword.t(), Keyword.t(), String.t()) :: :ok
```

Validates that two keyword-list option sets describe compatible hash
configurations.

Raises `ExDataSketch.Errors.IncompatibleSketchesError` on mismatch.
Returns `:ok` on success.

## Examples

    iex> ExDataSketch.Hash.Validation.validate_options!([hash_strategy: :xxhash3, seed: 0], [hash_strategy: :xxhash3, seed: 0], "HLL")
    :ok

    iex> try do
    ...>   ExDataSketch.Hash.Validation.validate_options!([hash_strategy: :xxhash3], [hash_strategy: :phash2], "HLL")
    ...> rescue
    ...>   ExDataSketch.Errors.IncompatibleSketchesError -> :raised
    ...> end
    :raised

---

*Consult [api-reference.md](api-reference.md) for complete listing*
