# Agents & Skills pour Flowdeck — Phase 4 : Agir dehors, travailler sur fichiers, compter | Champ | Valeur | |---|---| | Phase | **4 sur 5** — la parité complète (dernière phase de fonctionnalité) | | Document parent | `architecture-agents-skills-notion-flowdeck.md` v1.1 — en particulier §3.2 et §3.5–3.6, §10.6–10.7, §14, §15, §16.3–16.5 | | Version | 1.0 — 9 octobre 2026 | | Auteur | Spark, pour Bruno | | Statut | Prêt à implémenter **après la Phase 3** | | Prérequis | Phase 3 (dispatcher, régime `allowlist`, approbations en autonome) | | Migrations créées | **42** (modèles & usage) et **43** (fichiers des runs) | | Débloque | Phase 5 (optimisations sur données réelles d'usage et de coûts) | > **Résultat visible à la fin de cette phase.** L'Agent agit dans le monde extérieur, sous confirmation : il cherche et poste dans **Slack** (nouveau connecteur), rédige/envoie/archive dans **Gmail**, **trouve un créneau** entre participants avec des suggestions classées et une grille, puis réserve ; il **gère l'Inbox** Flowdeck par le chat ; les Custom Agents gagnent des déclencheurs messagerie/courriel/calendrier. Dans le chat, on **dépose des fichiers** (PDF, CSV, XLSX, DOCX, PPTX, ZIP) que l'Agent lit, analyse avec du code sandboxé, transforme en pages ou bases, et il **rend des fichiers téléchargeables**. Et tout est **compté** : modèles autorisés par surface, modèles premium activés par l'admin, allocation d'usage, crédits, limites par membre et par agent, tableaux d'usage. --- ## Table des matières 1. [Objectif](#1-objectif) 2. [Périmètre](#2-périmètre) 3. [État d'entrée](#3-état-dentrée) 4. [Modèle de données — migrations 42 et 43](#4-modèle-de-données--migrations-42-et-43) 5. [Tickets de travail](#5-tickets-de-travail) 6. [API livrée par la phase](#6-api-livrée-par-la-phase) 7. [Comportements détaillés](#7-comportements-détaillés) 8. [Tests](#8-tests) 9. [Critères d'acceptation](#9-critères-dacceptation) 10. [Risques spécifiques et vigilance](#10-risques-spécifiques-et-vigilance) 11. [Ordre d'exécution](#11-ordre-dexécution) 12. [Définition de « terminé »](#12-définition-de--terminé-) --- ## 1. Objectif Trois chantiers indépendants mais livrés ensemble parce qu'ils partagent la même exigence — **ne jamais agir ou dépenser dans l'ombre** : 1. **Les actions externes** (écarts E8 du parent) : chaque écriture hors Flowdeck est un outil de classe `EXTERNAL_WRITE`, confirmé ou couvert par une politique explicite, et journalisé comme les écritures internes. 2. **L'espace fichiers** (écart E9 + E10) : l'Agent cesse d'être limité au texte du workspace ; il ingère, calcule et produit, en assemblant importers, sandbox Workers et exports existants. 3. **La comptabilité** (écart E13) : les modèles deviennent gouvernés (autorisés par surface, premium activés) et chaque run a un coût calculé depuis un journal — c'est ce qui rend les deux premiers chantiers soutenables en production. ## 2. Périmètre ### 2.1 Inclus - Contrat « agent-ready » pour les connecteurs (sources / outils de lecture / outils d'écriture / déclencheurs / identité) appliqué à tous les connecteurs livrés dans la phase. - Connecteur **Slack** natif : connexion workspace (admin) + connexion de compte (utilisateur) ; outils de l'Agent personnel (identité *utilisateur*) et des Custom Agents (canaux accordés) ; déclencheurs message/réaction/mention. - Google/MS365 : second consentement pour les **scopes d'écriture** ; outils Gmail (brouillon, envoi, archive, étiquettes, corbeille, désabonnement) ; outils calendrier (trouver un créneau + grille, créer, préparer, déplacer si organisateur) ; dépôt d'un fichier produit dans Drive/Files. - Outils **Inbox** : lire/résumer, regrouper, marquer, archiver (dont en masse avec confirmation et compte exact) ; bornes documentées (pas de décision d'approbation, pas de création de notification, pas de réglages). - Promotion des connecteurs Discord/Telegram/Teams au contrat agent-ready (canaux comme sources, cibles d'envoi, déclencheurs). - Déclencheurs Phase 4 dans le dispatcher de la Phase 3 : `message.posted`, `message.reaction`, `message.mention` (par connecteur), `mail.received`, `calendar.event_created/updated/cancelled`. - Classe d'outils `EXTERNAL_WRITE` dans la gouvernance : approbation par défaut, politiques pré-approuvées bornées (outil × cible) pour les Custom Agents, envoi de courriel toujours confirmé pour l'Agent personnel. - Espace fichiers : dépôt dans le chat (trombone + glisser-déposer), `agent_run_files`, extraction par les importers, profil tabulaire, outil `run_code_on_data` sur la sandbox Workers avec montage borné, `produce_file` (XLSX, PDF, DOCX, PPTX), `create_collection_from_file`, **tableau interactif de résultats** dans le chat, rétention et purge. - Migration 42 : `workspace_ai_settings` (modèles autorisés par surface, premium, modèle par défaut, limites, qui peut créer des agents, accès web par défaut), `ai_usage_ledger` ; service `usage_meter` ; tarification par modèle en réglages ; allocation d'usage (fenêtre calculée depuis le journal) ; limites membre et agent appliquées au routage de modèle ; tableaux d'usage (admin) et coût par run dans Activity ; webhooks de seuil de crédits. - Application de `credit_limit_monthly` (Phase 3, colonne créée) et de `who_can_create_agents`. ### 2.2 Exclu - Le **serveur MCP** Flowdeck (chantier séparé déjà documenté côté Flowdeck) et le SDK d'agents externe → Phase 5 (préparation seulement). - Les connecteurs métier nouveaux au-delà de Slack (CRM, billetterie…) : le contrat agent-ready et le client MCP les couvrent sans code dédié. - La refacturation réelle : les crédits sont une unité de compte interne (question ouverte Q1 du parent : quotas de gouvernance ou reflet de coûts fournisseurs — le journal livré ici sert les deux, seuls les taux changent). ## 3. État d'entrée | Élément | État | |---|---| | Connecteurs natifs (gitea, github, web, google, ms365) + personnels (custom, discord, telegram, mcp) ; OAuth Google/MS365 **lecture seule**, refresh auto, secrets Fernet | Existants (§16.4 de l'architecture) | | `connectors.py` (fetch gardé SSRF), `oauth_connectors.py`, client MCP complet | Existants | | Importers (PDF, DOCX, CSV/XLSX, ZIP via pipeline) ; exports (XLSX, PDF, DOCX…) | Existants (§21) | | Workers sandboxés (AST, pas de réseau/filesystem, timeout 30 s, budget journalier) | Existants (§19.2) | | Service de notifications + Inbox sidebar | Existant (§19.4) | | `agent_approvals`, webhooks `agent.*`, dispatcher + régime `allowlist`, `agent_runs` avec `credits` à 0 | Livrés Phases 2–3 | | `llm_config` (23 fournisseurs, précédence 4 niveaux) | Existant — les taux par modèle s'y ajoutent | ## 4. Modèle de données — migrations 42 et 43 ```sql -- Migration 42 — Phase 4 (gouvernance modèles & usage) CREATE TABLE workspace_ai_settings ( workspace_id INTEGER PRIMARY KEY REFERENCES workspaces(id), allowed_models_personal_json TEXT DEFAULT '[]', -- [] = tous les modèles configurés allowed_models_custom_json TEXT DEFAULT '[]', premium_models_json TEXT DEFAULT '[]', -- activés par l'admin default_model TEXT, member_credit_limit INTEGER, -- crédits / membre / mois ; NULL = illimité allowance_json TEXT DEFAULT '{}', -- {window_hours, volume} de l'allocation incluse who_can_create_agents TEXT DEFAULT 'everyone', -- 'everyone' | 'admins' web_access_default INTEGER NOT NULL DEFAULT 0, updated_by INTEGER REFERENCES users(id), updated_at TEXT ); CREATE TABLE ai_usage_ledger ( id INTEGER PRIMARY KEY, workspace_id INTEGER NOT NULL, run_id INTEGER REFERENCES agent_runs(id), user_id INTEGER REFERENCES users(id), agent_id INTEGER REFERENCES agents(id), provider TEXT, model TEXT, tokens_in INTEGER DEFAULT 0, tokens_out INTEGER DEFAULT 0, credits REAL NOT NULL DEFAULT 0, bucket TEXT NOT NULL DEFAULT 'allowance', -- 'allowance' | 'premium' created_at TEXT NOT NULL ); -- Index : (workspace_id, created_at), (user_id, created_at), (agent_id, created_at). -- Taux par modèle : table de correspondance dans les réglages (JSON versionné), -- {"/": {"in_per_1k": x, "out_per_1k": y, "premium": bool}} -- le mode offline a un taux de 0 par construction. -- Migration 43 — Phase 4 (espace fichiers) CREATE TABLE agent_run_files ( id INTEGER PRIMARY KEY, run_id INTEGER REFERENCES agent_runs(id), conversation_id INTEGER REFERENCES agent_conversations(id), direction TEXT NOT NULL, -- 'input' | 'output' name TEXT NOT NULL, mime TEXT, size INTEGER, storage_path TEXT NOT NULL, -- data/uploads/agent-files//… created_at TEXT NOT NULL, expires_at TEXT -- NULL = livrable conservé par l'utilisateur ); ``` Règles : le ledger est **append-only** (aucune correction d'écriture — un ajustement est une ligne négative motivée, créée par un admin) ; les agrégats (allocation consommée, crédits du mois) sont **toujours calculés** depuis le ledger ; `agent_run_files` ne stocke jamais le contenu en base. ## 5. Tickets de travail ### Le contrat connecteur et Slack **P4-T01 — Contrat agent-ready et registre des capacités.** Fichiers : `app/services/connectors.py` (extension), registre dans `tool_registry.py`. Travail : formaliser la déclaration de capacités du parent §14.1 (sources, read_tools, write_tools, triggers, identité) ; le sélecteur *All sources* (Phase 2) et le Tool Registry consomment cette déclaration au lieu de listes codées en dur ; un connecteur sans déclaration reste utilisable en lecture comme aujourd'hui (compatibilité). Acceptation : brancher un connecteur de test déclaratif suffit à le faire apparaître dans All sources et dans les outils, sans autre code. **P4-T02 — Connecteur Slack natif : connexions.** Fichiers : catalogue des connecteurs natifs, flux OAuth (patron des natifs existants). Travail : connexion **workspace** par un admin (préalable aux agents) stockée comme les autres connecteurs workspace ; connexion **compte** par utilisateur pour l'Agent personnel (jeton utilisateur, Fernet) ; écran de statut distinguant les deux niveaux ; révocation indépendante. Acceptation : sans connexion workspace, les déclencheurs Slack d'agents sont refusés proprement ; sans connexion compte, l'Agent personnel signale le manque au lieu d'échouer en cours de run. **P4-T03 — Outils Slack.** Travail : lecture (chercher des personnes ; lire canaux publics/privés et fils **dans la visibilité du jeton utilisé** ; lire les fichiers partagés récents) et écritures `EXTERNAL_WRITE` (poster, répondre en fil, éditer **ses propres** messages, réagir) ; identité *utilisateur* pour l'Agent personnel (les messages portent son nom), identité *agent* pour les Custom Agents limitée aux canaux présents dans `agent_access` (extension de `resource_type` à `'channel'`) ; l'outil d'édition refuse tout message non émis par la même identité. Acceptation : test de borne — avec un jeton limité à un canal, aucune lecture ni écriture hors de ce canal n'est possible, y compris par recherche. **P4-T04 — Déclencheurs Slack et messageries existantes.** Travail : émission vers le bus — Slack : `message.posted` (filtres mots-clés, inclusion des fils), `message.reaction`, `message.mention` ; indicateur d'activité dans le canal pendant le run (`show_typing` du déclencheur) ; promotion de Discord/Telegram/Teams au même contrat : leurs événements existants alimentent les mêmes `event_name`, leurs canaux deviennent des ressources accordables et des cibles de `channel_post`. Acceptation : UC-05 (rapport horaire posté) et un triage sur mention fonctionnent sur Slack **et** sur un connecteur de messagerie préexistant, sans code de dispatcher différent. ### Écritures Google / Microsoft 365 et Inbox **P4-T05 — Second consentement d'écriture et outils Gmail.** Fichiers : `app/services/oauth_connectors.py`. Travail : demande de scopes d'écriture séparée et révocable indépendamment (l'état « lecture seule » reste le défaut et un état stable) ; outils : `mail_draft`, `mail_send`, `mail_archive`, `mail_label`, `mail_trash` (+ désabonnement d'expéditeur) sur Gmail et, en parité de contrat, Outlook/Graph ; l'envoi est **toujours** confirmé pour l'Agent personnel (carte d'approbation montrant destinataires, objet, corps complet) ; pour les Custom Agents, l'envoi exige une politique pré-approuvée explicite par boîte. Acceptation : aucun envoi ne part sans que le contenu exact envoyé soit celui qui a été approuvé (hash du contenu dans la demande d'approbation, revérifié à l'exécution). **P4-T06 — Outils calendrier d'agent.** Travail : `calendar_find_time` (croise les disponibilités des participants sur les calendriers connectés, rend des suggestions **classées** avec les motifs du classement — chevauchements évités, préférences horaires — et la matière de la **grille interactive** rendue dans le panneau : créneaux × participants, sélection en un clic) ; `calendar_create_event` (organisateur = l'utilisateur ou l'agenda accordé) ; `calendar_prep` (assemble événement, participants, pages liées, dernière note de réunion) ; `calendar_move/cancel` bornés aux événements dont l'acteur est organisateur ; en multi-calendriers : calendrier par défaut, sinon question à l'utilisateur. Acceptation : UC-09 (calendrier) passe ; déplacer un événement d'un tiers est refusé avec le motif, pas tenté. **P4-T07 — Outils Inbox.** Fichiers : service de notifications existant (ajout d'une API de service consommable par les outils, pas d'accès direct aux tables depuis le registre). Travail : `inbox_read` (résumé structuré : nouveau, à répondre, peut être effacé), `inbox_group` (type / statut / projet / page), `inbox_mark`, `inbox_archive` (masse comprise) ; confirmation obligatoire au-delà d'un seuil d'éléments (défaut proposé : 10) avec **compte exact** affiché ; bornes : les notifications d'approbation/demande d'accès sont signalées mais jamais décidées ; aucun outil de création de notification ni de modification des préférences. Acceptation : « archive tout ce qui est lu » sur une Inbox de test de 250 éléments archive exactement les éléments lus, après une confirmation affichant « 250 » — ni 249 ni 251 (test de comptage sur fixture). **P4-T08 — Classe `EXTERNAL_WRITE` dans la gouvernance.** Fichiers : `app/services/agent_policies.py`, `agent_approvals`. Travail : quatrième classe d'outils ; par défaut approbation par action (le run passe en `waiting_approval`, carte dans le panneau **ou** dans Activity pour les runs autonomes) ; politiques pré-approuvées pour les Custom Agents : tuples (agent, outil, cible) accordés par un niveau `full`, révocables, expirant par défaut (durée réglable, défaut proposé : 90 jours) et affichés dans les Settings de l'agent ; toute écriture externe exécutée écrit dans `agent_actions` avec, quand le tiers le permet, l'action inverse (supprimer le message…) sinon la mention « non annulable ». Acceptation : il n'existe aucun chemin d'exécution d'un outil `EXTERNAL_WRITE` qui contourne soit l'approbation, soit une politique en vigueur (test par énumération des points d'entrée du registre). ### Espace fichiers **P4-T09 — Dépôt et lecture de fichiers de conversation.** Fichiers : routes de conversation (téléversement), nouveau `app/services/agent_files.py`, importers. Travail : dépôt par trombone et glisser-déposer ; validation (liste blanche de types alignée sur les importers, taille `AGENT_FILE_MAX_MB`) ; stockage sous `data/uploads/agent-files/` ; outil `read_uploaded_file` : extraction texte (PDF/DOCX/PPTX), profil tabulaire (CSV/XLSX : colonnes, types devinés, aperçu), inventaire ZIP (pas d'extraction récursive, plafond décompressé) ; le LLM ne reçoit que résumés et aperçus, jamais le binaire. Acceptation : déposer le CSV d'UC-08 donne à l'Agent un profil fidèle (noms et types de colonnes, nombre de lignes exact). **P4-T10 — Calcul sandboxé et production de fichiers.** Travail : `run_code_on_data` sur le moteur des Workers avec l'unique écart documenté (montage en lecture des fichiers de la conversation, répertoire de sortie en écriture, quotas renforcés) ; `produce_file` pour XLSX/PDF/DOCX/PPTX avec les bibliothèques d'export existantes ; cartes téléchargeables dans le message (`GET …/files/{id}/download` avec contrôle d'ACL de la conversation) ; `create_collection_from_file` via le pipeline d'import (déduplication comprise). Acceptation : UC-08 de bout en bout ; un code qui tente un accès réseau ou hors du montage est bloqué par la sandbox, et le run continue avec l'échec comme résultat d'outil. **P4-T11 — Tableau interactif de résultats dans le chat.** Fichiers : panneau, outil `query_collection` formalisé (Annexe B du parent). Travail : quand un résultat d'outil est tabulaire (lignes × colonnes typées), le panneau le rend en tableau en lecture (tri client, ouverture de la ligne source) ; le tableau est un artefact du message, pas une collection ; plafond de lignes affichées avec mention du total. Acceptation : une question « quelles tâches en retard ? » rend le tableau sans ouvrir la base, et chaque ligne ouvre la bonne tâche. **P4-T12 — Rétention des fichiers.** Travail : `expires_at` posé au dépôt (défaut `AGENT_FILE_RETENTION_DAYS`, 30 j) sauf pour les livrables que l'utilisateur épingle/conserve ; purge ajoutée au `trash_purge_scheduler` existant ; la suppression d'une conversation supprime ses fichiers et sa mémoire (règle du parent §16.6). Acceptation : après purge simulée, les métadonnées de run subsistent (nom, taille) mais aucun fichier expiré n'est téléchargeable. ### Comptabilité et gouvernance des modèles **P4-T13 — `usage_meter` et journal d'usage.** Fichiers : nouveau `app/services/usage_meter.py`, migration 42, extension de `llm_config` (taux par modèle). Travail : à la fin de chaque run (et, pour les runs longs, par paliers), écrire la ligne de ledger depuis `agent_runs` (tokens réels remontés par le client LLM) : bucket `allowance` si le modèle est inclus, `premium` sinon ; le taux zéro du mode offline est un cas de test permanent ; webhooks `agent.credits.threshold` aux seuils 50/80/100 % des limites concernées. Acceptation : la somme du ledger recoupe les tokens des `agent_runs` sur toute période de test ; aucun run terminé sans ligne (ou ligne à zéro explicitement offline). **P4-T14 — Modèles gouvernés : autorisés par surface, premium, replis.** Travail : le routeur `Auto` (Phase 2) et les sélecteurs ne voient que les modèles **autorisés pour la surface** ; les premium exigent l'activation admin et puisent dans les crédits ; un modèle désactivé disparaît (grisé pendant la transition) et les agents qui l'utilisaient basculent au prochain run sur défaut/`Auto` (comportement annoncé dans les Settings de l'agent, pas silencieux pour son propriétaire : notification) ; à limite de crédits atteinte (membre ou agent), les modèles inclus continuent et les premium s'arrêtent avec un état explicite dans le run. Acceptation : retirer un modèle utilisé par un agent ne casse aucun run suivant et laisse une trace visible pour le propriétaire. **P4-T15 — Tableaux d'usage et réglages IA du workspace.** Fichiers : page de réglages (section IA & Agents du parent §7.6). Travail : réglages de `workspace_ai_settings` (deux listes de modèles, premium, défaut, limites, `who_can_create_agents` **appliqué**, accès web par défaut) ; tableaux : usage par membre, par agent, par modèle (période, bucket, crédits), export CSV ; le coût (tokens + crédits) rejoint l'onglet Activity des agents et le détail d'un run du panneau. Acceptation : un admin répond en moins d'une minute, depuis l'interface, à « qui a dépensé quoi, sur quel modèle, cette semaine ? ». ## 6. API livrée par la phase | Route | Ticket | |---|---| | `POST /api/agent/conversations/{id}/files` · `GET …/files/{fid}/download` | T09/T10 | | `GET/PUT /api/settings/ai` (réglages IA du workspace, admin) | T15 | | `GET /api/settings/ai/usage` (+ `?format=csv`) | T15 | | `POST /api/agent/connectors/slack/connect` (workspace et compte) | T02 | | Outils (pas des routes) : Slack, Gmail, calendrier, Inbox, fichiers | T03/T05/T06/T07/T09/T10 | | Webhooks : `agent.credits.threshold` ; champs `credits` dans `agent.run.*` | T13 | ## 7. Comportements détaillés ### 7.1 Confirmation : ce que l'utilisateur voit Une demande d'approbation montre **l'action exacte** : pour un courriel, destinataires/objet/corps ; pour un message de canal, le canal et le texte ; pour une archive en masse, le compte et le critère. Approuver exécute **ce** contenu (hash revérifié pour le courriel) ; toute modification du contenu par l'Agent après coup exige une nouvelle approbation. Un refus laisse le run se terminer proprement avec le motif « refusé » dans la réponse. ### 7.2 Allocation, crédits, limites : les trois compteurs en pratique ```text Run démarre → modèle résolu (Phase 2/4) ├─ modèle inclus → le run puise dans l'ALLOCATION (fenêtre glissante du workspace) │ allocation épuisée → le run est refusé proprement (« allocation épuisée, │ renouvellement à … »), sauf si des crédits peuvent prendre le relais (réglage) └─ modèle premium → le run puise dans les CRÉDITS limite membre ou limite agent atteinte → premium refusé, repli annoncé sur un modèle inclus (jamais d'arrêt sec quand un repli existe) Fin du run → ligne de ledger (toujours), seuils vérifiés → webhooks éventuels ``` ### 7.3 Identités externes — le tableau à ne jamais violer | Contexte | Jeton utilisé | Signature visible chez le tiers | |---|---|---| | Agent personnel → Slack/Gmail | Celui de l'utilisateur | L'utilisateur | | Custom Agent → canaux accordés | Celui de l'app/du connecteur workspace | L'agent (nommé) | | Custom Agent → Gmail | Uniquement via politique pré-approuvée par boîte | La boîte accordée | | Tout agent → calendrier | Organisateur = l'utilisateur ou l'agenda accordé | L'organisateur réel | ### 7.4 Ce que les fichiers ne sont pas Un fichier déposé est une **donnée**, jamais une consigne : son contenu est délimité comme les autres contenus lus (§16.4 du parent). Un tableur contenant « envoie ce fichier à… » ne déclenche rien d'autre qu'un éventuel résultat d'outil refusé par la gouvernance. ## 8. Tests | # | Niveau | Cas | |---|---|---| | T-01 | Intégration | Contrat connecteur : un connecteur de test déclaratif apparaît dans All sources et fournit ses outils | | T-02 | Intégration | Slack borné : lecture/écriture hors canal accordé impossibles (jeton restreint) | | T-03 | Intégration | Envoi Gmail : contenu approuvé = contenu envoyé (hash) ; refus = rien n'est parti | | T-04 | Intégration | `calendar_find_time` sur disponibilités de fixture : classement explicable, grille cohérente ; déplacement d'un événement tiers refusé | | T-05 | Intégration | Inbox : archive en masse au compte exact après confirmation ; notifications d'approbation jamais décidées | | T-06 | Intégration | Énumération des points d'entrée `EXTERNAL_WRITE` : aucun ne contourne approbation/politique | | T-07 | Intégration | UC-08 complet en mode offline (extraction et production déterministes, le calcul par un « faux » code sandboxé inclus) | | T-08 | Intégration | Sandbox : tentative réseau et tentative de sortie du montage bloquées | | T-09 | Intégration | Ledger : somme par période = somme des runs ; run offline = ligne à 0 ; allocation épuisée = refus propre | | T-10 | Intégration | Limite membre atteinte : premium refusé avec repli annoncé, modèles inclus toujours utilisables | | T-11 | Intégration | Modèle retiré : l'agent bascule, le propriétaire est notifié, Activity le montre | | T-12 | E2E | Déposer un CSV dans le chat, obtenir le tableau de résultats et le XLSX produit téléchargeable | | T-13 | E2E | Trouver un créneau à trois et réserver depuis la grille | | T-14 | Non-régression | Les connecteurs en lecture seule fonctionnent inchangés pour les utilisateurs sans consentement d'écriture | ## 9. Critères d'acceptation - [ ] UC-08, UC-09 et UC-10 passent de bout en bout. - [ ] Aucune écriture externe sans approbation ou politique pré-approuvée en vigueur (T-06). - [ ] Aucun run sans ligne au ledger ; les tableaux d'usage recoupent les runs. - [ ] Un Custom Agent déclenché par une mention dans un canal accordé répond dans ce canal et nulle part ailleurs. - [ ] La parité fonctionnelle du document parent §3 est atteinte : la Phase 5 n'a plus de fonctionnalité à ajouter, seulement à durcir. ## 10. Risques spécifiques et vigilance | Risque | Vigilance | |---|---| | Consentements OAuth d'écriture trop larges demandés d'un bloc | Le second consentement est séparé, nommé par domaine (courriel **ou** calendrier), et la lecture seule reste un état complet et digne | | Un envoi approuvé puis modifié par une reprise de run | Hash du contenu dans l'approbation (T05) ; un run repris après refus repart d'une demande nouvelle | | Explosion des coûts par un déclencheur de messagerie bavard | Les plafonds de la Phase 3 s'appliquent, plus les budgets crédits désormais réels ; l'indicateur d'activité (`show_typing`) est désactivable et les filtres mots-clés sont proposés par défaut | | Le montage fichiers de la sandbox devient une brèche | C'est l'unique écart au modèle Workers : revue de sécurité dédiée avant T10, chemins canonisés et vérifiés sous le répertoire de la conversation, quotas bas par défaut | | L'allocation « fenêtre glissante » mal comprise crée des refus surprenants | L'état courant de l'allocation est visible par l'utilisateur dans ses réglages, avec l'heure de renouvellement calculée depuis le ledger — jamais un message « réessayez plus tard » sans date | | Slack change ses API/scopes | Le connecteur isole les appels derrière son service ; les tests d'intégration Slack utilisent un double d'API, les tests réels sont manuels et listés dans la grille de test | ## 11. Ordre d'exécution ```text T01 ──┬── T02 ── T03 ── T04 ├── T05 ──┐ ├── T06 ├── T08 (gouvernance, avant toute mise en service des écritures) └── T07 ──┘ T09 ── T10 ── T11 ; T12 après T10 T13 ── T14 ── T15 Les trois chantiers (externe / fichiers / comptabilité) sont parallélisables, mais T08 et T13 sont les portes : pas d'écriture externe en production sans gouvernance complète, pas de premium sans comptage. ``` ## 12. Définition de « terminé » Critères du §9 verts ; revue de sécurité passée sur `EXTERNAL_WRITE` et sur le montage fichiers ; deux semaines de fonctionnement avec le ledger en observation (écarts ledger/runs à zéro) ; document parent annoté (« Phase 4 livrée — parité atteinte ») ; aide in-app complète pour les nouveaux réglages. --- *Document de phase 4/5 — dépend des Phases 1 à 3 ; la Phase 5 ne fait que durcir et étendre.*