# Cycle "need review" (Phase 2) > Pièce maîtresse. Tout asset/op privilégié est sous review avant exécution. > Voir `docs/risk-tiers.md` (paliers) et `docs/security.md` (sécurité). ## Asset & états Un asset (table SQLite `assets`, `src/gatekeeper/repository.ts`) suit : - **PROVISOIRE** : créé et exécutable, sursis de 7 jours (réservé au palier `reversible`). - **APPROUVÉ** : review OK → permanent, plus d'alertes. - **REFUSÉ** : review KO → désactivé. - **BLOQUÉ** : sursis écoulé OU palier `privileged` (aucun sursis) → non exécutable ; toute tentative lève une alerte. Champs : `id, type, version, risk_tier, status, created_at, expires_at, exec_count, commit_link, doc_link`. ## Règle de sursis (non négociable) - `reversible` → PROVISOIRE 7 j (`createAsset` pose `expires_at = +7j`). - `privileged` → **BLOQUÉ immédiat, aucun sursis** (`expires_at = null`). - Le LLM ne peut jamais reclasser un asset (`assertNoEscalation` : `privileged → reversible` interdit). Le palier vient des annotations MCP. ## Gatekeeper (`src/gatekeeper/gatekeeper.ts`) Vérifie le statut **avant chaque exécution** (`canExecute`) : - lecture seule → autorisée, sans asset ; - privilégié inconnu → enregistré **BLOQUÉ** + exécution refusée + hook d'alerte ; - privilégié **APPROUVÉ** → exécuté, `exec_count` incrémenté ; - REFUSÉ / BLOQUÉ / sursis expiré → refusé. Branché via `GatekeeperGuard` (interface `Guard` ; la boucle agent est inchangée). ## Cron (`src/gatekeeper/review.ts`) `startExpiryCron` passe horairement les PROVISOIRE échus en BLOQUÉ (`expireProvisional`). `runExpiryOnce` = un passage (testable). ## Review (humaine, hors LLM) Commandes owner Telegram (`src/surfaces/commands.ts`) : `/pending`, `/approve `, `/refuse `, `/help`. Le LLM n'y a pas accès : seul l'humain change un statut. ## Gate de phase `CHLOVA_PHASE` (défaut 1). Phase 1 : aucun outil mutant exposé, `ReadOnlyGuard`. Phase 2 : tous les outils exposés, `GatekeeperGuard`, cron + review actifs. Passage à `CHLOVA_PHASE=2` requis pour toute écriture (et `PORTAINER_READ_ONLY` peut alors valoir `false`). ## Rollback - Repasser `CHLOVA_PHASE=1` → écriture désactivée, retour au cerveau read-only. - `git revert` du commit de l'asset fautif ; redeploy version N-1 (GitOps). - Un asset REFUSÉ reste tracé (audit) ; suppression via op SQL manuelle si besoin. ## Alertes (Phase 3 — implémenté) Stratégie anti-fatigue (`src/alerts/`) : - **tentative bloquée** → alerte immédiate (`onBlockedAttempt`) ; - **1ʳᵉ exécution d'un asset PROVISOIRE** → alerte immédiate (`onFirstProvisionalExec`) ; - **digest quotidien** + **rappel J-1** → `startAlertScheduler` (`runAlertCycleOnce`). Transport : `HttpAlertSender` POST vers `ALERT_WEBHOOK_URL` (webhook n8n) ; sans URL, `NullAlertSender` log-only (fail-safe). Best-effort : une panne d'alerte ne casse jamais l'agent. Le mail est envoyé par le workflow `workflows-n8n/chlova-alerts.v1.0.0.json` (doc : `docs/assets/workflow-chlova-alerts.md`). Le payload ne contient aucun secret. ## Reste à faire (Phase 4+) - Auto-extension : CHLOVA génère commit + version + doc d'un asset **avant** de le passer en need-review (Phase 4).