hazard-detector
Wetland and forest CHANGE over a Gulf Coast county, delivered as a subscribable alert and ranked by community vulnerability. Two Sentinel-2 composites per AOI — a baseline window and a current window — give NDVI (vegetation vigour) and MNDWI (open water / wetland inundation). The bitemporal deltas fire two independent arms: vegetation LOSS when NDVI drops past a threshold, wetland CHANGE when MNDWI moves either direction past a threshold. A cell fires if either arm crosses, and carries both deltas plus which arm drove it, so a reader sees "NDVI 0.75 -> 0.35 (-0.40) => forest loss" rather than a bare boolean. What the incumbent self-serve alert surfaces never combine is the second half: each firing is joined to its CDC/ATSDR Social Vulnerability Index tract and carries that tract's percentile, so county planners and emergency managers (MEMA / Gulf Coast counties, the named end-users) can triage by who is least able to absorb the change. The SVI RANKS delivery. It never gates detection — the fire set is identical at every svi_floor. The detector is not novel science and does not try to beat GFW or DIST-ALERT at detection. What it demonstrates is subscription + vulnerability-contextualized delivery to non-developer end-users, composed entirely from shipped ops (imagery_composite + stack_concat + raster_calc). No new op.
- 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
| parameter | type | domain | default | what it does |
|---|---|---|---|---|
aoi_bbox |
bbox | [-89.6,30.15,-89,30.55] |
Watched extent [w, s, e, n] in WGS84. Default covers Hancock/Harrison County on the Mississippi Gulf Coast — the ms-wetlands study area. A subscription overrides this with the county geometry it watches. | |
baseline_start |
string | 2023-01-01 |
Start of the BEFORE reference window. | |
baseline_end |
string | 2023-12-31 |
End of the BEFORE reference window. A full calendar year by default, so the median composite averages over a whole phenological cycle rather than one season — a baseline built from summer scenes alone would read every winter current-window composite as vegetation loss. | |
current_start |
string | 2026-01-01 |
Start of the AFTER window under test. | |
current_end |
string | 2026-06-30 |
End of the AFTER window under test. Shorter than the baseline on purpose: this is the recent state, and a subscription's dispatcher advances it as new overpasses land (see extensions.folia/freshness-ref). | |
veg_loss_threshold |
number | >= 0, <= 2 | 0.15 |
NDVI drop that counts as vegetation/forest loss. The veg arm fires where (ndvi_baseline - ndvi_current) >= this value. |
wet_change_threshold |
number | >= 0, <= 2 | 0.15 |
|MNDWI| change that counts as wetland change. The wetland arm fires where |mndwi_current - mndwi_baseline| >= this value. Magnitude, not sign: a marsh that floods and a marsh that dries are both changes an emergency manager wants. |
min_affected_area |
integer | >= 1 | 3 |
Minimum contiguous fired cells before the SUBSCRIPTION notifies (it maps to the trigger's `min_cells`, ALERTS §3). It suppresses single-cell speckle; it does not change what the detector flags. |
svi_floor |
number | >= 0, <= 1 | 0 |
OPTIONAL vulnerability triage on DELIVERY. When greater than 0, only firings whose containing tract's SVI percentile (RPL_THEMES) is at or above this value are delivered; every delivered firing carries its SVI context either way. |
composite_method |
string | one of median, mean, min, max | median |
Per-pixel reduction over the scene stack in each window. Median by default because it is the reduction that survives residual cloud the SCL mask missed — a mean lets one bright cloud edge pull a whole composite. |
scene_limit |
integer | >= 1 | 24 |
Scene budget PER YEAR, not per window (imagery_composite stratifies its search by year). At 24 the 2023 baseline draws up to 24 scenes and the 2026 current window up to 24 more. WHY 24: roughly one clear-ish Sentinel-2 pass per fortnight, which is enough for a stable annual median over a cloudy subtropical coast; the op default of 6 admits visible cloud residue into the median at this latitude. |
target_resolution_m |
number | >= 1 | 20 |
Grid all four composites snap to, in metres. |
Outputs
| output | kind | layer | what it is |
|---|---|---|---|
hazard |
raster | alerts/hazard-detector |
THE hazard output: per-cell change score, thresholdable at 1.0. A subscription watches this layer; a crossing becomes a firing carrying the deltas, the driving arm, and the affected tract's SVI percentile (extensions.folia/firing-provenance). |
dndvi |
raster | compute/dndvi |
Bitemporal NDVI change (current - baseline) behind the vegetation arm. |
dmndwi |
raster | compute/dmndwi |
Bitemporal MNDWI change (current - baseline) behind the wetland arm. |
ndvi_baseline |
raster | compute/ndvi-baseline |
The BEFORE vegetation composite. |
ndvi_current |
raster | compute/ndvi-current |
The AFTER vegetation composite. |
mndwi_baseline |
raster | compute/mndwi-baseline |
The BEFORE water/wetland composite. |
mndwi_current |
raster | compute/mndwi-current |
The AFTER water/wetland composite. |
Capabilities it requires
Declares no requires: block, so it asks nothing of a host beyond the engine itself.
Where it runs
- Browser preview does not run here alerts/_delta-stack: depends on layer "compute/dndvi", which cannot run here; alerts/hazard-detector: depends on layer "alerts/_delta-stack", which cannot run here; compute/dmndwi: depends on layer "compute/dmndwi-stack", which cannot run here; and 7 more
- Local CLI (folia run) runs here runs locally through the governed folia/0.1 parser
- Operated fleet (POST /plan, /run) runs here binds to a canonical digest, so a lock is checked by digest equality
registry/recipes/hazard-detector/folia.yaml