Vigil
← All news

v0.29.0 — ### Added — T-302 M-FAULT strat-aware fault attribution

- `analysis/fault_attribution.py::compute_fault_scores_for_fight()` walks deaths in one fight and classifies each as **root** / **cascade** / **enrage** / **unknown** based on the…

  • analysis/fault_attribution.py::compute_fault_scores_for_fight() walks deaths in one fight and classifies each as root / cascade / enrage / unknown based on the killing ability's type_label from fight_model (T-203):
    • tankbuster / aoe_party → root (the targeted player failed)
    • raidwide → root if it's the first death, cascade if a preceding death sits within 5s
    • non-attributable (FFLogs sourceID=-1 / null ability) → cascade
    • enrage → enrage (boss DPS check)
  • Writes per-(fight, player) rows to fault_scores (already in schema from T-003). score = roots × 1.0 + cascades × 0.1. reasons JSONB carries the per-death breakdown.
  • classify_wipe_type() categorizes whole fights as kill / enrage_dps / body_check / mechanics / mixed — headline for T-307 Discord reports.
  • fault_aggregate_for_encounter() aggregates across all our wipes per encounter, per player — the "weekly summary" view.
  • API: POST /api/fights/{id}/fault-scores/compute, GET /api/fights/{id}/fault-scores, GET /api/fights/{id}/wipe-type, GET /api/encounters/{id}/fault-aggregate.
  • React FaultScores panel in PullDetail — colored score column (red ≥1.0, orange ≥0.5), per-player root/cascade/unknown counts, compute/re-compute button.
  • 15 new tests (7 pure-function _death_kind branches + 8 end-to-end including live M5S AC). 246 tests total.
  • Live AC on M5S wipe #75 (9 deaths): classified as mechanics wipe type, 0 root / 7 cascade / 2 unknown. The high unknown-count is honest: M5S fight_model only has 18 canonical abilities (sparse consensus on a short fight), so many killing abilities lack labels. Confirming more labels via the T-108 review queue tightens this directly. T-303 mit audit + T-304 disambiguation will improve cascade classification further.