# Exogenous timeline
The timeline lives on `TimelineParams` and is built once per simulation by
`build_timeline`. Length is `T+1` to include both `t=0` and the landfall hour.
## Forecast intensity
Piecewise-constant baseline plus i.i.d. Gaussian noise:
```
F̄_t = 1 for 0 ≤ t < 48
2 for 48 ≤ t < 72
3 for 72 ≤ t < 96
4 for 96 ≤ t ≤ T
F_t = F̄_t + ε_t, ε_t ~ N(0, 0.15²)
```
The breakpoints `(0, 48, 72, 96)` and levels `(1, 2, 3, 4)` are tuples on
`TimelineParams`. They must be the same length, and the first breakpoint must
be 0; both invariants are checked at construction.
## Warning orders
Two indicators step from 0 to 1 once and stay on:
```
vol_t = 1{t ≥ voluntary_hour}
mand_t = 1{t ≥ mandatory_hour}
```
Defaults: voluntary at t=60, mandatory at t=84. These are the primary
scenario-tunable knobs; the `early-warning` scenario pulls them to 48 and 72.
## Time since last order
`time_since_order[t]` is the number of hours since the most recent escalation
in `(vol, mand)`. Before either order has fired we use a sentinel `T+1` so
downstream features treat early time steps as "no order has happened yet".
The current build does not consume this field directly, but it is exported in
`timeline.parquet` for use by later builds and figures.
## Local risk
`local_risk_at(forecast_t, distance, zone_multiplier)` is computed on-the-fly
each step (rather than materializing an N×(T+1) array), saving memory at no
runtime cost:
```
ρ_{i,t} = F_t · exp(−d_i / 10)
```
Optionally multiplied per-household by a zone multiplier (used by the
targeted-messaging scenario).