v0.20.0 — ### Added
- **T-202** Cross-group consensus → `fight_model` persistence. `analysis/consensus.py::write_consensus_to_fight_model(session, encounter_id, *, version=1)` runs T-104, then replac…
- T-202 Cross-group consensus →
fight_modelpersistence.analysis/consensus.py::write_consensus_to_fight_model(session, encounter_id, *, version=1)runs T-104, then replaces rows for(encounter_id, version)atomically.seqis assigned by sorting canonical abilities bymedian_relative_t_mswithin each phase.confidence= occurrence_rate;type_labelleft null (T-203 will fill: raidwide/tankbuster/tower/spread/stack/tether/enrage).metacarries{sample_count, pulls_reaching}for downstream filtering. read_fight_model(session, encounter_id)mirrors the write shape for the API.- API:
POST /api/encounters/{id}/fight-model/persist(trigger a write),GET /api/encounters/{id}/fight-model(read persisted rows). - 5 new tests covering write/read/idempotency/seq-ordering/empty cases. 176 tests total.
- Live AC: persisted FRU (encounter 1079) — 6 phases / 149 canonical abilities / 11 pulls aggregated — and M5S (encounter 101) — 2 phases / 18 abilities / 19 pulls.