# `sampling.ts` _(no submodules)_ ## Purpose Implements head-based sampling for `@suaveplan/analytics-browser`. The tracker calls `sampler.shouldSample(event)` after the consent gate but before the scrubber so events that will be dropped never pay the cost of property scrubbing or queue persistence. `HeadSampler` accepts a base sample rate in `[0, 1]` plus an optional `Record` override map so common events (e.g. `page`) can be captured at a different rate than rare events (e.g. `error_reported`). ## Features - Per-event-name overrides — `new HeadSampler(0.1, { error_reported: 1 })` keeps every error while sampling everything else at 10 %. - Strict clamping — rates `<= 0` always drop, rates `>= 1` always keep; `NaN` clamps to 0. - Injectable random source — the constructor accepts a `random: () => number` seam so tests can drive deterministic decisions without monkey-patching `Math.random`. - Stateless — every call is independent; safe to share a sampler across many trackers. ## Usage: Basic ```ts import { HeadSampler } from "@suaveplan/analytics-browser/sampling"; const sampler = new HeadSampler(0.25); // keep 25 % of events ``` ## Usage: Advanced ```ts import { HeadSampler } from "@suaveplan/analytics-browser/sampling"; // 1 % sampling for verbose page-view events, 100 % for clicks and errors. const sampler = new HeadSampler(0.01, { clicked: 1, error_reported: 1, }); // In tests, inject a deterministic counter so behaviour is reproducible. let n = 0; const deterministic = new HeadSampler(0.5, {}, () => { const sequence = [0.4, 0.6, 0.2, 0.8]; return sequence[n++ % sequence.length] as number; }); ``` ## API Reference - `class HeadSampler implements Sampler` - `new HeadSampler(rate, overrides?, random?)` - `rate: number` — base rate in `[0, 1]`. Values outside this range clamp. - `overrides?: Readonly>` — per-event-name rate. Each entry clamps independently. - `random?: () => number` — random source; defaults to `Math.random`. - `shouldSample(event): boolean` — `true` keeps the event, `false` drops it. ## Implementation Notes The clamp logic guards against floating-point drift and pathological caller input (e.g. accidentally passing `rate=2`). NaN clamps to 0 rather than 1 so a misconfigured environment variable does not silently flood the backend. The injected random source enables deterministic testing without resorting to `vi.stubGlobal` (banned by §2 of `AGENTS.md`).