L'appareil poll GET /devices/:id/update_check sur une boucle courte. Le serveur renvoie trois informations : un flag blocked global (le kill switch), un plancher min_sha informatif, et un flag force_update par appareil.
La nuit de mise à jour, l'appareil vérifie blocked en premier — si true, le cycle est sauté intégralement. Sinon, il lance auto-update.sh qui fait git-fetch, tourne les tests contre une suite known-good, et swap le firmware atomiquement. Chaque résultat (succeeded, failed, rolled_back) est reporté via POST /devices/:device_id/update_events avec from_sha et to_sha, donc l'état du parc est visible par appareil dans l'admin.