# Programs

> What a reinsurance program is: the protections bought on one exposure, often an excess-of-loss tower, sometimes with a quota share, and how inuring links them.

Source: https://reinsurance.dev/financial-modelling/programs/

A cedent rarely transfers its risk with a single contract. It assembles a
**[program](https://reinsurance.dev/glossary/#program)**: the structured set of reinsurance protections bought
to cover one set of exposure (a property-catastrophe book, a casualty account, a single
large risk). A program is the container for everything a placement needs: the exposure being
protected, the contracts structured on top of it, and the terms that govern them. It is the
unit a cedent buys, a broker places, and a reinsurer prices and renews.

Programs span a wide spectrum of uses. A regional insurer buys a property-catastrophe
program to protect its homeowners book; a reinsurer buys a
**[retrocession](https://reinsurance.dev/glossary/#retrocession)** program to protect the portfolio it has assumed; two
carriers enter a risk-sharing agreement; a cedent sponsors a **[cat bond](https://reinsurance.dev/glossary/#cat-bond)**
to move peak risk into the capital markets. The structures differ, but the idea is constant:
a coordinated set of protections on one defined exposure.

Most programs share a common shape, a tower of excess-of-loss layers, sometimes placed beside a [quota share](https://reinsurance.dev/financial-modelling/contracts/quota-share/) on the same exposure; some add relationships between their contracts.

## The common shape: a tower of layers

The common shape is a stack of [excess-of-loss](https://reinsurance.dev/financial-modelling/contracts/catxol/) [layers](https://reinsurance.dev/glossary/#layer), each covering a band of loss above the one below it. The industry calls the stack a **[tower](https://reinsurance.dev/glossary/#tower)**.[^tower] A cedent that retains the first \$10M of any catastrophe might buy a \$10M xs \$10M
layer, a \$30M xs \$20M layer above it, and a \$50M xs \$50M layer above that: three layers
covering loss from \$10M up to \$100M, each placed (often with a [different panel of reinsurers](https://reinsurance.dev/foundations/products-and-contracts/#participation))
as its own contract.

*Figure (interactive on the web page): One occurrence loss read from the bottom: the cedent retains the first \$10M, layer 1 covers the next \$10M, layer 2 the \$30M above that, and layer 3 the \$50M band up to the \$100M exhaustion point.*

Read the tower from the bottom: an occurrence loss fills the retention first, then layer 1, then layer 2, and only a loss above \$50M reaches layer 3. Every layer reads the same occurrence and responds to its own band of it.

In a vanilla tower the layers are **independent**. Each one
[filters the subject loss, applies its layer, and computes its gross loss](https://reinsurance.dev/financial-modelling/composition/)
without reference to any other layer: every layer reads the same exposure, each at a different
band. Evaluate them in any order, or all at once; the program's total ceded loss is the
sum. This is the [single-contract evaluation](https://reinsurance.dev/financial-modelling/dissection/)
from earlier in the chapter, repeated once per layer and added up.

:::tip[Key Insight]
A program is not a new kind of object. It is a bundle of contracts, each still a
[composition of financial terms](https://reinsurance.dev/financial-modelling/composition/), collected because they
protect one exposure and are bought together. The bundling is what makes it a program; the
contracts need not depend on one another. A plain tower of independent layers is already a
complete program.
:::

The independence ends where
[one layer's result changes another layer's subject](https://reinsurance.dev/financial-modelling/programs/#when-layers-reference-one-another), and an
evaluation order follows.

## When layers reference one another

Some programs add **relationships between contracts**, where one contract's result changes what
another contract sees:

- **[Inuring](https://reinsurance.dev/glossary/#inuring)**: one contract's recoveries are subtracted from another's
  subject, so the same loss is not recovered twice, [as a catastrophe cover's wording
  usually provides](https://reinsurance.dev/foundations/products-and-contracts/#caldera-res-contract-portfolio). A quota
  share that inures to the benefit of the catastrophe layers, so they cover only the loss the
  cedent retains, is the common case.
- **[Forwarding](https://reinsurance.dev/glossary/#forwarding)**: one layer's gross loss becomes another's subject (the
  retrocession case).
- **[Top & drop](https://reinsurance.dev/glossary/#top--drop)**: a single block of limit responds at a high attachment or drops down to a
  lower one, depending on how the year unfolds.[^topdrop]

Of the three, inuring and forwarding change a contract's subject stream; top & drop changes a layer's attachment, not its input.

```mermaid
---
config:
  flowchart:
    minNodeWidth: 0
---
graph TB
    subgraph I[Inuring: B's subject is the subject loss less A's recoveries]
        direction TB
        IS[Subject loss]:::Losses --> IA[Layer A]:::Contract
        IS --> IB[Layer B]:::Contract
        IA -- "recoveries" --> IM(("× −1")):::Process
        IM --> IB
    end
    subgraph S[Forwarding: A's gross loss is B's subject]
        direction TB
        SS[Subject loss]:::Losses --> SA[Layer A]:::Contract
        SA -- "gross loss" --> SB["Layer B (a retro layer)"]:::Contract
    end
    I ~~~ S

    classDef Losses fill:#F5CEBC,stroke:#B16C4B,stroke-width:1.5px,color:#2B2620
    classDef Contract fill:#BFDBF8,stroke:#4F84BA,stroke-width:1.5px,color:#2B2620
    classDef Process fill:#F7CBCB,stroke:#B46669,stroke-width:1.5px,color:#2B2620
```

These are optional features, not part of the definition: a tower with none of them is still
a program. But when present, they make the contracts interdependent: a contract can no longer be
evaluated in isolation, because its subject depends on another contract's output.
[SunCoast's program](https://reinsurance.dev/financial-modelling/programs/#suncoasts-program) uses **inuring**, so this page treats inuring in depth;
forwarding and top & drop are out of scope for this page.

## SunCoast's program

The [risk-profiling story](https://reinsurance.dev/applications/risk-profiling/) characterised SunCoast's
[subject loss](https://reinsurance.dev/glossary/#subject-loss): \$275.6M of expected annual loss on the [20-trial demo tier](https://reinsurance.dev/toolkit/trials/#demo-scale),
hurricane-dominated, with exposure spread across the Gulf. SunCoast protects that book with
three layers:

*[Table: Portfolio table. See the web page: https://reinsurance.dev/financial-modelling/programs/]*

Two of these are ordinary, independent layers: C1 caps individual Florida hurricanes, C2 caps
a bad year of California quakes. The inuring relationship is the one addition: C3 is a whole-book backstop that
responds only in a genuinely catastrophic year, and only for loss C1 and C2 have not already
absorbed. That "net of C1 and C2" clause is an **inuring** relationship. SunCoast's program is
not exotic: it is a standard catastrophe program with a single inuring edge on top of
an otherwise vanilla structure. C1 is a [catastrophe excess of loss (CatXoL)](https://reinsurance.dev/glossary/#catxol-catastrophe-excess-of-loss) layer; C2 and C3 are [aggregate excess of loss (AggXoL)](https://reinsurance.dev/glossary/#aggxol-aggregate-excess-of-loss) layers.

```mermaid
graph LR
    SUBJ[SunCoast subject loss]:::Losses --> C1[C1 · FL hurricane CatXoL]:::Contract
    SUBJ --> C2[C2 · CA/AZ earthquake AggXoL]:::Contract
    SUBJ --> NET{{net of C1, C2}}:::Process
    C1 -. inures .-> NET
    C2 -. inures .-> NET
    NET --> C3[C3 · All-US AggXoL]:::Contract

    classDef Losses fill:#F5CEBC,stroke:#B16C4B,stroke-width:1.5px,color:#2B2620
    classDef Contract fill:#BFDBF8,stroke:#4F84BA,stroke-width:1.5px,color:#2B2620
    classDef Process fill:#F7CBCB,stroke:#B46669,stroke-width:1.5px,color:#2B2620
```

C1 and C2 read the subject loss directly and can be evaluated in any order. C3 depends on both:
it cannot be computed until they are, because its subject is defined in terms of their
recoveries. [Inuring](https://reinsurance.dev/financial-modelling/programs/#inuring) defines C3's subject, and
[dependency order](https://reinsurance.dev/financial-modelling/programs/#evaluating-a-program-with-edges) determines when an engine can compute it.

## Inuring

**[Inuring](https://reinsurance.dev/glossary/#inuring)** is the relationship where one layer's recoveries reduce the
subject loss of another. "C1 and C2 inure to the benefit of C3" means C3 responds only to the
loss left after C1 and C2 have paid. Its purpose is to prevent **[double recovery](https://reinsurance.dev/glossary/#double-recovery)**: the same
dollar of loss being collected once by a lower layer and again by the backstop.

For SunCoast the netting is arithmetic on per-trial losses. Because C3 is an
[aggregate](https://reinsurance.dev/financial-modelling/terms/aggregate-excess/) layer, the netting happens at the
trial-aggregate level. Write $L_j$ for SunCoast's total loss in trial $j$ and $C_i(L_j)$ for
contract $i$'s gross loss on it; C1 and C2 apply to SunCoast's loss before any netting. In the two formulas below $L_j^{\text{subject}}$ is C3's subject alone, the total minus what C1 and C2 recovered,

$$
L_j^{\text{subject}} = L_j - C_1(L_j) - C_2(L_j)
$$

and C3's aggregate layer, with an attachment $A_3$ of \$300M and a limit $\ell_3$ of \$50M, covers
that net figure:

$$
C_3\big(L_j^{\text{subject}}\big) = \min\!\big(\max(L_j^{\text{subject}} - A_3,\; 0),\; \ell_3\big)
$$

No new financial term is involved. C3 is still an aggregate excess layer. Inuring changes only
the loss it **covers**: the net aggregate rather than the gross one.

:::caution[Watch Out]
The trial-aggregate netting above is correct because C3 is an aggregate layer. If the inuring
layer had per-occurrence terms, the netting would have to happen at the occurrence level: each
occurrence's loss reduced by the recoveries the lower layers paid on that occurrence, before
the occurrence layer applies. Netting per-trial totals would be wrong there, because an
occurrence layer depends on which occurrence the remaining loss belongs to, not on the annual
sum alone. Inuring is applied at the resolution the downstream layer operates on.
:::

:::note[Remember]
Inuring is a property of the program, not of any one layer. C3's own definition, an AggXoL at
\$50M xs \$300M, says nothing about C1 or C2. The netting comes from how the layers are combined. Move C3 to a different program and it covers a different subject; the contract itself
is unchanged.
:::

### Where inuring changes the answer

Netting only matters in the trials where it moves a payout. Across SunCoast's 20-trial demo tier, C3's
\$300M attachment is cleared by the gross aggregate in seven trials, but in two of them,
subtracting the C1 and C2 recoveries pulls the subject back below attachment, and C3 pays
nothing:

| Trial | Gross aggregate | C1 + C2 recoveries | Net aggregate | C3 on gross basis | C3 net of C1, C2 |
| ---: | ---: | ---: | ---: | ---: | ---: |
| 1 | \$616.2M | \$8.2M | \$608.0M | \$50.0M | \$50.0M |
| 2 | \$489.1M | \$32.3M | \$456.8M | \$50.0M | \$50.0M |
| 3 | \$468.2M | \$42.3M | \$425.9M | \$50.0M | \$50.0M |
| **4** | **\$309.2M** | **\$13.9M** | **\$295.3M** | **\$9.2M** | **\$0.0M** |
| 8 | \$303.2M | \$0.0M | \$303.2M | \$3.2M | \$3.2M |
| **11** | **\$305.3M** | **\$37.9M** | **\$267.4M** | **\$5.3M** | **\$0.0M** |
| 13 | \$378.2M | \$22.3M | \$355.9M | \$50.0M | \$50.0M |

Trial 4 is the clearest. SunCoast's gross aggregate loss reaches \$309.2M, slightly above C3's \$300M attachment, so
a backstop applied to the gross aggregate would pay \$9.2M. But C1 and C2 have already recovered
\$13.9M of that trial's loss; net of those recoveries the aggregate is \$295.3M, below attachment,
and C3 correctly pays \$0. The \$9.2M a gross-basis backstop would have paid was loss the lower
layers had already covered. Trial 11 behaves the same way. Without the inuring edge, SunCoast
would recover those amounts twice.

Python (`python/caldera_re/program_ceded.py`, runnable on the web page):

```python
"""SunCoast's reinsurance program: three layers, evaluated in dependency order.

The program is one cedent's coordinated placement, not a pile of independent
contracts:

    C1  Florida hurricane CatXoL ........ 30M xs 10M, 1 reinstatement
    C2  CA/AZ earthquake AggXoL ......... 10M xs 15M aggregate
    C3  All-US AggXoL ................... 50M xs 300M, net of C1 and C2

C3 is where the program stops being separable. Its subject is SunCoast's
*total* annual loss net of whatever C1 and C2 already paid -- so the same
dollar of loss is never recovered twice. That makes C3 depend on C1 and C2:
the three layers must be evaluated in order, not in isolation.

Each layer reuses the published terms from the Financial Modelling catalog
(filter, occurrence excess, aggregate excess) via the catxol/aggxol helpers.
The only new thing here is the inuring wiring, which is arithmetic on
per-trial gross losses -- no new financial term.
"""

import numpy as np
import pandas as pd

from caldera_re.aggxol import aggxol
from caldera_re.catxol import catxol
from caldera_re.data import cedents
from caldera_re.contract_period import contract_period
from caldera_re.report import heading, table

N = 20  # trial count of the Caldera Re demo tier

def _per_trial(result: pd.DataFrame, column: str = 'gross_loss') -> np.ndarray:
    """Collapse a contract's YELT output into a length-N per-trial array."""
    arr = np.zeros(N)
    for tid, value in result.groupby('trial_id')[column].sum().items():
        arr[int(tid) - 1] = value
    return arr

def suncoast_program(yelt: pd.DataFrame | None = None) -> dict:
    """Evaluate SunCoast's three-layer program on the locked YELT.

    Returns a dict of length-N per-trial gross (ceded-to-Caldera) arrays:
    {'C1', 'C2', 'C3', 'program', 'subject_agg', 'net_agg'}.
    """
    sc = cedents.suncoast if yelt is None else yelt

    # C1: Florida hurricane CatXoL, 30M xs 10M, 1 reinstatement (agg cap 60M).
    c1 = _per_trial(catxol(sc, attachment=10.0, limit=30.0, reinstatements=1,
                           peril='HU', geography_id='FL'))

    # C2: CA/AZ earthquake AggXoL, 10M xs 15M on the annual EQ aggregate.
    c2 = _per_trial(aggxol(sc, attachment=15.0, limit=10.0, peril='EQ'))

    # C1 and C2 inure to the benefit of C3: its subject is SunCoast's total
    # annual loss net of the C1 and C2 recoveries, so losses those layers paid
    # cannot be recovered again. Per trial:
    #   net_agg = total_subject - C1_gross - C2_gross
    #   C3_gross = clip(net_agg - 300, 0, 50)
    subject = contract_period(sc, '2024-01-01', '2024-12-31')
    subject_agg = (subject.groupby('trial_id')['loss'].sum()
                   .reindex(range(1, N + 1), fill_value=0.0).to_numpy())
    net_agg = subject_agg - c1 - c2
    c3 = np.clip(net_agg - 300.0, 0.0, 50.0)

    return {
        'C1': c1, 'C2': c2, 'C3': c3,
        'program': c1 + c2 + c3,
        'subject_agg': subject_agg, 'net_agg': net_agg,
    }

if __name__ == '__main__':
    p = suncoast_program()

    heading("SunCoast program: per-trial ceded loss by layer (AEP, $M)")
    table(['Trial', 'Subject', 'C1', 'C2', 'C3', 'Program'],
          zip(range(1, N + 1), p['subject_agg'], p['C1'], p['C2'], p['C3'],
              p['program']),
          fmt=['{}'] + ['{:.1f}M'] * 4 + ['{:.2f}M'])

    print(f"\n{'Layer EL:':<12} "
          f"C1 {p['C1'].mean():.2f}M | C2 {p['C2'].mean():.2f}M | "
          f"C3 {p['C3'].mean():.2f}M | Program {p['program'].mean():.2f}M")

    # --- The inuring check: where does netting actually bind? -------------
    # In any trial whose subject aggregate clears 300M, ask what C3 would
    # have paid on the GROSS aggregate versus the net-of-C1/C2 aggregate.
    print()
    heading("Inuring: gross-basis vs net-basis C3 (prevents double pay)")
    rows = []
    for t in range(N):
        subj = p['subject_agg'][t]
        if subj <= 300.0:
            continue  # C3 cannot trigger on either basis
        c3_gross_basis = np.clip(subj - 300.0, 0.0, 50.0)
        recoveries = p['C1'][t] + p['C2'][t]
        rows.append((t + 1, subj, recoveries, p['net_agg'][t],
                     c3_gross_basis, p['C3'][t]))
    table(['Trial', 'Subject', 'C1+C2', 'Net', 'C3 gross-basis', 'C3 net'],
          rows, fmt=['{}'] + ['{:.1f}M'] * 5)

    print("\nTrials 4 and 11 are where the netting binds. In trial 4 the gross")
    print("aggregate (309.2M) clears the 300M attachment and would pay 9.2M,")
    print("but C1 and C2 have already absorbed 13.9M, dropping the net")
    print("aggregate to 295.3M -- below attachment, so C3 net of inuring pays 0.")
    print("Trial 11 is the same story (305.3M gross, 267.4M net). Without")
    print("inuring, SunCoast would recover those losses twice.")
```

:::note[In Practice]
Double recovery is a correctness problem of three kinds, and only one of them is the engine's
fault:

1. **Engine correctness.** The implementation of the financial terms must not double-count: an
   aggregate layer that re-adds an occurrence, an inuring edge applied twice. This is a hard
   correctness bug, but a bounded one: careful engineering and thorough tests catch it, and once
   the terms are right it rarely recurs except when new functionality is deployed.
2. **Mis-structured programs.** Harder to catch automatically: the
   terms are correct but combined in a way that double-recovers. Two CatXoLs written \$10M xs
   \$15M and \$10M xs \$20M both cover the \$15M–\$20M band: a data-entry error, a misinterpreted submission, or an inuring clause that was meant to apply and was overlooked. The engine cannot
   know this is wrong: the numbers are internally consistent, but not what the placement
   intended.
3. **Deliberate overlap.** Occasionally double recovery is contractually correct: a premium
   rebate or bonus that the available terms cannot express directly, modelled as a second layer
   that deliberately pays on top of the first. The engine has no way to tell that construction
   from the mis-structure above; only the placement's documentation can.

An engine can guarantee it evaluates the terms it is given correctly; it cannot guarantee the
terms it is given are the program someone meant to buy. That gap is where structural review,
reconciliation, and tests against expected payouts are needed.
:::

*[Interactive figure: Program ceded chart. See the web page: https://reinsurance.dev/financial-modelling/programs/]*

Trial by trial, the three layers' recoveries rarely reach their maximum together. How the layers are structured (here
including the inuring edge) is what determines the capital the program demands, which the
[standalone pricing story](https://reinsurance.dev/applications/standalone-pricing/) works out.

## Evaluating a program with edges

A vanilla tower imposes no evaluation order: its layers are independent, so an engine can run them in any order. An inuring (or forwarding) edge changes that. For the SunCoast program,
contract C3 cannot be computed until contracts C1 and C2 are evaluated, because C3's subject is
defined net of their recoveries. A correct evaluator processes a program in **dependency order**,
a topological sort over its edges. In [SunCoast's program](https://reinsurance.dev/financial-modelling/programs/#suncoasts-program), C1 and C2
(no incoming edges) run first, in parallel; C3 waits for both.

The contract definitions determine the stages. Each contract names the contracts it is net of, so the edges come from those clauses, and the stages are a topological sort over them. The snippet derives both for SunCoast's program and yields the evaluation order:

Python (runnable on the web page):

```python
# A program as its contracts define it: each contract names what it is net of.
program = {
    "C1": {"type": "CatXoL", "net_of": []},
    "C2": {"type": "AggXoL", "net_of": []},
    "C3": {"type": "AggXoL", "net_of": ["C1", "C2"]},
}

# Edges are derived from the inuring clauses rather than declared separately:
# an edge upstream -> downstream for every contract the downstream is net of.
edges = [(up, down) for down, c in program.items() for up in c["net_of"]]
print("edges:", edges)

# Topological sort into stages (Kahn's algorithm): a stage holds every
# contract whose upstream contracts have all been evaluated. Contracts in
# one stage are independent and run in parallel, across all trials.
remaining = dict(program)
stages = []
while remaining:
    ready = sorted(
        name for name, c in remaining.items()
        if all(up not in remaining for up in c["net_of"])
    )
    if not ready:
        raise ValueError("cycle: a contract is net of itself, directly or indirectly")
    stages.append(ready)
    for name in ready:
        del remaining[name]

for i, stage in enumerate(stages, start=1):
    print(f"stage {i}: {stage}")
```

For three layers the order can be verified by inspection. For a real placement (more than a dozen separately placed tranches, retrocessions
forwarding off the gross portfolio, layers inuring to one another),[^placement-scale] it is the difference between a
correct evaluation and a subtly wrong one. The
[per-trial independence](https://reinsurance.dev/financial-modelling/dissection/) the toolkit established still holds
within each stage, so the expensive part (running each layer across [10,000 to 1,000,000+ trials](https://reinsurance.dev/toolkit/trials/#demo-scale))
stays embarrassingly parallel. Only the edges between layers impose order.

:::caution[Watch Out]
When a program has edges, the [dependency graph](https://reinsurance.dev/glossary/#dependency-graph) is best derived, not hand-maintained. That C3
depends on C1 and C2 falls out of C3's subject being defined net of them; a separate, hand-kept
"C3 depends on C1, C2" declaration drifts out of sync the first time someone edits a layer. Derive the dependencies from the inuring and forwarding clauses rather than storing them twice.
:::

The sort is linear in the number of contracts and edges, and the
[standalone pricing story](https://reinsurance.dev/applications/standalone-pricing/#at-production-scale) shows how it
orders the per-trial evaluation at production scale.

## What carries forward

A program is a **bundle of contracts on a shared exposure**, the unit a cedent buys to cover a
defined risk. Most programs are towers of independent excess-of-loss layers, sometimes beside a
quota share, each contract a
[composition of financial terms](https://reinsurance.dev/financial-modelling/composition/) evaluated on its own, with
their losses summed. Some add relationships between contracts: **inuring** (recoveries netted out of a
downstream subject), **forwarding** (one layer's gross becoming another's subject), or **top &
drop** (one limit, two attachment points). These make the contracts interdependent and impose an
evaluation order, without changing what any single contract is.

**[Pricing](https://reinsurance.dev/applications/standalone-pricing/)**
asks what the whole program is worth: the ceded distribution its layers produce and the capital
their structure demands. **[Portfolio roll-up](https://reinsurance.dev/financial-modelling/portfolios/)** asks what the program does to a
reinsurer's wider portfolio (the next page in this chapter). Pricing is taken up in the
Applications chapter.

[^tower]: RAA, [*Fundamentals of Reinsurance and Glossary of Reinsurance Terms*](https://www.reinsurance.org/Common/Uploaded%20files/Fundamentals/FundamentalsofReinsuranceandGlossaryofReinsuranceTerms.pdf), on layering: a cedent "may purchase numerous treaties until the desired level of reinsurance protection is achieved", and "at the time a claim comes due, the reinsurers respond in a predetermined sequence, as necessary, to cover the loss". Steve Evans, ["IAG renews \$10bn catastrophe reinsurance tower, expands quota share to 35%"](https://www.artemis.bm/news/iag-renews-10bn-catastrophe-reinsurance-tower-expands-quota-share-to-35/), *Artemis*, January 2026, uses "catastrophe reinsurance tower" without explanation as the trade name for such a stack.

[^topdrop]: Ivelin Zvezdov, ["Top and Drop: A Reusable and Customizable Reinsurance Solution"](https://www.verisk.com/blog/top-and-drop-a-reusable-and-customizable-reinsurance-solution/), Verisk, September 2016. The clause lets the reinsured reuse "the top excess-of-loss layer in the reinsurance tower if the retention of this top layer is not breached by the first loss event", after which that layer "acts as a reinstatement on one or more of the lower layers".

[^placement-scale]: Citizens Property Insurance Corporation, [*2025 Risk Transfer Program*](https://www.citizensfla.com/documents/20702/36903169/20250625+03Aa+2025_Layer_Charts_%28WS%29.pdf), Board of Governors, June 2025. Its \$4.49 billion program is five named layers placed as thirteen separate single-year and multi-year tranches across the traditional and capital markets, with the sliver layer working "in tandem with the mandatory coverage provided by the FHCF" and Layer 1 sitting above both. Citizens is a residual-market insurer whose program is published in this detail.
