`load_recent_from_database` n'avait qu'une borne basse. `build_scoring_frame` repartait donc de la derniere lecture de toute la table quel que soit `--now` : `target_at` valait toujours "fin du jeu + 1h", et `_age = instant - derniere_lecture` devenait negatif, ce qui passait le seuil de peremption sans rien signaler. Consequence concrete : sur le jeu historique, arrete au 31/12/2024, aucune boucle de rattrapage ne pouvait produire une prevision dont le realise existe deja. La surveillance de derive livree par la migration precedente n'aurait donc rien eu a comparer en demonstration. `until` est desormais obligatoire sur ce chargeur, ce qui interdit de l'oublier, et le mode CSV filtre symetriquement. En exploitation rien ne change, aucune lecture n'etant posterieure a l'heure courante.
Documentation
adr: décisions d'architecture, une par fichier, numérotées et immuables.architecture: les vues du système. Point d'entrée : architecture/README.md.
Décisions en vigueur
| ADR | Sujet |
|---|---|
| 0001 | PostgreSQL avec l'extension TimescaleDB |
| 0002 | Authentification par JWT d'accès et jeton de rafraîchissement opaque |
| 0003 | Autorisation RBAC à trois rôles, relecture du compte à chaque requête |
| 0004 | Journal d'audit en ajout seul, garanti par PostgreSQL |
| 0005 | LightGBM pour la prédiction de consommation, un modèle global |
| 0006 | Le moteur de règles de recommandation vit dans le backend, pas dans ml/ |
| 0007 | Terminaison TLS par un reverse proxy Nginx, en Docker Compose |
| 0008 | Airflow exécute le code du backend en sous-processus, dans son propre environnement |
| 0009 | Deux environnements sur la VM ENI, un projet Compose chacun, déployés par un runner auto-hébergé |
| 0010 | Terraform provisionne la machine, GitHub Actions déploie l'application |
| 0011 | La surveillance de dérive vit dans le backend et écrit sa propre table |