# Treeline Analysis - Composite Operation
# Demonstrates DAG validation with multiple steps

id: treeline_analysis
name: Treeline Analysis
description: >
  Compute treeline boundary by combining slope analysis with vegetation index.
  Uses terrain slope and NDVI to identify areas above treeline.
version: 1.0.0
category: analysis
type: composite
default_implementation: native

inputs:
  - name: dem
    type: raster
    format: geotiff
    description: Digital Elevation Model
  - name: imagery
    type: raster
    format: geotiff
    description: Multispectral imagery with red and NIR bands

# Composite rollup of the DAG below:
#   slope step  → requires elevation concept (via terrain_slope)
#   ndvi step   → requires red + nir bands (via raster_ndvi)
#   final step  → thresholds slope + ndvi + dem
requires:
  bands: [red, nir]
  concepts: [elevation]

outputs:
  - name: result
    type: raster
    format: cog
    # No concept slug — binary treeline mask is a recipe-specific
    # derivation, not a canonical concept in registry/concepts/.
    description: Binary treeline mask

# External data sources required
sources:
  dem:
    connector: usgs_3dep
    params:
      resolution: 10m
  imagery:
    connector: sentinel2
    params:
      bands: [B04, B08]

# DAG definition - operations executed in dependency order
dag:
  - id: slope
    op: terrain_slope
    inputs: [dem]
    params:
      smooth: true
      smooth_sigma: 1.5

  - id: ndvi
    op: raster_ndvi
    inputs: [imagery]
    params:
      red_band: B04
      nir_band: B08

  - id: result
    op: raster_calc
    inputs: [slope, ndvi, dem]
    params:
      expression: "(slope > 30) & (ndvi < 0.2) & (dem > 2500)"

# backends: audited 2026-08-14 (defect 50). NOTHING dispatches this op: no arm in folia-engine
# `dispatch_op`, no `registerOp`/OP_TABLE entry in packages/compute, no `_BUILTIN_OP_MAP`
# key in folia/compute.py, no backend manifest. Declared EMPTY on purpose — an absent
# block would be indistinguishable from one nobody ever wrote.
# this record composes other ops in its `dag:` block rather than naming a kernel — but nothing reads an op record's `dag:` (no expander exists in folia/, packages/compute or folia-engine), so the composition is documentation, not a run path.
backends: {}

display_hints:
  map:
    renderer: maplibre
    palette: binary
    opacity: 0.7
  info:
    fields: [above_treeline]
    format: "{value}"
    section: Treeline

output: result
