---
id: e5-fusion-logic-map
title: Fusion Logic Map
module: GROW-S5
module_slug: grow-s5-sensor-fusion-data-ops
cluster: Execution
type: map
version: v0.1.0
status: Gate-reviewed
tier: membership
contract_role: ""
canonical_url: "https://grow.goodcombinator.ai/library/registry/e5-fusion-logic-map"
download_url: "https://grow.goodcombinator.ai/library/registry/e5-fusion-logic-map.md"
license: CC-BY-4.0 (proposed — owner confirmation required)
source: GROW by Good Combinator
retrieved_at: 2026-05-29
---

# Fusion Logic Map

The Fusion Logic Map defines how normalized, individually-trusted telemetry signals are combined into a single operational view for each measurement type of interest. Fusion is the step where conflicting sources are reconciled, freshness-weighted composites are produced, and the composite `confidence_band` is determined — driving every downstream alert, recommendation, and agent action. This map is not a machine-learning model; it is an explicit, auditable set of weighting rules and conflict-resolution policies that a practitioner can inspect, override, and version. `e5-alert-design-spec` and `e5-decision-support-layer` read the fusion output, not the raw signals.

---

## 1. Fusion Principles

1. **Explicit over implicit.** Every weighting factor and conflict-resolution rule is declared in this map, not inferred at runtime.
2. **Composite band = minimum contributing band after weights.** A fusion result is only as trustworthy as its weakest significant contributor. If a `low`-band source carries more than a declared maximum share of the composite value, the composite band is capped at `low`.
3. **Freshness degrades trust.** A measurement that has aged past its declared staleness window is treated as if its `confidence_band` is one notch lower for the purpose of weighting.
4. **Conflict forwarding, not silent merge.** When `e5-normalization-layer` forwards a `conflict-group`, fusion must choose a winner by rule — not by averaging silently — and must record the rule applied and the losing values.
5. **The fusion layer produces one record per measurement type per fusion window.** Downstream systems do not re-fuse; they consume the canonical fusion output.

---

## 2. Fusion Window

The fusion window controls temporal alignment across sources with different emission frequencies.

```yaml
default_fusion_window_seconds: 60
per_type_overrides:
  water-level: 30          # high-frequency pond sensors warrant tighter window
  rainfall-rate: 60
  tide-height: 30
  soil-moisture-volumetric: 120   # slower-moving measurement
  flow-rate: 30
  rainfall-accumulation: 300      # rolling 5-min window
```

At the end of each fusion window, the fusion engine collects all normalized records with `timestamp_utc` within the window for each `measurement_type` and applies the weighting rules below. Records older than the window are archived, not re-fused.

---

## 3. Weighting Rules

Each source contributing to a fused measurement is assigned a composite weight `W` as the product of three factors:

```
W = W_band × W_freshness × W_authoritative
```

### 3.1 Band weight (`W_band`)

| confidence_band | W_band |
|---|---|
| high | 1.00 |
| medium | 0.60 |
| low | 0.20 |
| unknown | 0.00 (excluded from fusion) |

A source with `confidence_band: unknown` is never included in the composite value. Its record is forwarded to pipeline monitoring only.

### 3.2 Freshness weight (`W_freshness`)

Let `age_ratio = record_age_seconds / staleness_ceiling_seconds` where `staleness_ceiling` is `2 × emission_frequency` converted to seconds.

| age_ratio | W_freshness |
|---|---|
| ≤ 0.50 | 1.00 |
| 0.51 – 0.75 | 0.80 |
| 0.76 – 1.00 | 0.50 |
| > 1.00 | 0.10 (stale; flag for pipeline monitoring) |

### 3.3 Authoritative weight (`W_authoritative`)

| authoritative | W_authoritative |
|---|---|
| true | 1.00 |
| false | 0.50 |

### 3.4 Composite value formula

After computing `W_i` for each contributing source `i`:

```
W_total = Σ W_i
fused_value = Σ (W_i × normalized_value_i) / W_total
```

The fused value is a weighted average. If only one source has a non-zero weight, the fused value equals that source's value exactly.

---

## 4. Composite Confidence Band

After computing the fused value, the composite `confidence_band` is determined by the following rules applied in order:

1. **Any `unknown` contributor present?** — Composite band = `low` (the unknown source flagged in provenance; the composite is still produced but capped).
2. **Weighted share of `low`-band sources > 30%?** — Composite band = `low`.
3. **Weighted share of `medium`-or-lower sources > 60%?** — Composite band = `medium`.
4. **All contributing sources are `high`?** — Composite band = `high`.
5. **Otherwise:** Composite band = `medium`.

The threshold of 30% for `low`-band share is the primary guard against a degraded secondary sensor inflating a `medium` or `high` composite into a consequential alert. Implementations may tighten but not relax these thresholds without a MINOR version bump to this map.

---

## 5. Conflict Resolution Rules

When `e5-normalization-layer` forwards a `conflict-group`, fusion applies rules in this priority order:

| Priority | Rule | Applied when |
|---|---|---|
| 1 | **Higher authoritative wins** | One source is `authoritative: true`, the other is not |
| 2 | **Higher confidence band wins** | Both same authoritative status; one has higher band |
| 3 | **More recent wins** | Same band; one record is fresher |
| 4 | **Conservative value wins** | Tie on all above; use the value that would trigger a higher alert level (safety-conservative) |

The conflict resolution outcome is recorded in the fused record:

```yaml
conflict_resolution:
  rule_applied: <1|2|3|4>
  winner_source_id: <source_id>
  loser_source_ids: [<source_id>, ...]
  loser_values: [<value>, ...]
  delta: <absolute difference>
```

This record is written to the provenance store via `e5-decision-support-layer` before any alert is raised.

---

## 6. Fusion Output Schema

```yaml
fused_record:
  measurement_type: <enum from e5-normalization-layer §2.1>
  fused_value: <number>
  unit: <canonical unit>
  confidence_band: <high|medium|low|unknown>
  composite_band_rule: <1|2|3|4|5>    # which composite-band rule applied
  fusion_window_end_utc: <ISO 8601 Z>
  contributing_sources:
    - source_id: <string>
      normalized_value: <number>
      weight: <W_i computed above>
      age_seconds: <integer>
      confidence_band: <band at time of fusion>
  conflict_resolution: <null or object from §5>
  stale_sources: [<source_id>, ...]    # sources with age_ratio > 1.0
```

---

## 7. Worked Example — Water Level Fusion (illustrative)

**Scenario:** South Walton stormwater network, fusion window ending `2026-05-29T19:33:00Z`, measurement type `water-level`.

Inputs from `e5-normalization-layer`:

| source_id | normalized_value (m) | confidence_band | authoritative | age_seconds |
|---|---|---|---|---|
| `sw-water-level-j1` | 0.753 | medium | true | 22 |
| `sw-tide-noaa-destin` | 0.481 | high | true | 18 |
| `sw-flow-culvert-c4` | 0.802 | low | true | 55 |

Note: `sw-tide-noaa-destin` measures coastal tide height at Destin, not pond level, so in a real deployment its `measurement_type` would differ. For this illustrative example, assume all three are measuring the same drainage reference plane.

**Weight calculation** (staleness ceiling for water-level = 60 s):

| source_id | W_band | age_ratio | W_freshness | W_auth | W_i |
|---|---|---|---|---|---|
| `sw-water-level-j1` | 0.60 | 22/60 = 0.37 | 1.00 | 1.00 | 0.600 |
| `sw-tide-noaa-destin` | 1.00 | 18/60 = 0.30 | 1.00 | 1.00 | 1.000 |
| `sw-flow-culvert-c4` | 0.20 | 55/60 = 0.92 | 0.50 | 1.00 | 0.100 |

W_total = 0.600 + 1.000 + 0.100 = 1.700

**Fused value:**
```
fused_value = (0.600×0.753 + 1.000×0.481 + 0.100×0.802) / 1.700
            = (0.452 + 0.481 + 0.080) / 1.700
            = 1.013 / 1.700
            = 0.596 m
```

**Composite band check:**
- No `unknown` contributors.
- `low`-band weighted share = 0.100 / 1.700 = 5.9% — below 30% threshold.
- `medium`-or-lower share = (0.600 + 0.100) / 1.700 = 41.2% — below 60%.
- Not all `high` (sw-water-level-j1 is medium).
- **Composite band = medium** (rule 5).

**Fused record output:**
```yaml
fused_record:
  measurement_type: water-level
  fused_value: 0.596
  unit: meters above NAVD88
  confidence_band: medium
  composite_band_rule: 5
  fusion_window_end_utc: "2026-05-29T19:33:00Z"
  contributing_sources:
    - source_id: sw-water-level-j1
      normalized_value: 0.753
      weight: 0.600
      age_seconds: 22
      confidence_band: medium
    - source_id: sw-tide-noaa-destin
      normalized_value: 0.481
      weight: 1.000
      age_seconds: 18
      confidence_band: high
    - source_id: sw-flow-culvert-c4
      normalized_value: 0.802
      weight: 0.100
      age_seconds: 55
      confidence_band: low
  conflict_resolution: null
  stale_sources: []
```

If `sw-water-level-j1` had instead arrived 70 seconds after the window start (age_ratio = 70/60 = 1.17), it would have been flagged as stale, its `W_freshness` would drop to 0.10, and its weight would become 0.060. The fused value would shift toward the NOAA tide reading, and `sw-water-level-j1` would appear in `stale_sources`.

---

## 8. Operational View

The fusion layer produces one `fused_record` per `measurement_type` per window. An operational view is the set of current fused records across all active measurement types. The operational view is the input surface for `e5-alert-design-spec` and `e5-decision-support-layer`. Stale or `unknown`-band entries in the operational view are surfaced to the pipeline monitoring channel defined in `e5-pipeline-resilience-playbook` — they are not hidden from operators.

---

## 9. Versioning and Change Control

Adding a `measurement_type` or a new weight factor is MINOR. Changing a weighting constant (W_band, W_freshness, W_authoritative) or a composite-band threshold is MINOR but requires re-validation against historical data. Removing a measurement type or changing the fused_record schema shape is MAJOR and triggers coordinated review with `e5-alert-design-spec` and `e5-decision-support-layer`.
