v1.10.0 — job-filterable DPS comparison (your static vs the field)
Ship 3 of 3 in the consumer-side push. T-204 `dps_check_for_encounter` already aggregates per-phase raid DPS across kills, but it pools everything (ours + field together) and ther…
Why
Ship 3 of 3 in the consumer-side push. T-204 dps_check_for_encounter already aggregates per-phase raid DPS across kills, but it pools everything (ours + field together) and there's no job-level granularity. The consumer goal was: "compare median total DPS of public vs your own static, filter down to your job if you want". v1.10.0 delivers both — static-split distributions and an optional per-job narrowing.
Added — dps_comparison_for_encounter()
- New function in analysis/dps_check.py. Splits per-phase DPS into
ours(kills from reports in the static's watchlist) vsfield(everything else), using the same watchlist-scoping rule as v1.8.0 cartography and v1.9.0 mit aggregate. - Without
job: each kill contributes one value (raid DPS = phase total damage / duration). Top-line "where do we sit vs the field" view. - With
job(e.g. "SAM"): contributes one value per matching player per kill. Two SAMs in one kill = two data points. Per-player-DPS distribution that answers "where does our SAM sit vs all SAMs that have cleared". - Returns
jobs_available(every job seen across both sides) so the Home dropdown doesn't need a second roundtrip. - Quartile shape reuses the existing
_quartileshelper (n=1 returns all-equal degenerate; ≥2 uses inclusive quantiles).
Added — GET /api/encounters/{id}/dps-comparison?job=<job>
Context-scoped. Default no-job returns raid-DPS comparison.
Added — Home section "Your DPS vs the field"
- New
DpsComparisonSectionin web/src/Home.jsx, placed after fault contributors. - Job dropdown in the section header:
All jobs (raid DPS)default + every job seen. - Table per phase: Our median · Field p25 · Field median · Field p75 · Δ vs median (percent delta of our median vs field's, color-graded green ≥0 / yellow -10..0 / red <-10).
- Sample-size hint (
n=N) on our column when ≥2 kills aggregated, since one kill is noisy. - Two empty states: (a) no kills anywhere in the encounter → "field comparison activates once kill data exists"; (b) job filter produces no rows for one side → friendly note.
formatDps()helper renders 27.3k-style numbers; tabular numerics for clean column alignment.
Tests
- 6 new in tests/test_dps_comparison.py: empty-encounter zero shape; two-kill ours+field split (correct raid-DPS for both sides); job filter narrows to per-player DPS; non-matching jobs excluded (ours side empty when no PCT among ours); jobs_available reflects both sides; static with no watched kills sees only field.
- 419 tests passing (413 → 419, +6).
Consumer-side push complete
Three ships landed in one session per the plan stated up front: v1.8.0 (Home dashboard), v1.9.0 (mit aggregate), v1.10.0 (job DPS comparison). Non-dev Home now has five vertical sections: encounter picker · Where we are (prog curve) · What's killing us (top wipe mechanics) · How mit usage is going · Who's contributing to wipes · Your DPS vs the field. Together they answer the consumer questions stated this session: "keep inputting reports", "graph progress", "what gimmick are we wiping to", "who's contributing to wipes", "mit being applied or not", "median DPS vs field optionally per job".