Vigil
← All news

v1.5.5 — Hungarian multi-cast assignment

- New helper module [analysis/_assignment.py](analysis/_assignment.py): `min_cost_assignment(cost, *, skip_penalty)` — pure-Python O(n³) Jonker-Volgenant solver for rectangular bi…

Changed — timeline-diff slot-to-cast matching is now globally optimal

  • New helper module analysis/_assignment.py: min_cost_assignment(cost, *, skip_penalty) — pure-Python O(n³) Jonker-Volgenant solver for rectangular bipartite assignment with forbidden-pair support via a per-row skip_penalty. No new dependencies (scipy would be a 50 MB add for one algorithm).
  • analysis/timeline_diff.py now builds a slots × casts cost matrix per phase (cost = absolute drift in ms, or SKIP_PENALTY = 10× phase duration for forbidden ability-set pairings) and calls the new solver. Replaces the v1.4.1 nearest-unused per-slot greedy.
  • Greedy was optimal for monotonic same-ability sequences (typical case) but mis-assigned when several slots had overlapping multi-ID candidate pools and a closer-in-time slot ate a cast that a later slot needed. Hungarian finds the globally-min-drift assignment that also maximizes matched slots.
  • Live AC on FRU fight 1500: cascade-drift signal preserved exactly vs v1.5.0 baseline (P1 +0.9s / P2 +10.9s / Adds -13.0s / P3 -14.0s / P4 +7.8s / P5 +11.1s). Fired-counts per phase unchanged or slightly higher.
  • 10 new tests in tests/test_assignment.py covering empty matrix, square, rectangular both ways, forbidden-pair, all-forbidden, single-row, and the motivating multi-cast pathological case (slot A accepts {X,Y}, slot B accepts {X} only — greedy strands B, Hungarian swaps). 360 tests passing (350 → 360).