cams-aerosol-anomaly
Parameterized ALERT LAYER (docs/spec/ALERTS.md §2.2, §10.2 pilot): fire where the current CAMS AOD550 near-real-time value exceeds its own recent history by more than N sigma over a user-chosen baseline window. The threshold is the USER's, not the operator's — this is the gap the incumbent CAMS Aerosol Alerts service leaves open (it bakes fixed high / very-high / extreme tiers against a 2003–2018 climatology; here `sigma` and `baseline_window` are subscription parameters). The recipe is a TEMPLATE, not a concrete layer. `params: { sigma, baseline_window }` are supplied per-subscription via `layer_params` (ALERTS §2.2), so one σ=2 subscriber and one σ=3 subscriber share the same layer definition without materializing `cams-aod-sigma-2` / `cams-aod-sigma-3` variants. Because the op's z-score is sigma-independent, a stricter σ always yields a SUBSET of a looser σ's firings over the same inputs. Method: 1. Ingest CAMS Global Atmospheric Composition Forecast AOD550 (NRT), windowed to the AOI, gridded onto the alert cell system (H3 r6). 2. Slice `baseline_window` into a per-cell baseline series (the "normal" reference); the newest observation is the `current` value being scored. The event under test is held OUT of the baseline. 3. anomaly_score (folia-engine op): per cell compute μ, σ_baseline, and z = (current − μ) / σ_baseline; fire where current >= μ + sigma·σ_baseline. 4. Emit a cell-indexed alert layer whose `flag`/`z_score` is thresholdable by the subscription (ALERTS §2 alert-layer convention). Separation of concerns (ALERTS §2.2): - Layer math : anomaly_score with the declared parameters - Layer instance : one subscriber's σ=3, another's σ=2 (via layer_params) - Subscription taste: when to actually notify ME (§3 trigger.threshold on the emitted flag/z_score) — NOT the same knob as sigma.
- recipe
- Apache-2.0
- outputs
- CC-BY-4.0
The contract
Read from this recipe's own declarations — parameters:,
outputs:, requires:, and the ops its layers name. Not from its
style blocks and not from any benchmark: a colour ramp is not a contract, and a measured
run is evidence about one AOI rather than a domain.
Parameters
The legacy dialect has no typed parameter schema. Read the folia.yaml for what this recipe takes; nothing here can type-check it.
Outputs
| output | kind | layer | what it is |
|---|---|---|---|
primary |
not declared | ['alerts/cams-aerosol-anomaly'] |
|
show_your_work |
not declared | ['source/cams-aod'] |
|
provenance |
not declared | ['cams_run_datetime', 'baseline_window_start', 'baseline_window_end', 'sigma_applied'] |
Capabilities it requires
The legacy dialect has no requires: block.
Where it runs
- Browser preview does not run here alerts/cams-aerosol-anomaly: carries an unsubstituted ${...} template; source/cams-aod: layer type "raster_timeseries" is not one folia-view parses
- Local CLI (folia run) runs here runs locally through the legacy (no spec_version) parser
- Operated fleet (POST /plan, /run) runs here legacy dialect: a lock binds by the cut's layer names, not by digest
registry/recipes/cams-aerosol-anomaly/folia.yaml