9bdc1633a0
CI / Build, lint & test (push) Successful in 3m38s
/squad/replace is a full replacement: it deletes every assignment and reinserts the supplied slots. Nothing validated that the supplied list was non-empty, so a caller sending no slots silently wiped the squad and got 200/ok back. This happened for real. A FIFA 17 client whose in-memory squad had been destroyed by a bad parse wrote its emptiness back twice; WAL forensics on the staging DB pin the damage to commit frame 465, squad_players 18 rows -> 0, logged as route=squad-replace status=200 outcome=ok. The squad is the authority's state, so mirroring a broken client's model is unrecoverable. No product flow empties a squad: a full-replacement client sends its complete slot array, and no caller or test in the tree builds an empty slot list. So an empty list means the caller's model is broken, and the write is refused with BadRequest. The check runs inside the transaction, so a concurrent write cannot slip between the count and the delete, and a newly created squad counts zero and is unaffected. The regression test asserts both halves: the empty replacement is rejected, and the existing assignments survive it. With the guard removed the test fails with 200 and slots_written 0 - the exact production symptom.