|
| 1 | +# Response ↔ Impact Boundary Rules |
| 2 | + |
| 3 | +> **Status:** Boundary-rules document accompanying the v1.3 `monty:response_detail` model. It complements [Response Best Practices](response-best-practices.md) by specifying **how to decide, per piece of data, whether something belongs on a Response item, on a paired Impact item, or on neither**. |
| 4 | +
|
| 5 | +The overlap between **Response** and **Impact** is the most common source of ETL modelling |
| 6 | +confusion. A CEMS Grading Product that reports "200 buildings destroyed" is unambiguously a |
| 7 | +**Response** product — an action was taken to produce it — but the building-damage count itself is |
| 8 | +**Impact** data. Without explicit rules, two ETL authors will model the same source record |
| 9 | +differently. |
| 10 | + |
| 11 | +This document publishes a **source-agnostic** decision procedure: a catalogue of recurring data |
| 12 | +patterns, a decision tree an ETL author runs per attribute/layer, the splitting algorithm and exact |
| 13 | +link block to emit, and the queries that re-pair the two halves. |
| 14 | + |
| 15 | +- **Response** = an *action taken or product produced* in response to a disaster (a CEMS map, a Charter VAP, a UNOSAT assessment, an IFRC DREF). |
| 16 | +- **Impact** = an *estimated/realised effect on people or assets* (deaths, people affected, buildings destroyed, economic loss). |
| 17 | + |
| 18 | +> **Scope.** This document is **source-agnostic**. Per-source data-element classification (which |
| 19 | +> Charter / CEMS / UNOSAT / IFRC attribute maps to which pattern) belongs to the analysis |
| 20 | +> deliverable of each source epic, which applies the pattern catalogue below. The governing |
| 21 | +> principle — *"statistical figures go to Impact items"* — is stated in |
| 22 | +> [Response Best Practices §1.5](response-best-practices.md#1-governing-principles); this document |
| 23 | +> operationalises it. |
| 24 | +
|
| 25 | +--- |
| 26 | + |
| 27 | +## 1. Pattern catalogue |
| 28 | + |
| 29 | +Run this catalogue over **each attribute, layer, or table** carried by an incoming response product. |
| 30 | +For every piece of data, find the matching pattern and apply its modelling outcome. The catalogue is |
| 31 | +non-exhaustive; refine it as new source patterns appear. |
| 32 | + |
| 33 | +| # | Data pattern in a Response product | Examples (any source) | Modelling outcome | |
| 34 | +|---|---|---|---| |
| 35 | +| **P1** | **Geometry-only delineation** — a polygon/raster describing event extent, with no per-feature attributes beyond geometry | Flood-extent polygon, fire perimeter, ash-fall area | **Response only.** Geometry on the Response item; no Impact derived. | |
| 36 | +| **P2** | **Categorical classification per feature** — polygons/pixels carry a hazard or damage *class* but no numeric estimate of effect | Damage grade per building polygon (`none` / `minor` / `major` / `destroyed`); `flooded` / `not flooded` per pixel | **Response only** when the class is intrinsic to the product. **Both → split** if the ETL aggregates the classification into a per-class **count** (the count becomes the Impact, see P4). | |
| 37 | +| **P3** | **Numeric estimate of effect on people/assets** — a quantitative figure in human/asset units, regardless of how it was produced | `affected_population: 12300`, `buildings_destroyed: 87`, `hectares_flooded: 1450`, `economic_loss_usd: 2.5e6` | **Impact.** Always becomes one or more Impact items; **never** carried under `monty:response_detail`. | |
| 38 | +| **P4** | **Multi-thematic statistics table** — one numeric estimate per thematic class | CEMS GRA `affected` / `total` per thematic (population, buildings, roads, …) | **Both → split:** one Response item **+ one Impact item per thematic class.** | |
| 39 | +| **P5** | **Provenance / methodology metadata** — analyst, method, software, sensor, processing chain | `producer`, `methodology`, `processing:software`, `sat:platform` on linked acquisitions | **Response only.** Carried under `monty:response_detail.producer` / `methodology` (or on the linked acquisition item for sensor metadata). | |
| 40 | +| **P6** | **Lifecycle / status flag** — production state of the product itself | CEMS `statusCode`, monitoring iteration number | **Response only.** Carried under `monty:response_detail.status` / `monitoring_number`. | |
| 41 | +| **P7** | **Activation / request record** — an administrative entry that *triggers* a response but is not itself a product | Charter activation record, CEMS activation event | **Neither Response nor Impact — it is an Event.** Modelled as a Monty Event item. (See [Response Best Practices §3.2](response-best-practices.md#32-international-charter): Charter activations are Events; only VAPs are Responses.) | |
| 42 | +| **P8** | **Free-text narrative / situational summary** with no machine-readable figures | CEMS Situational Report prose, UNOSAT report PDF | **Response only.** Carries the narrative as an asset. Any figures a human/NLP step extracts from it are then modelled as Impact items in addition (P3). | |
| 43 | +| **P9** | **Pre-event baseline** — reference data of assets/exposure *before* the event | CEMS Reference Map, pre-event population layer | **Response only.** `monty:response_detail.type = eo-ref`. Exposure baselines are **not** Impact items — no realised effect has occurred. | |
| 44 | + |
| 45 | +**Key distinction P3 vs. P9:** a numeric figure is Impact (P3) only when it expresses a *realised |
| 46 | +effect of the event*. A pre-event exposure baseline (P9) is the same kind of number measured *before* |
| 47 | +the event and stays on the Response item. |
| 48 | + |
| 49 | +--- |
| 50 | + |
| 51 | +## 2. Decision tree |
| 52 | + |
| 53 | +Apply this per attribute/layer. It resolves every catalogue pattern to one of four outcomes: |
| 54 | +**Event**, **Response only**, **Impact**, or **Both → split**. |
| 55 | + |
| 56 | +```mermaid |
| 57 | +flowchart TD |
| 58 | + A([Attribute / layer in a Response product]) --> B{Is it an activation /<br/>request record that triggers<br/>a response?} |
| 59 | + B -- yes --> EV[/"Event item<br/>(P7) — not Response, not Impact"/] |
| 60 | + B -- no --> C{Is it a numeric estimate of a<br/>realised effect on people/assets?} |
| 61 | + C -- "yes, single figure" --> IM[/"Impact item (P3)<br/>one monty:impact_detail"/] |
| 62 | + C -- "yes, one figure per thematic class" --> SP[/"Both → split (P4)<br/>1 Response + 1 Impact per thematic"/] |
| 63 | + C -- no --> D{Is it geometry, a per-feature<br/>class, a pre-event baseline,<br/>or narrative?} |
| 64 | + D -- "geometry / class / baseline / narrative" --> RO[/"Response only<br/>(P1, P2, P8, P9)"/] |
| 65 | + D -- no --> E{Is it provenance, methodology,<br/>or a lifecycle/status flag?} |
| 66 | + E -- yes --> RF[/"Response only — carry under<br/>monty:response_detail (P5, P6)"/] |
| 67 | + E -- no --> RO |
| 68 | + RO -. "ETL aggregates a per-feature<br/>class into per-class counts" .-> SP |
| 69 | +``` |
| 70 | + |
| 71 | +**Prose fallback (run top to bottom, first match wins):** |
| 72 | + |
| 73 | +1. **Activation / request record?** → **Event** item (P7). Stop. |
| 74 | +2. **Numeric estimate of a realised effect** on people/assets? |
| 75 | + - Single figure → **Impact** item (P3). |
| 76 | + - One figure per thematic class (a statistics table) → **Both → split** (P4): one Response item + one Impact item per thematic. |
| 77 | +3. **Geometry, per-feature class, pre-event baseline, or free-text narrative?** → **Response only** (P1, P2, P8, P9). *If the ETL later aggregates a per-feature class into per-class counts, those counts re-enter at step 2 as Impacts.* |
| 78 | +4. **Provenance, methodology, or a lifecycle/status flag?** → **Response only**, carried under the relevant `monty:response_detail` field (P5, P6). |
| 79 | + |
| 80 | +--- |
| 81 | + |
| 82 | +## 3. ETL splitting guidance — when and how to split a source record |
| 83 | + |
| 84 | +When a source product matches **P3** or **P4** (it carries realised-effect figures), the ETL |
| 85 | +transformer splits the incoming record into one Response item plus one or more Impact items. |
| 86 | + |
| 87 | +### 3.1 Algorithm |
| 88 | + |
| 89 | +For each incoming source product: |
| 90 | + |
| 91 | +1. **Emit one Response item.** Carry the product type, lifecycle, provenance, geometry, and assets |
| 92 | + per [Response Best Practices](response-best-practices.md). Do **not** put any realised-effect |
| 93 | + figure under `monty:response_detail`. |
| 94 | +2. **For each numeric thematic** in the source (P4: one per thematic class; P3: the single figure), |
| 95 | + **emit one Impact item** carrying that single figure in `monty:impact_detail`. |
| 96 | +3. On every Impact item, add the **`derived_from` → Response** link block (§3.3). |
| 97 | +4. Set the **same `monty:corr_id`** on the Response item and on every paired Impact item. |
| 98 | + |
| 99 | +### 3.2 ID and `corr_id` conventions (idempotent re-pairing) |
| 100 | + |
| 101 | +So that re-running the ETL re-pairs the same items instead of creating duplicates: |
| 102 | + |
| 103 | +- **Shared `monty:corr_id`** on the Response and all its Impacts is the durable join key. Reuse the |
| 104 | + existing Monty `corr_id` format `YYYYMMDDTHHMMSSZ-CCC-HAZ-EPISODE-PROVIDER`. |
| 105 | +- **Deterministic item ids.** Derive Impact ids from the Response `source_id` + thematic, e.g. |
| 106 | + `<source_id>-<thematic>-<impact_type>` (`EMSR-DEMO-001-buildings-destroyed`). Re-runs produce the |
| 107 | + same id → the catalog upserts rather than duplicating. |
| 108 | +- Keep `monty:country_codes` and `monty:hazard_codes` consistent across the paired items. |
| 109 | + |
| 110 | +### 3.3 Exact link block to emit on each Impact item |
| 111 | + |
| 112 | +The canonical provenance edge runs **Impact → Response** (see |
| 113 | +[Response Best Practices §6](response-best-practices.md#6-linkage-summary)). On every Impact item: |
| 114 | + |
| 115 | +```jsonc |
| 116 | +{ |
| 117 | + "rel": "derived_from", |
| 118 | + "href": "response-EMSR-DEMO-001-GRA.json", |
| 119 | + "type": "application/json", |
| 120 | + "roles": ["response"] |
| 121 | +} |
| 122 | +``` |
| 123 | + |
| 124 | +The reverse edge (Response → `rel: related` with `roles: ["impact"]` to each Impact) is an |
| 125 | +**optional back-reference** only; the `derived_from` link above plus the shared `corr_id` are the |
| 126 | +authoritative linkage. |
| 127 | + |
| 128 | +### 3.4 Multi-thematic products (P4) |
| 129 | + |
| 130 | +A CEMS GRA-style statistics table with figures for population, buildings, and roads becomes **one |
| 131 | +Response item and three Impact items** — never a single Impact item bundling all thematics, and never |
| 132 | +the figures stuffed into `monty:response_detail`. Each Impact item carries exactly one |
| 133 | +`monty:impact_detail` object. See the worked fixture under |
| 134 | +[`examples/_response-impact-pairing/`](../../examples/_response-impact-pairing/), which exercises this |
| 135 | +pattern (one `eo-gra` Response → two thematic Impacts). |
| 136 | + |
| 137 | +--- |
| 138 | + |
| 139 | +## 4. Query perspective — re-pairing the two halves |
| 140 | + |
| 141 | +A STAC API consumer reconstructs the paired record using the shared `monty:corr_id` and the |
| 142 | +`derived_from` link. Examples use `cql2-json`, consistent with the |
| 143 | +[STAC API correlation examples](stac-api/correlation_examples.md). |
| 144 | + |
| 145 | +### 4.1 Return both halves of a paired record |
| 146 | + |
| 147 | +All items (Response + Impacts) sharing a `monty:corr_id`: |
| 148 | + |
| 149 | +```json |
| 150 | +{ |
| 151 | + "filter-lang": "cql2-json", |
| 152 | + "filter": { |
| 153 | + "op": "=", |
| 154 | + "args": [ |
| 155 | + {"property": "monty:corr_id"}, |
| 156 | + "20260615T000000Z-DEMO-FL-001-DEMO" |
| 157 | + ] |
| 158 | + } |
| 159 | +} |
| 160 | +``` |
| 161 | + |
| 162 | +### 4.2 Given a Response, find its downstream Impacts |
| 163 | + |
| 164 | +```json |
| 165 | +{ |
| 166 | + "filter-lang": "cql2-json", |
| 167 | + "filter": { |
| 168 | + "op": "and", |
| 169 | + "args": [ |
| 170 | + { |
| 171 | + "op": "=", |
| 172 | + "args": [{"property": "monty:corr_id"}, "20260615T000000Z-DEMO-FL-001-DEMO"] |
| 173 | + }, |
| 174 | + { |
| 175 | + "op": "in", |
| 176 | + "args": ["impact", {"property": "roles"}] |
| 177 | + } |
| 178 | + ] |
| 179 | + } |
| 180 | +} |
| 181 | +``` |
| 182 | + |
| 183 | +### 4.3 Given an Impact, find its source Response |
| 184 | + |
| 185 | +Two equivalent strategies: |
| 186 | + |
| 187 | +- **Follow the link (authoritative):** read the Impact item's `links`, take the entry with |
| 188 | + `rel: derived_from` and `roles: ["response"]`, and dereference its `href`. |
| 189 | +- **Filter by `corr_id` + role:** same query as §4.2 with the `roles` arg set to `"response"`: |
| 190 | + |
| 191 | +```json |
| 192 | +{ |
| 193 | + "filter-lang": "cql2-json", |
| 194 | + "filter": { |
| 195 | + "op": "and", |
| 196 | + "args": [ |
| 197 | + { |
| 198 | + "op": "=", |
| 199 | + "args": [{"property": "monty:corr_id"}, "20260615T000000Z-DEMO-FL-001-DEMO"] |
| 200 | + }, |
| 201 | + { |
| 202 | + "op": "in", |
| 203 | + "args": ["response", {"property": "roles"}] |
| 204 | + } |
| 205 | + ] |
| 206 | + } |
| 207 | +} |
| 208 | +``` |
| 209 | + |
| 210 | +--- |
| 211 | + |
| 212 | +## See also |
| 213 | + |
| 214 | +- [Response Best Practices](response-best-practices.md) — extension layering, field carriage per source, anti-patterns, and the linkage summary. |
| 215 | +- [Response Taxonomy](response-taxonomy.md) — response type codes and the Sendai crosswalk. |
| 216 | +- [STAC API correlation examples](stac-api/correlation_examples.md) — broader CQL2 correlation patterns. |
| 217 | +- [`examples/_response-impact-pairing/`](../../examples/_response-impact-pairing/) — synthetic Response+Impact fixture exercising pattern P4. |
0 commit comments