docs/dgp/03-state-space.md

# State space

Each household occupies one of five latent behavioral states. Codes are stable
(used as compact integer keys throughout the codebase) and live on `State` in
`src/iohmm_evac/types.py`.

| Code | Name | Behavioral interpretation |
|------|------|----------------------------|
| 0 | UA  | Unaware: not yet attending to the storm. |
| 1 | AW  | Aware: receiving information, not yet preparing. |
| 2 | PR  | Preparing: gathering supplies / arranging evacuation. |
| 3 | ER  | En Route: actively evacuating along the road network. |
| 4 | SH  | Sheltered: terminal — either at a destination away from home, or sheltered in place. |

## Allowed transitions

The DGP only fires the transitions listed below. Every other (origin →
destination) pair has logit −∞ and is masked in the sampler.

| From | To | Notes |
|------|----|-------|
| UA  | UA | self-loop |
| UA  | AW |  |
| AW  | UA | rare backslide |
| AW  | AW | self-loop |
| AW  | PR |  |
| PR  | PR | self-loop |
| PR  | ER |  |
| PR  | SH | shelter-in-place |
| ER  | ER | self-loop |
| ER  | SH |  |
| SH  | SH | absorbing |

`SH` is absorbing: once a household enters, it stays there for the rest of the
run. The simulator skips the transition step for SH households as a small
performance optimization.

## Auxiliary attributes

Two per-household attributes live alongside the latent state. They are not
additional states — the IO-HMM fit will treat them as deterministic functions
of the latent trajectory (or, in the case of `tir`, conditional on the
state).

* **`evac_path` ∈ {NONE, AWAY, HOME}** — set when SH is first entered.
  - `PR → ER` ⇒ AWAY (the household will subsequently shelter at `dest_i`).
  - `PR → SH` ⇒ HOME (sheltered in place).
  - `ER → SH` ⇒ unchanged (already AWAY from the earlier `PR → ER`).
  Households that never reach SH carry NONE.
* **`tir`** — time-in-state in hours, while in ER. Increments by 1 per hour
  spent in ER and resets to 0 on leaving ER. Drives the `ER → SH` logit.