# World Model — W1 state layer

The time-indexed, joined **world-state** layer for magalia.wiki, built from the
experts-panel roadmap ([`WORLD-MODEL-PLAN-2026-07-08.md`](../WORLD-MODEL-PLAN-2026-07-08.md)).
Where the estate's spines hold *dated points* (a consular year, a place, an
inscription), W1 composes them into **state you can query at a year**: who held
which office, what a place was called and depended on, what economic regime
governed a production centre — each as a derived interval carrying its evidence.

This is **Phase 0 + the three Tier-A state fact tables (A1–A5)**. The query
surfaces (A7–A9: workbench, state-at-year-*t* map, CmdK card) are Phase 2.

## What's here

| File | What | Rows | Source |
|---|---|---|---|
| `build/wm_contract.py` | **Phase 0** — the reckoning contract + honesty rails every table inherits | — | `fasti/consular.json` meta |
| `data/person_office.json` | **A1** — office-holding intervals on the DPRR office tree | 9,724 | DPRR PG dump |
| `data/place_state.json` | **A2** — ancient toponyms + admin/succession relations over time | 23,834 places | Pleiades gazetteer |
| `data/economy_state.json` | **A3–A5** — center regimes · production intensity · amphora flows | 2,392 | economy-centers · production-index×LIST · CEIPAC |
| `data/counterfactual.json` | **W2 / Phase 3** — evidence-graph suppression substrate + fragility | 62 nodes | events.json · entities-edges · date-crosscheck |
| `data/state-card-index.json` | **A9** — compact governor + economy digest for the ⌘K card | 38 provinces | person_office + economy_state |
| `data/place-geo.json` | **A8** — compact geo layer for the time map | 14,310 places | place_state + economy_state |
| `data/annona.json` | **W3** — the annona premium (Dressel 20 vs transport cost) | 214 sites | economy_state (CEIPAC) + geography |
| `data/place-ecology.json` | **W4** — generalized place-state ecology axes (substrate) | 4,113 places | place_state + harborscapes Q/C/D |

Surfaces: `matrix-hub/world-model.html` — five tabs (office-holders at *t* · place
state at *t* · as-of-*t* state card · **what rests on this** · **time map**), on
`js/magalia-worldmodel.js` + `js/magalia-counterfactual.js`. The site-wide ⌘K
portal (`js/magalia-portal.js`) grows a "place year" grammar via
`js/magalia-worldcard.js`: typing "Cilicia 51 BCE" returns a state card (Cicero,
proconsul) without loading the fact tables.

Rebuild all + gate: `build/build_all.sh` (needs the epipap + litdat mounts).
Regression gate alone (stdlib, no mounts): `build/check_world_model.py`.

## The contract (Phase 0)

`wm_contract.py` is load-bearing and inherited by every builder. It encodes,
from the fasti SSOT, *not a re-typed copy*:

- **Interval semantics** — `closed-shared-lower`, signed proleptic Varronian BC
  (no year 0). The Capitoline reckoning is a reserved, unpopulated slot.
- **Coverage-gap registry** — the anarchy (375–371 BCE) and thinned-DPRR years.
  A "who held X at year *t*" query must not fabricate a magistrate for a gap year.
- **Date-precision classes** — `point` / `narrow` / `decade-scale` / `floruit` /
  `undated`. Only `point`/`narrow` are `bindable_to_year`; a `floruit` is CONTEXT,
  never a point-in-time claim. (This is why a coarsely-dated Pleiades name shows
  as "in use during a window overlapping *t*", never "the name at exactly *t*".)
- **Key normalization** — canonicalize TM / Pleiades / EDCS / PIR ids before any
  hub join, so a format mismatch becomes a *logged* miss, not a silent one.
- **Modality stamp** — `state_row()` refuses to emit a state claim without
  `modality ∈ {asserted, derived, hypothesised}` and non-empty `source_loci`.

## What it answers (verified in the gate)

- **person_office** — "the praetors and tribunes of 63 BCE alongside consuls
  Cicero and Antonius" returns 55 bindable office-holders; the consuls match the
  fasti exactly, and the cast of the Catilinarian year is precise (Caesar as
  *duovir perduellionis*, Catiline typed `repulsa (cos.)` — he lost the election).
- **place_state** — Pleiades 857177 gives the real renaming sequence Κάβειρα →
  Diospolis → Neocaesarea/Sebaste/Hadriane; the Mithridatic name has dropped out
  by 400 CE. 674 administrative-parent relations are queryable over time.
- **economy_state** — Dokimeion marble shifts `direct_fisc_army` → `coloni_concession`;
  Dressel 20 Baetican olive oil flows to exactly its known distribution (Ostia, the
  Rhône at Vienne, the Rhine/Britain frontier at Mainz + London, plus Baetican
  production sites).
- **counterfactual (W2)** — suppress Herodotus and 5 events fall: the Persian Wars
  (its only witness gone) and its four battles (Marathon, Thermopylae, Salamis,
  Plataea — each a cascade child with no independent witness). The fragility report
  names the record's single points of evidentiary failure: the Persian Wars rest on
  one author, the March of the Ten Thousand on Xenophon, the Jugurthine War on
  Sallust, the Catilinarian Conspiracy on Cassius Dio.
- **annona premium (W3)** — Baetican olive oil defies transport-cost decay: 24 sites
  hold it at ≥5× the cost expectation, and beyond 1,500 km — where no civilian market
  explains the volume — 12 of 14 are frontier military bases (Mainz, London, Augst,
  and Hadrian's Wall's supply base at Corbridge, 1,948 km from Baetica). The annona
  militaris, quantified from the CEIPAC stamps (a proxy; the cost model is great-circle,
  the reading follows Remesal Rodríguez).
- **ecology axes (W4, substrate)** — the harborscapes Q/C/D codebook generalised: the
  C axis (relation to water/terrain) across 4,113 Pleiades places (riverine, insular,
  coastal, upland, water-source, wetland); Q and D kept honestly harbor-only (61 sites,
  text-derived), never invented for other places.

## Honesty posture

Every row is `derived` (or `asserted`, for the curated economy centres) and carries
the loci it rests on. Nothing here is model-generated. The intensity layer is an
attestation-**density** proxy, explicitly not output volume. Coarse dating is
classed `floruit` and refused as point-in-time fact. Amphora commodities come from
a cited form typology, and forms without a textbook-secure date stay undated.
Inherited constraints (no embedding unification; Zenodo/Wikidata paused) are
untouched — W1 is a join, not a model that guesses.
