v0.15.1

 ## Changed
   - `GET /api/health` returns 503 until minion registration, the round info cache and the
     scheduler have each come up once. While starting, the body lists what it is still waiting on.
     After that it returns 503 with `Status: Degraded` whenever Postgres is unreachable or RabbitMQ
     is disconnected. The body now includes `Database` and `RabbitMQ` lines
   - `/api/health` no longer goes through the transaction middleware, so a database outage shows
     up as a 503 from the health check instead of a 500
   - `/minion/health` returns the version, `Status` and `RabbitMQ`, and returns 503 while the minion
     is unregistered or has no RabbitMQ connection. Docker's healthcheck retries cover a short
     reconnect
   - The backend, frontend and minion images no longer have the `entrypoint.sh` that waited on
     Postgres and RabbitMQ. The processes already retry both on their own
   - In the compose override, the minion waits for a healthy backend instead of the database, and
     the frontend waits for a healthy backend instead of the database and RabbitMQ
   - Frontend is on TypeScript 7, and npm dependencies are updated

 ## Fixed
   - A check or team deleted mid-round (a database reset, for example) made that round's ledger
     insert fail, and every team lost the round's results. The ledger write now skips results for
     deleted checks and teams, logs a warning with their ids, and writes the rest. A delete that
     lands during the write waits for it to finish, then cascades over the new rows
   - The scheduler published checks in the same order every round, and RabbitMQ's round-robin gave
     each team the same minion, and so the same source IP, every round. Checks are now shuffled
     before publishing
   - `just check-nodes` showed no IP range on Docker 29, which reports no IPAM config for the
     config-only `minion_lan_config` network. It reads the range from `minion_lan` now. That network
     only exists on a node while a minion runs there, so a node without one shows "range shows once
     a minion runs here""