name: goes-fdc-fire
version: "0.1"
category: events-hazards
themes: [hazards]
family: active-fire-nrt-hotspot-detection
answers_verb: alert
description: >
  Active-fire alerts read from the SOURCE product rather than from a vendor
  feed: NOAA's GOES-R ABI L2 Fire/Hot-Spot Characterization (ABI-L2-FDC), taken
  straight off the public NOAA Open Data S3 buckets.

  This is the same operational detection that NASA FIRMS re-serves for GOES —
  verified, not asserted: over the Palisades Fire ignition window, reading
  ABI-L2-FDCF and keeping the four mask codes FIRMS exports reproduces the FIRMS
  rows at F1 1.0000 with FRP equal to within the CSV's rounding
  (research/fire-detection-cloud-native/VALIDATION.md).

  Reading the source is what buys the difference:
    - cadence: ABI-L2-FDCC is a 5-min CONUS scan; FIRMS ingests the 10-min Full Disk.
    - fields: fire Temp (K), Area (m2) and DQF, all dropped by the FIRMS CSV.
    - YOUR threshold: FIRMS exports only mask 10/11/30/31 and silently discards
      the probability classes. In three hours over an active megafire it withheld
      18 high-probability fire pixels. Here `min_class` is a parameter, so the
      subscriber decides what counts as a fire — not the vendor.
    - provenance: S3 objects are immutable and carry an ETag, so a firing commits
      the exact bytes it was derived from, not a hash of rows seen at query time.

  What it does NOT claim: earlier detection. Same product, same scan, same
  pixels as FIRMS. The win is resolution, completeness, control and auditability.

alert_layer: alerts/goes-fdc-fire
type: computed
geo: { cell_system: h3, resolution: 8 }

cooldown_default: 6h
min_confidence: 0.5

params:
  satellite:
    type: enum
    enum: [G16, G18, G19]
    default: G18
    description: >
      Which GOES. Geostationary coverage is the satellite disk — the Americas.
      There is no geostationary option outside it; use a polar source elsewhere.
  product:
    type: enum
    enum: [ABI-L2-FDCC, ABI-L2-FDCF, ABI-L2-FDCM]
    default: ABI-L2-FDCC
    description: "CONUS 5 min | Full Disk 10 min (what FIRMS uses) | Mesoscale ~1 min."
  min_class:
    type: enum
    enum: [good_only, firms_equivalent, include_high_prob, all_fire]
    default: include_high_prob
    description: >
      Which fire-mask classes count as a firing. good_only = 10/30;
      firms_equivalent = 10/11/30/31 (exactly what FIRMS exports);
      include_high_prob = adds 13/33; all_fire = every fire class incl.
      cloud-contaminated and low-probability. This is the parameter FIRMS
      does not expose.
  min_frp_mw:
    type: number
    default: 0
    description: "Optional fire-radiative-power floor (MW). 0 = no FRP gate."

inputs:
  fdc:
    dataset: "@noaa/goes-abi/l2-fdc"
    connector: connectors.goes_fdc.adapter    # S3 object-arrival poll + netCDF -> detections
    params:
      satellite: ${params.satellite}
      product: ${params.product}

compute:
  op: feed_threshold
  inputs:
    detections: { input: fdc }
  params:
    value: confidence_norm                    # mask class -> [0,1]; see connector
    threshold: ${params.min_confidence}
    min_class: ${params.min_class}
    min_frp_mw: ${params.min_frp_mw}
    commit_source_object: true                # firing.inputs = {key, etag, sha256}

outputs:
  primary:
    - alerts/goes-fdc-fire
  show_your_work:
    - fdc                                     # the source scan object behind each firing

license:
  recipe: Apache-2.0
  output_dataset: public-domain
  upstream_data:
    - { source: "@noaa/goes-abi/l2-fdc", license: public-domain }

# Object-arrival, not feed-poll: the dispatcher watches for the next scan key to
# appear (~3 min after scan start) rather than re-querying a mutable feed.
freshness_source: "@noaa/goes-abi/l2-fdc#noaa-odd-s3"

reproduction:
  # Tested end to end; see VALIDATION.md for the recorded run.
  extract: research/fire-detection-cloud-native/repro/goes_fdc.py
  validate: research/fire-detection-cloud-native/repro/validate_vs_firms.py
