The anomaly block declares how this Vial turns a stream into a decision. The host compiles it into a detector owned by the Vial. The base app keeps its own detector; a Vial cannot loosen the host's refusal or raise the base alert level.
A profile cannot lower the per-sample noise floor of the array. It can change how often noise becomes an episode a person sees, at a stated latency and minimum detectable effect. There are four levers:
| Lever | Field | What it buys | What it costs |
|---|---|---|---|
| Persistence | detection.escalation.warningS | A transient shorter than the window never becomes a warning. | A real change that resolves faster than the window is missed. |
| Hysteresis | detection.hysteresis | A signal hovering at the threshold cannot chatter. | The alert stays latched until the signal falls well below the peak. |
| Context admissibility | admissibility | Refuses to arm without a ready baseline and enough live, non-dead channels. | A degraded rig shows a refusal instead of a number. |
| Operating point | sensitivity, minChannels, perChannelLimits | Moves the trade-off between missed changes and false alarms. | Every gain in sensitivity costs specificity; no setting gives both for free. |
| Field | Range | Effect |
|---|---|---|
baseline.protocol | first-n | session-mean | How the UI chooses the R0 reference for the response series. The detector's calibration is separate. |
baseline.warmupS | 0.5–86400 | Wall-clock seconds of clean readings before the detector trusts a baseline. The engine still refuses to score until calibration succeeds. |
baseline.r0WindowS | 0.5–3600 | Seconds of the early series used as R0 by the UI transform. It must be shorter than the warm-up or the UI has fewer early samples than declared. |
The leak preset is not universal. A leak may establish a baseline in seconds; a fermentation batch, a soil column, or a slow spoilage process may need minutes to hours. The profile owns the window. Shortening the warm-up to make a demo feel responsive is how a detector learns the wrong normal.
| Field | Supported values | Meaning |
|---|---|---|
transforms.conditioning | median3 | A three-sample median filter. It suppresses single-sample spikes before the response is computed. |
transforms.response | delta-over-r0 | relative | delta | delta-over-r0 is (x − R0) / R0; relative is x / R0; delta is x − R0. |
The response mode determines the units of perChannelLimits. A limit of 0.12 means a 12% change for delta-over-r0 and 0.12 sensor units for delta. Do not copy a limit between modes.
In v2 the host compiles the profile into a detector owned by the Vial. The engine's multivariate verdict and the declared bands are combined: an alert requires the engine to see a sustained change and at least minChannels channels to clear their band. The bands are a corroboration gate, not a decorative display. A profile with no bands uses the engine verdict alone.
| Field | Range | Effect |
|---|---|---|
detection.enabled | boolean | Compiles the profile but keeps it disarmed. The UI can still show baseline state. |
detection.sensitivity | 0.1–10 | The engine's operating point. Higher values flag smaller deviations and admit more noise. |
detection.minChannels | 1–32 | Minimum channels that must clear their budget before the multivariate claim is trusted. 2+ demands corroboration. The same floor applies to the declared bands in v2. |
detection.levelBudget | 0–12σ | An absolute level-anchored threshold. 0 disables the level leg. |
detection.levelRefS | 0–86400 | Rolling reference seconds for the level leg. 0 uses the fixed calibration baseline. A non-zero value requires a non-zero level budget. |
detection.alertThreshold | 0–1 | Confidence floor for the per-channel band. The engine's level budget remains the statistical threshold. In v2 the host requires the engine verdict and the band gate to agree. |
detection.perChannelLimits | channel id → positive number | Absolute response bands in transformed units. A channel with no limit does not contribute a band trigger. An empty map uses the engine verdict alone. |
detection.hysteresis | 0–0.95 | How far below the peak the signal must fall before the level can clear. 0 clears on the reset timer alone. |
detection.farTargetPerMonth | ≥ 0 or null | The deployment false-alarm budget the author is designing to. The evidence block holds the measured numbers. |
The escalation ladder is a set of wall-clock timers, not sample counts. That makes the same profile behave the same on a 2 Hz rig and a 25 Hz logger.
| Field | Meaning |
|---|---|
escalation.warningS | Seconds of continuous anomaly before warning. This is the persistence lever. |
escalation.criticalS | Seconds before critical. Must be at least warningS. |
escalation.emergencyS | Seconds before emergency. Must be at least criticalS. |
escalation.resetNormalS | Seconds of continuous normal readings before a raised level can clear, subject to hysteresis. |
// Slow fermentation: a 30 s blip is noise.
"escalation": { "warningS": 30, "criticalS": 120, "emergencyS": 300, "resetNormalS": 300 }
// Fast bench assay: a 30 s alarm is already late.
"escalation": { "warningS": 0.5, "criticalS": 2, "emergencyS": 5, "resetNormalS": 10 }These are durations, not claims about performance. The evidence block and the fixture must show that the chosen durations produce the states the author expects on a real or deterministic sequence.
| Field | Meaning |
|---|---|
admissibility.requireBaseline | ready means the host refuses to arm before the baseline is ready. any allows the UI to open while warming, but the detector still does not score. |
admissibility.minCoverage | Minimum fraction of declared channels that must be live and non-dead. A dead channel is a refusal. |
Separate two numbers that are often conflated:
A deployment budget of one false alarm per month is roughly 3.9 × 10⁻⁷ per sample at a 10 Hz duty cycle. Raw real-corpus rates are orders of magnitude above that, so a profile that claims a monthly budget must state the persistence, the latency, and the minimum detectable effect it paid. The measured foundations are in the engine design notes; this page does not restate them as marketing numbers.
A profile cannot retroactively relabel an alarm. If the detector fired, the episode happened. Persistence and hysteresis change which future samples fire; they do not erase the past.
A v2 UI cannot call setDetection or setTransforms. Those calls exist for legacy manifests. The profile is immutable at runtime; to change it, publish a new version and let the hash-verified update replace it.
A osmograph.domain-pack/1 manifest has no anomaly block. It installs as Ungated and its UI may call setTransforms and setDetection at runtime. That path is kept for compatibility; it is not eligible for a new listing. New Vials use v2.