Volume Anomalies

What this sheet teaches. Detect sender-recipient pairs whose money flow spikes outside their own rolling baseline. The volume anomalies sheet flags unusual transfer patterns by comparing each 2-day window against the per-pair mean and standard deviation across all that pair's history.

What you're looking at

A KPI strip at the top shows Flagged at current σ — the count of pair-windows meeting the sigma threshold you've set. Below that, a Pair-Window σ Distribution bar chart breaks the entire population into sigma buckets, showing where the full dataset sits relative to your threshold. The chart stays unfiltered as you move the slider, so you can see the population shape before deciding how tight to set the cutoff. Finally, a Flagged Pair-Windows — Ranked table shows every (sender, recipient, window) that crossed your threshold, ranked by z-score descending (furthest from the population mean at the top). A Window End Date picker lets you narrow by date range; a Min sigma slider adjusts the threshold.

How to read the numbers

The sheet reads from the <prefix>_inv_pair_rolling_anomalies matview, which computes a 2-day rolling window for every (sender, recipient) pair and calculates its z-score against that pair's own historical distribution.

Per-pair z and the min-n floor

The matview uses a per-pair PARTITION BY z formula (introduced in Phase CV, 2026-06-09). For each (sender, recipient) pair the matview computes AVG(window_sum) OVER (PARTITION BY pair) and STDDEV_SAMP(window_sum) OVER (PARTITION BY pair) — so each window's z-score is measured against its own pair's history, not a global population.

This is the semantically correct shape — a pair's biggest day relative to its own pattern IS the most anomalous — but it requires enough history per pair to compute a meaningful divisor. The matview enforces a min-n floor: pairs with fewer than INV_MIN_HISTORICAL_WINDOWS=3 total observations get z_score = 0 regardless of magnitude. This collapses one-shot pairs (no signal) and very-shallow-history pairs (estimate unreliable) into the '0-1 sigma' bucket.

There's a mathematical consequence: under the inclusive PARTITION BY frame, a single outlier's z-score asymptotes at N / sqrt(N+1) where N is the pair's window count. For a pair with 20 prior windows + 1 spike, the spike's z caps at ≈4.36. For pairs with longer history (e.g. 90 days of seed data), the cap is higher. This bounds noise: under the pre-CV global-z formula spec_example's top observed z was 8.62 and sasquatch_pr's was 25.84; post-CV, both L2s' top observed z is ≈6.

The Flagged at current σ KPI counts rows where z_score >= <<$pInvAnomaliesSigma>> (the slider's current value). The Pair-Window σ Distribution chart groups the full population by z_bucket so you see the shape unfiltered. The Flagged Pair-Windows table applies the sigma filter and ranks by z_score descending.

Common patterns

High z-score on a normally-quiet pair

One row, z-score of 3+ or 4+, a pair that's usually under-the-radar. This is a genuine anomaly — the pair's window sum is far outside its population baseline. Drill into the table row to see which transfers fired in that window and whether they're legitimate or suspicious.

Entire population clustered in "0-1 sigma"

The distribution chart shows almost all pair-windows bunched in the leftmost bucket. Under per-pair z this means most pairs have low day-to-day variance — each window is close to its pair's baseline. The sigma slider's default is 2; widen it left to flag the borderline cases or right to focus on the extreme tail.

Pairs with very shallow history (< 3 windows total) automatically land in '0-1 sigma' due to the matview's min-n floor — there's not enough signal to compute a meaningful z-score. If your operators see a brand-new pair that has only fired once or twice and expect it to surface as anomalous, the floor is doing its job; widen the time window so the pair accumulates enough observations.

Pairs flagged across many window dates

The table has dozens of rows for the same (sender, recipient), dates spanning weeks or months. This is recurring behavior, not a spike — the pair's transfers consistently exceed the population baseline. It may be legitimate (a high-volume partner that trades frequently) or suspicious (a relationship worth deeper audit). Cross to the Money Trail sheet with the sender or recipient account to trace where the money originated and where it lands.

Distribution shows tail but z-score KPI is zero

The bar chart clearly renders high-sigma buckets ("3-4 sigma", "4+ sigma") but the Flagged at current σ KPI shows zero. The threshold you've set is tighter than the extreme data points — you're asking for pairs 4+ sigmas away while the tail sits at 2–3. Drag the sigma slider left to widen the net and flag the data you see in the chart.

What "no rows" means

A clean anomalies sheet means every (sender, recipient) pair-window in the window sits within your sigma cutoff. That is the expected steady-state — the sheet flags OUTLIERS, not routine activity. If you see zero rows:

Cross-sheet drills

The Volume Anomalies sheet has no drills defined. The table rows are reference data for further investigation; navigate to other sheets (Money Trail, Account Network) via their anchor or root-transfer controls once you've identified an account pair of interest.


First time here? See the Vocabulary for matview, account_role and the other project-specific terms.