# Expert Knowledge: Cascade Chain Extraction Rules ## Scope & Budget The downstream task is **predicting major cascade risks** for new flood events. Capture the full cascade structure — every consequence the news articles report as a notable downstream effect should appear as a node. - **Grounding (hard rule).** Every node MUST correspond to a specific consequence that is *literally stated* in the input articles — named places, named infrastructure, reported numbers, named institutions, named programs. Do NOT add a node because "this typically follows a flood"; only add a node if the articles report it. Hallucinated nodes pollute the dataset and are worse than missing ones. - **Sparse-input rule.** If the articles are too thin to support extraction (e.g. only a headline confirming a flood occurred, with no specific consequences), it is *correct* to return very few nodes (0–3). Empty `cascade_events: []` is acceptable when no concrete consequences are reported. Do NOT pad to hit a target. - **Maximum 40 cascade nodes per event.** If the articles describe more than 40 distinct effects, keep only the most consequential. - **Target density (only for events with rich news coverage):** 12–25 nodes when the articles together provide multiple paragraphs of concrete consequences across several sources. Producing fewer than ~8 from such rich coverage is a strong signal you are being too restrictive — re-audit. **Do not apply the density target to thin-input events** (single short article, one-liner headline) — there, sparse output is correct output. - **Time window: 2 weeks (336 hours after flood onset).** Anything later — long-term reconstruction, insurance settlements, multi-month mental-health impacts — is out of scope. - **What counts as a node.** A node is worth recording if it meets AT LEAST ONE of: - Reported casualties (deaths, missing, serious injuries — even one person) - People evacuated, displaced, sheltered, or without essential services (any reported number) - A service disruption (power, water, transport, telecom, hospital) lasting more than a couple of hours, or affecting a named population/area - Quantified or qualitatively-described economic damage (property, inventory, agricultural, business closure) - Named infrastructure damage (substation, bridge, treatment plant, hospital wing, school, etc.) - Government / institutional response (state of emergency declaration, school closures, evacuation orders, military deployment, international aid request) - Environmental contamination or chemical spill events - Triggers a further cascade in a different domain (e.g. power loss → hospital crisis) - **What to skip.** One-street road closure that resolved within an hour and didn't disrupt anyone, brief individual panic anecdotes without broader effect, social-media noise, single-business minor inventory issues. The bar is "did this affect a named population, named infrastructure, or quantifiable damage?" — if yes, include it; if no, skip it. If the news mentions distinct effects in different communes / municipalities / domains, prefer to keep them as separate nodes rather than merging into a generic "widespread X" — separate nodes carry more predictive signal. ## Closed Domain Taxonomy (pick EXACTLY one per node) You MUST use one of these 12 labels. Do not invent new ones. - `infrastructure/power` — electricity grid outages, substation damage, generator failure - `infrastructure/water` — drinking water supply, wastewater, sewage overflow - `infrastructure/transport` — roads, rail, airports, ports, bridges - `infrastructure/communication` — telecom, internet, cellular, emergency radio - `health/casualties` — deaths, missing persons, serious injuries - `health/hospital_service` — hospital operations, ICU capacity, medical supply, evacuation of patients - `health/disease_outbreak` — waterborne disease, infection clusters, epidemic risk - `social/evacuation` — mandatory or advised evacuation, displacement, emergency sheltering, housing loss - `social/supply_shortage` — food, fuel, medicine, essentials unavailable in affected zone - `economy/business_damage` — business property / inventory / revenue losses, closures - `economy/agriculture` — crop loss, livestock losses, farmland inundation - `environment/contamination` — chemical spills, polluted water bodies, soil contamination ## Severity Scale (use quantitative thresholds) - **critical** — deaths reported, national-level emergency response, > 100 000 people affected, or multi-region infrastructure collapse - **high** — thousands evacuated, regional state-of-emergency, multi-day outages in essential services, > 10 000 people affected - **medium** — hundreds to low-thousands affected, single-day service disruption, localized damage - **low** — transient, small-scale, not a "major impact" by definition above → usually should not appear at all. Only use `low` when the cascade is structurally important (e.g. a parent for a higher-severity child) but otherwise minor. ## Time Offset Buckets (hours after flood onset) - **0–6 h**: infrastructure damage, first road closures, initial evacuations, immediate casualties - **6–48 h**: power / comms outages, hospital stress, water supply failure - **2–7 days**: disease onset, prolonged evacuation, business closure, agricultural losses - **1–2 weeks**: secondary health impacts, economic assessment, environmental damage detection - **> 2 weeks**: OUT OF SCOPE — do not create nodes here ## DAG Edge Semantics (v0.2 issue #9 / B', tuned in issue #10) `parent_ids` encodes **causal structure** — what in this chain caused this effect to happen the way you described it. The DAG must capture cause→effect dependency, not just be a flat list of impacts. ### Default behavior: link by default Walk through every cascade event you've identified and ask: > "What in this chain caused this effect to happen the way I described it?" - If the answer is "the flood itself, directly" → `parent_ids: []` (root). - If the answer names another node already in your list → `parent_ids: [""]`. **This is the common case for non-first-order events.** - If two distinct nodes are *jointly necessary* (per the ablation test below) → `parent_ids: ["E2", "E5"]`. **Anti-pattern — flat DAG.** A chain where almost every node has `parent_ids: []` is almost always wrong. Schools closing, emergency declarations, supply shortages, business closures, evacuations to shelters, hospital strain, international aid requests — these are downstream effects, not direct flood-triggered ones. They should chain to the relevant prior node (transport blocked, infrastructure damaged, casualties reported, etc.). If your output has more than ~25% of nodes with empty `parent_ids`, audit again — most of those nodes probably have a real upstream cause inside your chain that you missed. ### Cardinality - **0 parents** — root: direct flood-triggered effect (physical inundation, immediate building damage, immediate drowning casualties, primary substation flooding, road submergence). - **1 parent** — single sufficient cause; *the common case for downstream effects*. School closures (cause = damage), hospital strain (cause = power loss), supply shortages (cause = transport blocked), emergency declarations (cause = casualties or service collapse). - **≥ 2 parents** — AND-conjunction; rare. Use ONLY when each listed parent passes the ablation test below. ### Multi-parent rules (apply ONLY when listing 2+ parents) These rules govern the *second and later* parents. The first parent — the most-direct cause — is the default chain link and does not need to pass an ablation test by itself; it just needs to actually be the cause. **Rule 1 — Ablation test (multi-parent only).** Before listing a SECOND or later parent P, ask: > If I remove P, would this child still occur with the same description, severity, and timing? - **YES** → P is contextual or amplifying. DO NOT list it; use a single parent. - **NO** → P is jointly necessary. List it. **Rule 2 — No-grandparent.** Do not list P if P is already an ancestor of another listed parent. List the most-direct cause only; transitive ancestors are recoverable by walking the graph. ### Worked examples Single-parent (common): - Flood inundates an area E1 (root). Schools close because the buildings are unsafe → `E2.parent_ids = ["E1"]`. - Roads blocked E3 → public transport suspended E4 → `E4.parent_ids = ["E3"]`. - 9 deaths from flash floods E1 (root) → national emergency declared E5 → `E5.parent_ids = ["E1"]`. - Power outage to 42K homes E2 → hospital forced onto generators E6 → `E6.parent_ids = ["E2"]`. Single-parent with no-grandparent rule: - Flood E_root → substation damage E5 → power outage E6. - WRONG: `E6.parent_ids = ["E5", "E_root"]` (E_root is grandparent via E5 → violates Rule 2) - RIGHT: `E6.parent_ids = ["E5"]` Multi-parent (rare, ablation-justified): - Transport disruption E9 + flood inundation E7 → mass displacement E10. Without E9 people would self-evacuate (so smaller scale, not "mass"); without E7 there is nothing to evacuate from. Both pass ablation; neither is ancestor of the other → `E10.parent_ids = ["E9", "E7"]`. ### Anti-patterns (do NOT repeat) - **Flat DAG** — emitting many events all with `parent_ids: []` because the LLM was unsure whether to chain. Default to chaining downstream effects to their causes; only `[]` for events caused directly by the flood physically. - Listing the macro flood event AND a specific damage as parents of a downstream impact (the macro is a grandparent → drop it). - Listing every prior infrastructure failure as parent of a long-tail social/economic impact (most are grandparents or contextual; pick the one direct cause). - Using `parent_ids` to encode "these nodes are related" rather than "these nodes are causal parents". ### Cross-domain preference Prefer cross-domain edges (power → hospital, transport → supply) over intra-domain edges — they carry more predictive signal. The ablation + no-grandparent rules still apply to multi-parent declarations; they do not gate single-parent linking. ## Deduplication Rules (apply BEFORE emitting) Before finalizing the JSON, merge cascade events that describe the same phenomenon in different words: - **Same domain + same affected population / mechanism → one node.** E.g. "Mass displacement of residents" and "Displacement due to unsafe living conditions" under `social/evacuation` → merge. - When merging, keep the most specific description, combine quantitative facts ("371 evacuated" + "189 municipalities" → "371 evacuated across 189 municipalities"), and pick the higher severity. - For the merged parent set: take the union of all clusters' parents, then re-apply Rule 2 (drop any parent that is now an ancestor of another listed parent within the merged graph). Do NOT keep raw unions — the union of two correctly-pruned sets can introduce new grandparent violations after structural merging. - If two nodes differ only by time offset, keep the earlier time and mention duration in the description. ## Extraction Guidelines - Explain the **mechanism** for each cascade link (HOW the parent(s) caused this effect), not just that it did. For multi-parent nodes, explicitly justify why each parent is jointly necessary. - Anchor descriptions in concrete facts from the articles (numbers, place names, named infrastructure). Avoid generic phrasing like "economic losses occurred". - If articles disagree on numbers, use the latest-dated article's figure. - Leave `time_offset_hours` null if no article indicates timing; don't guess. - Cross-domain transitions are the highest-value outputs — prioritize extracting them within the 40-node budget.