Aller au contenu principal

ADR-0206 : Navin Enterprise Meeting Intelligence Agent, capture autorisée et intelligence de réunion au-dessus du Control Plane

  • Statut : proposé (2026-11-05)
  • Décideurs : équipe plateforme Navin Enterprise AI, mission brief 02 (agent_uses_cases/tel_note_meeting/02_NAVIN_AGENT_MEETING_EQUIVALENT_LEEXI.md)
  • Références : ADR-0176 (modèle UC-00 dont les modules génériques sont copiés), ADR-0177 (règle des agents : jamais une seconde installation d'un service partagé), ADR-0173 (plateforme de téléphonie Asterisk, Kamailio, LiveKit), ADR-0205 (produit Notes, destination des pages et des tâches), ADR-0101 (politique de licences), conventions du produit navin-enterprise-meeting/CONVENTIONS.md, paquet OPA eai.meetings (deploy/policies/opa/meetings.rego, tests meetings_test.rego, clé meetings de deploy/policies/opa/data.json), fragment OpenFGA deploy/policies/openfga/products/meetings.fga (+ meetings.tests.fga.yaml, meetings.tuples.yaml), carte Manager navin-meeting-agent (navin-manager/agent-templates/navin-meeting-agent.yaml, statut planned tant que le Service Template n'est pas construit, jamais publiée sans décision explicite du client).

Contexte​

Le brief 02 demande un agent d'intelligence de réunion pour les équipes d'un locataire : capture autorisée des réunions (visioconférence, présentiel, téléphonie), calendrier et participants, traitement média, transcription, diarisation, résumés, décisions et actions, bibliothèque de réunions, questions et réponses sourcées, extraits et partages, relances, synchronisation CRM, rapports multi-réunions et coaching. La cible fonctionnelle est la parité avec les usages d'un outil de type Leexi ; rien de propriétaire n'est copié : ni code, ni modèle, ni marque, et aucune parité n'est annoncée tant qu'elle n'est pas prouvée par un test réel (section 28 du brief). Le produit n'enregistre jamais sans la base juridique et l'état de consentement que son mode exige, ne contourne jamais une salle d'attente ni une politique d'enregistrement d'un fournisseur, et chaque lecture, recherche, export, extrait, partage, session live et traitement en arrière-plan revérifie les permissions côté serveur (sections 7, 19 et 26 du brief).

Décision​

  1. Produit séparé navin-enterprise-meeting/ (id produit meeting, secteur cross_industry) avec son propre frontend Next.js 16 + React 19 + MUI 9 (studio de transcription, lecteur synchronisé, interface live) au lieu du shell partagé de l'ADR-0180 ; pas de product.manifest.json à la racine. Backend FastAPI navin_meeting (hatchling, Python 3.12, mêmes épingles que UC-00), schéma PostgreSQL meeting avec RLS forcée via meeting.current_tenant() / meeting.current_project(), rôles navin_meeting_migrate, navin_meeting_app (sans BYPASSRLS) et navin_meeting_worker, Alembic à révisions nommées, Redis préfixé meeting:{instance_id}:.
  2. Réutilisation des services partagés du Control Plane par le SDK enterprise_ai, jamais une seconde copie : le media store (upload, analyse antivirale ClamAV/YARA-X, classification, chiffrement au repos), la transcription (faster-whisper ou point de terminaison compatible OpenAI via LiteLLM, horodatage des mots, DLP sur les transcriptions), la diarisation (pyannote 3.1 quand elle est installée et que le jeton Hugging Face du client est configuré), les salles LiveKit et le protocole voix temps réel (jetons vérifiés côté serveur, lignes de consentement), le courtier de connecteurs (identifiants courts pour Google, Microsoft Graph, Zoom, Webex, CRM et outils de tâches, jetons de rafraîchissement dans OpenBao), les canaux du locataire (e-mail, chat) pour les relances, LiteLLM pour le LLM et les plongements, Qdrant/Cognee pour l'index sémantique, l'API Notes pour la destination des pages et des tâches. Les enregistrements de téléphonie sont importés par référence depuis client.telephony, jamais réenregistrés. Seule la logique VAD pure (Silero ONNX, MIT) est embarquée dans le worker, qui doit tourner sans le paquet du Control Plane ; ffmpeg/ffprobe sont des binaires du système appelés comme processus, jamais liés ni empaquetés.
  3. Matrice de fournisseurs honnête (section 8 des conventions), exposée par l'API et l'interface avec son statut planned|implemented|tested|partial|blocked et sa raison : livekit (bot participant natif, une piste par participant donc attribution de locuteur vérifiée) et in_person (capture navigateur) visent tested ; jitsi est partial (pas de participant sans navigateur, import Jibri quand il est configuré) ; google_meet, teams, zoom et webex sont partial pour l'import des enregistrements cloud après la réunion et blocked pour le bot live (pas de cadre de bot approuvé livré) ; telephony est tested avec un faux. Un refus du fournisseur (salle d'attente, salle verrouillée, politique) est une erreur typée et une tentative FAILED avec sa raison.
  4. Modes de consentement portés par l'instance et décidés par OPA avant tout enregistrement : explicit_all (chaque participant connu a accordé), host_declares (événement host_declared journalisé), announce_only (événement announced journalisé) ; refus quand l'adaptateur rapporte recording_method = none, refus sous legal hold, journal de consentement, pause et reprise journalisées, indication « enregistrement en cours » dans l'interface.
  5. Autorisation en deux couches via le Control Plane : OpenFGA pour les relations (meeting_instance, meeting_library, meeting, meeting_clip, meeting_report, meeting_template, le backend ne vérifie que les relations can_* ; can_export = can_view but not guest ; can_record = host or owner ; le viewer: user:* d'un extrait est écrit uniquement par le service de partage) et OPA eai.meetings pour les décisions au-dessus des relations : démarrage d'enregistrement (consentement, méthode, legal hold), auto-join (événement externe refusé sans règle), partage externe et lien (domaine, classification, invité), export (legal hold pour les médias, invité, format), extraits, écriture CRM (approbation, connecteur autorisé), relance (approbation et destinataires vérifiés), affectation de tâche à un externe (toujours refusée), retranscription et suppression définitive (legal hold, rétention), changement de rétention (rôles), indexation IA (restricted refusé sauf si l'instance l'autorise, secret toujours refusé), fiche de coaching individuelle (sales manager ou la personne évaluée). Fail closed, raisons triées, chaque décision auditée.
  6. IA fondée sur des preuves : chaque résumé, décision, action, réponse et score cite les segments de transcription dont il provient ; un nom de locuteur deviné n'est jamais affiché comme vérifié ; le modèle ne décide ni n'exécute : écriture CRM, synchronisation de tâches et envoi d'e-mail sont des propositions approuvées par un humain et annoncées uniquement après la confirmation de l'API de destination ; le texte des transcriptions est une donnée non fiable (injection de prompt) et n'est jamais journalisé.
  7. Legal hold et rétention par locataire, projet et type : un legal hold gèle l'enregistrement, la retranscription, les extraits, l'export des médias et la suppression définitive ; l'index sémantique n'est alimenté qu'après la prise de l'instantané des ACL et jamais pour les réunions restricted sans autorisation de l'instance.
  8. Intégration Manager par six composants runtime, migrate, backend, worker, live, web (stratégie dedicated, service navin-meeting-agent), ports de développement web 3490, API 8490, santé du worker 8491, live 8492, Redis 6410. La carte du registre reste planned puis prepared / published: false ; les artefacts sont pending tant qu'ils ne sont pas réellement construits.

Conséquences​

  • Le produit dépend de la disponibilité et des quotas des domaines multimodal, realtime, connecteurs et canaux du Control Plane ; en échange il n'héberge ni modèle STT, ni diarisation, ni secret de connecteur, et bénéficie des mêmes contrôles (antivirus, DLP, audit, kill switch).
  • La matrice de fournisseurs affiche des statuts partial et blocked : la parité avec un bot universel n'est pas promise ; l'import des enregistrements cloud après la réunion est la voie réaliste pour Google Meet, Teams, Zoom et Webex.
  • Toute nouvelle action sensible passe par une relation can_* et une décision eai.meetings ; une action absente de la politique est refusée (unknown_action).
  • Le processus live est un composant de plus à superviser (santé, métriques, sessions WebSocket) ; la cohérence PostgreSQL + media store est vérifiée par le test de restauration.
  • La carte reste absente du catalogue tant qu'aucune validation explicite n'est donnée.

Sécurité​

  • Identité et délégation : le bot et les workers portent une identité de charge de travail et le contexte de délégation de l'utilisateur, jamais un mot de passe brut ; les jetons LiveKit sont vérifiés côté serveur, les valeurs par défaut de développement sont refusées en production ; l'identité ne vient jamais du navigateur.
  • Menaces de la section 26 du brief couvertes par des tests de refus : invitation malveillante et auto-join non autorisé (règle OPA meetings.join.auto), webhook usurpé (vérification par le courtier de connecteurs), fuite de lien (meetings.share.link refusé pour le contenu classifié, URL signées courtes), charge média malveillante (analyse antivirale du media store), injection de prompt dans la transcription (contenu non fiable, outils vérifiés contre les permissions de l'appelant), récupération inter-locataires (RLS et filtres ACL de l'index), attribution de locuteur synthétique (jamais affichée comme vérifiée), écriture CRM non autorisée (approbation obligatoire).
  • Audit en ajout seul de chaque décision et de chaque effet de bord ; DLP mask sur les exports ; legal hold et rétention appliqués par la politique et par les travaux de suppression.

Alternatives étudiées​

  • Modèles STT et de diarisation embarqués dans le produit : écarté (ADR-0177) ; le Control Plane les fournit déjà avec la DLP, les quotas et l'audit, et une seconde copie des poids doublerait la surface de maintenance et de licence.
  • Bot universel rejoignant toute visioconférence par un navigateur sans tête : écarté ; il contourne les cadres approuvés des fournisseurs et leurs politiques d'enregistrement ; le produit livre un bot natif LiveKit, l'import des enregistrements cloud et la capture navigateur, et affiche blocked là où aucun cadre approuvé n'existe.
  • Grafana, Loki et Tempo pour l'observabilité : refusés, licence AGPL (ADR-0101) ; Prometheus, Alloy, OpenSearch, Jaeger et Opik sont utilisés.
  • Second index sémantique propre au produit : écarté, Qdrant/Cognee via le Control Plane restent la seule source avec filtres ACL.
  • Shell frontend partagé de l'ADR-0180 : écarté, un studio de transcription synchronisé au média ne se décrit pas par un manifeste piloté par le shell.

Questions ouvertes​

  • Application Zoom Meeting SDK : nécessaire pour un bot live Zoom, non livrée ; décision du client sur la publication d'une application dans son compte Zoom.
  • Enregistrement d'un bot Teams (Azure Bot Service, permissions d'application Graph) : hors périmètre tant que le locataire n'accorde pas les permissions ; seul l'import des enregistrements et transcriptions Graph est prévu.
  • Poids pyannote soumis à acceptation (gated) : le client doit les accepter sur son compte Hugging Face et configurer EAI_HF_TOKEN sur le Control Plane ; sans cela la diarisation est indisponible et l'attribution par piste LiveKit reste la seule attribution vérifiée.
  • Jibri pour Jitsi : capture possible uniquement si le client exploite Jibri et expose le répertoire ou le webhook de finalisation ; sinon dépôt manuel.

Liens​

  • Brief : agent_uses_cases/tel_note_meeting/02_NAVIN_AGENT_MEETING_EQUIVALENT_LEEXI.md (sections 2, 7, 19, 26)
  • Conventions : navin-enterprise-meeting/CONVENTIONS.md
  • Politiques : deploy/policies/openfga/products/meetings.fga, deploy/policies/opa/meetings.rego
  • Carte : navin-manager/agent-templates/navin-meeting-agent.yaml
  • Version anglaise : docs/architecture/ADRs/en/ADR-0206-navin-enterprise-meeting-agent.md