Le fix, en 4 couches :
1. rate-limit fail-open : Redis down ≠ requête bloquée
2. AuthGuard : « erreur » ≠ « zéro org »
3. déploiement : abort si disque trop plein
4. un canary qui écrit dans Redis, pour détecter tôt
Un bug. Quatre symptômes qui semblaient sans rapport.
Le site tombe. Les API répondent 500. Des users actifs sont éjectés vers la page d'accueil. Le monitoring ne voit rien.
Une seule cause racine. Voici la cascade ↓
Le 4e symptôme, le plus sournois.
L'AuthGuard reçoit les 500. Un `.catch(() => null)` transformait l'erreur transitoire en « aucune organisation ». L'AuthGuard en conclut : nouvel utilisateur → redirection vers /welcome.
Des clients actifs, éjectés. Par un disque plein.
Couches 4-5 — Audit + cron retroactive :
- 4 : chaque skip loggé en DB
- 5 : cron horaire scan messages outbound dernière heure, SMS critique si match
Source unique : 1 module exporté, jamais dupliquer les patterns ailleurs.
2 lock tests verrouillent toute la stack.
Question reçue : « Comment éviter qu'un agent IA email réponde à ses propres notifications et crée une boucle infinie ? »
J'ai eu exactement ce bug. Voici la défense en profondeur à 5 couches qu'on a livrée après (RFC standards inclus) :
Couche 3 — Agent self-defense :
Même si couches 1+2 ratent, l'agent refuse de générer reply si email_subject match pattern système.
Belt-and-suspenders. L'agent doit savoir détecter qu'il ne devrait pas parler.
Mentality lock : finir l'existant à 100 % avant d'ajouter du nouveau à 50 %.
Inconfortable à dire dans un marché où chaque éditeur SaaS publie sa launch week.
C'est ce qui fait que le produit tient.
Hier : 50+ PRs mergées sur master en une journée chez https://t.co/o91s7XxCQL.
Pas un sprint nouvelle feature.
Une vague de **finition canonique** sur 30+ features existantes. Anti-pattern « launch week ».
Détails ↓
Le ratio lock tests par PR cette journée : ~1200+ assertions ajoutées au total.
Pas pour le score. Pour que dans 18 mois, un dev qui ouvre une de ces features ne casse pas silencieusement ce qui marche.
Pattern observé 3x en 14 jours : quelqu'un re-introduit un fallback « pour débloquer », cascade.
Les humains oublient. Les lock tests pas.
Coût utilisateur visible : zéro. Coût caché : 40 min sans livraison.
Build in public ne sert à rien si on ne documente pas ce qui a foiré.
Hier 10h39 UTC : 6 deploys consécutifs cascade fail en 40 min.
Root cause documentée : `npm run build` LOCAL sur la machine de prod.
15 Go RAM totale. ~648 Mo libres après containers blue+green. NODE_OPTIONS=8192. Swap explose. Timeout 600s. Exit 1. Retry x6.
Fix structurel v37 (PR Forgejo #268) :
- Zéro `npm run build` autorisé sur edge-1 (lock test bloque)
- TARBALL_WAIT_SEC porté à 900s
- Tarball absent après 900s = exit 0 gracieux (skip, pas crash)
- SMS warning au lieu de critical
- Reconcile cron retry au prochain push