# Overview

`nexus-stats-detection` collects the advanced change-detection and signal-analysis types from the nexus-stats ecosystem. Each algorithm here implements a specific statistical test — knowing which *hypothesis* you're testing is how you pick the right one.

## Why this crate is separate

The umbrella `nexus-stats` crate has a lot of algorithms, and change-detection specifically pulls in some heavier machinery (windowed MOSUM accumulators, log-likelihood ratios for Shiryaev-Roberts, MAD estimators for robust Z). Splitting it out means you don't pay for what you don't use, and the dependency graph stays clean.

If you're already using `nexus-stats`, enable its `detection` feature and import from there. Depend on this crate directly only when you want a narrower dep tree.

## Design Conventions

Same as the rest of the ecosystem:

- `update(sample) -> Result<..., DataError>` (or `Option<Direction>`, `Option<bool>`, `Decision` — the return type encodes what the detector signals).
- `is_primed()` / `count()` / `reset()` on every type.
- Builder-style construction for anything with more than two parameters.
- O(1) per update, fixed memory. Windowed types allocate once at construction.

## The Return Types

Detection types don't all return the same shape. Know what you're getting:

- **`Option<Direction>`** — None if nothing fired; `Some(Direction::Up)` or `Some(Direction::Down)` on signal. Used by CUSUM and MOSUM.
- **`Option<bool>`** — None before primed, `Some(true)` on trigger. Used by Shiryaev-Roberts.
- **`Option<Condition>`** — None if steady, `Some(Condition::Warning | Critical)` on state transition. Used by MultiGate, ErrorRate.
- **Score** — just `update()` and then query `.z_score()` / `.score()` / `.value()`. Used by AdaptiveThreshold and RobustZScore when you want the raw score rather than a threshold decision.
- **`Decision`** — `Accept`, `Reject`, `Continue`. Used by SPRT.

## Feature Flags

| Feature | Effect |
|---------|--------|
| `std` | Native math via standard library; default. |
| `libm` | `no_std` fallback. |
| `alloc` | Enables `MosumF64`, entropy types, transfer entropy. |

Shiryaev-Roberts, AdaptiveThreshold, and SPRT variants require `std` or `libm`. MOSUM, Entropy, CrossCorrelation, and TransferEntropy require `alloc`.

## no_std

Everything non-windowed and non-log works under `no_std` + `libm`. Add `alloc` for the windowed and histogram-based types. No wall-clock time dependency — these operate on sample streams, not timestamps.

## Composing with the ecosystem

A typical detection pipeline:

```
raw input
   │
   ▼
 [HampelF64 or EmaF64]         pre-filter / smooth
   │
   ▼
 [AdaptiveThresholdF64]        score the residual
   │
   ▼
 [DebounceU32]                 suppress single-sample noise
   │
   ▼
 alert
```

Every stage is O(1) and composable. None of them allocate on the hot path.

## Cross-references

- Basic CUSUM: [`nexus-stats-core::detection::CusumF64`](../../nexus-stats-core/docs/detection.md#cusum--cumulative-sum).
- Smoothing before detecting: [`nexus-stats-smoothing`](../../nexus-stats-smoothing/docs/INDEX.md).
- Composing many detectors: see `choosing.md`.
