v1.14.5 — phase-weighted fault scoring (prog-aware)
The score was an absolute sum: a P3 root weighed the same as a P7 root. The user asked for a "mild nonlinear" penalty that weights late-phase wipes heavier, AND a relative weighti…
Why
The score was an absolute sum: a P3 root weighed the same as a P7 root. The user asked for a "mild nonlinear" penalty that weights late-phase wipes heavier, AND a relative weighting that de-emphasizes early-phase wipes once the group has moved past that phase.
Added — three new multiplier helpers
analysis/fault_attribution.py:
_phase_severity(phase)—1 + p(p+1)/14. Gentle quadratic. P3=1.86, P5=3.14, P7=5.0. P5 is ~1.7× P3._within_phase_severity(fight_pct)—1.0at fp=100% (just entered phase) →1.5at fp=0% (boss almost dead). Wipes closer to clearing the phase weigh more._prog_relevance(wipe_phase, best_phase_at_time)— at the prog wall (delta=0) → 1.0; each phase past the wall drops 15% down to 0.3× floor.fight_score_multiplier(...)composes the three.
Changed — fault_aggregate_for_encounter weights at READ TIME
- Builds a running-best-phase timeline by walking ALL watched fights (kills + wipes) in start-time order.
fight_context[fid] = (last_phase, fight_pct, best_phase_at_time). - Per (FaultScore, Fight) row: looks up the context, computes the multiplier, applies it before summing into the per-player score.
scoreis now the weighted total;raw_scoreis preserved alongside.
Stored data unchanged
FaultScore.score stays raw. Re-running compute-all isn't needed when the formula changes — the weighting is applied at read time only.
Tests
- 15 new in tests/test_fault_phase_weighting_v1_14_5.py.
- 471 total passing (456 → 471, +15).