Vigil
← All news

v1.15.1 — Roster polish + sub-account merge in fault contributors

[analysis/roster_discovery.py](analysis/roster_discovery.py). Before: a member with ≥2 aliases had ALL of them classified as `sub` (so P1 marked core + P2 attached as sub of P1 ma…

Fixed — classifier bug: both halves of a main+sub pair showed as each other's sub

analysis/roster_discovery.py. Before: a member with ≥2 aliases had ALL of them classified as sub (so P1 marked core + P2 attached as sub of P1 made BOTH P1 and P2 render as each other's sub). After: pick the PRIMARY alias per member (min alias.id — the one created first, by convention the member's main character) and only non-primary aliases get sub. Primary keeps member.kind ('core' or 'substitute'). The fix preserves the existing test (Bob → sub) and adds a regression assertion that the primary (Alice → core) stays correctly classified.

Fixed — copy clarification + "sub-stitute" hyphen

web/src/Members.jsx. The page header now spells out the four roles explicitly: core = a real person's main account; sub = a secondary character of the SAME person (alt / sub-account); substitute = a backup member (their own person, their own characters); ignore = pugs, loot trades, anyone you don't want in analytics. The character-checklist intro got the same treatment. Replaced the visually-hyphenated <button>sub-stitute</button> with plain <button>substitute</button> (the dash was an unintentional line-wrap artifact).

Added — sub-account merge in "Who's contributing to wipes"

When a roster member owns multiple character aliases (main + subs), the fault contributors table now collapses them into one row.

  • Backend (analysis/fault_attribution.py): fault_aggregate_for_encounter joins each FFLogs player_id to its roster member via static-scoped character_aliases (prefer (name, server) exact match; fall back to name-only when exactly one member claims the name — same lookup as resolve_members.py / roster_discovery.py). Per-player rows now carry member_id, member_name, and server.
  • Frontend (web/src/Home.jsx): FaultSection groupedPlayers regroups by member_id when present (m:${id} key), falls back to character name (n:${name}). Each grouped row tracks its constituent characters in a characters_list with per-character fights / score / jobs. The Player cell renders a +N alt / +N alts accent pill when character_count > 1 (tooltip lists each character + server + jobs). The row expansion grows a third sub-table — "Characters merged into Alice (3 accounts)" — between the per-job breakdown and the per-mechanic top-killers.

Tests

  • 1 new in tests/test_fault_attribution.py: seed Alice owning P1, Bob owning P2 + P3 (main + sub), compute faults, assert the aggregate response gives all three rows a member_id/member_name and that Bob's rows share the same member id.
  • 1 regression assertion in tests/test_roster_discovery_v1_15.py: in test_discovery_marks_subs_when_owner_has_multiple_aliases, also assert that "Alice Tankerton" (the primary) stays as classification: "core" after Bob is attached.
  • 494 tests passing (480 → 494, +14: 13 from v1.15.0 + 1 today).