Files
ObsiGate/docs/Assistant-V2/assistant-v21-phase-2-temps-reel.md
T
bruno f783394f09
CI / lint (push) Successful in 3m17s
CI / security (push) Failing after 1m51s
CI / test (push) Successful in 5m14s
CI / build (push) Successful in 1m50s
CI / e2e (push) Successful in 18m18s
feat: intégration TikTak #197-200 + scoped tokens, webhooks filtrés, listes mtime/size ; fix e2e-server BUG-112
2026-10-14 11:42:53 -04:00

25 KiB
Raw Permalink Blame History

Assistant V2.1 ObsiGate — Phase 2 : Le temps réel (agent programmé, consolidation, rappels, automatisations, rituels)

Champ Valeur
Phase 2 sur 5 — l'assistant devient proactif, dans un budget
Document parent ASSISTANT-V2.1.md — en particulier §9.5–9.6 (consolidation), §12 (automatisations), §13.3 (rituels), §14.4 (budget d'interruption)
Version 1.0 — 9 octobre 2026
Auteur Spark, pour Bruno
Statut Prêt à implémenter
Tranches #200 (agent programmé + briefing), #194 (consolidation nocturne), #199 (rappels), #208 (automatisations événementielles & recettes), #214 (rituels & habitudes)
Effort estimé 14–19 jours
Prérequis Phase 0 (runs #206, politiques #213, mémoire #192/#193) et phase 1 (tâches #202, plan #204, inbox #205, file d'approbations #203) terminées
Dépendances #200 ← #192, #206 ; #194 ← #200, #193 ; #199 ← #200, #202 ; #208 ← #206, #202 ; #214 ← #204, #208
Débloque Phase 3 (les automatisations et le briefing consommeront les événements connecteurs), phase 4 (la proactivité #201 s'appuie sur les détecteurs et le budget livrés ici)

Résultat visible à la fin de cette phase. L'assistant travaille quand Bruno n'est pas là — de façon bornée, journalisée et révocable. Le scheduler sait lancer l'agent (agent_prompt à whitelist) : le briefing du matin devient l'amorce rédigée du plan du jour. Chaque nuit, la consolidation extrait faits, entités et contradictions des conversations et des notes, en cartes validables, sous budget de tokens. Les rappels sont de vrais objets livrés à heure dite (push, canaux, escalade, snooze compté) et peuvent être contextuels (« quand j'ouvre le projet X »). Les automatisations réagissent aux événements du vault et des tâches, avec dry-run et circuit-breaker. Et les rituels — matin, soir, semaine — tiennent la boucle : rien ne glisse en silence d'un jour à l'autre.


Table des matières

  1. Objectif et principe directeur
  2. Périmètre
  3. État d'entrée
  4. Modèle de données
  5. Tickets de travail
  6. API livrée par la phase
  7. Comportements détaillés
  8. Tests et golden tasks
  9. Critères d'acceptation de la phase
  10. Risques spécifiques et vigilance
  11. Ordre d'exécution
  12. Définition de « terminé »

1. Objectif et principe directeur

Le principe : l'autonomie se prouve en journal, pas en promesse. Tout ce que la phase ajoute d'automatique — un run planifié, une consolidation, une automatisation — est un run ordinaire de la phase 0 : visible, plafonné, reprenable, annulable, et soumis au moteur de politiques et au budget d'interruption (P15).

Corollaires :

  • Pas de magie par défaut. Chaque tâche planifiée et chaque automatisation est créée par Bruno ou proposée en carte puis validée ; l'installation ne crée que le briefing-plan (désactivable) et la consolidation (désactivable).
  • Les actions primitives d'abord. Une automatisation qui peut s'exprimer sans LLM (créer une tâche, notifier, classer) ne doit pas appeler de LLM : c'est plus fiable, gratuit et auditable.
  • L'échec est un état, pas un silence. Échec de run planifié = journal + notification de synthèse au briefing suivant ; échecs répétés d'une automatisation = suspension + insight, jamais une boucle d'erreurs.

2. Périmètre

2.1 Inclus

  • #200 : action scheduler agent_prompt (whitelist de capacités V2 renforcée : READ libre ; WRITE restreint aux chemins déclarés, défaut 99_Assistant/** ; DANGEROUS et écritures connecteurs interdits ; allowed_extra_tools explicite), plafonds (8 itérations par défaut, budget tokens par tâche), runs origin='scheduled' unifiés au modèle de la phase 0 (reprise des runs planifiés interrompus), briefing du matin comme amorce rédactionnelle du plan (skill /brief), tâches intégrées déclarées dans l'UI avec leurs capacités.
  • #194 : consolidation nocturne complète (parent §9.5) : collecte incrémentale (sessions, notes, tâches clôturées, revues), extraction LLM sous budget dur, résolution d'entités, contradictions explicites vers la file d'approbations, candidats connecteurs en réglage off|candidats (mécanisme livré ; les sources arrivent en phase 3), journal dans Journal.md.
  • #199 : action scheduler reminder et livraison multi-canal (Web Push + notify.broadcast existant), outils reminder_*, RRULE (moteur de la phase 1), rattachement aux tâches (une tâche due peut être livrée comme rappel — §7.2 du document phase 1), snooze compté, escalade optionnelle, section Rappels d'Aujourd'hui.
  • #208 : bus d'événements interne (vault, tâches, inbox, runs, horloge, webhooks entrants), moteur d'automatisations (note markdown à frontmatter structuré : déclencheur → conditions → actions primitives ou agent_prompt borné), gardes (frequence_max obligatoire, dédup par clé d'événement, profondeur d'enchaînement ≤ 2, circuit-breaker à 3 échecs), dry-run sur événements passés, scheduler amendé (cron complet, politique de rattrapage misfire, idempotence par occurrence), activation des rappels contextuels de #199 sur le bus, catalogue initial de recettes (annexe D du parent) en modèles.
  • #214 : rituels livrés comme recettes assemblées sur l'existant (briefing/plan du matin, revue du soir à reports explicites, revue de semaine, inbox zéro) ; habitudes = tâches récurrentes rattachées à un objectif avec compteur de série ; série cassée → au plus un insight hebdomadaire.

2.2 Exclu (phases ultérieures)

  • Les événements connector.* : le bus les déclare dès cette phase (schéma d'événement), le moteur de sync qui les émet est en phase 3. Aucune automatisation livrée ne dépend d'un connecteur.
  • Les détecteurs d'insights complets (#201, phase 4) : la phase livre les données (snooze compté, reports comptés, séries) et le canal Insights.md ; les détecteurs métier sont en phase 4.
  • Les engagements (#211, phase 4) : la consolidation peut déjà émettre des faits open_loop (V2) ; leur promotion en objets suivis est en phase 4.

3. État d'entrée

Élément Usage en phase 2
Scheduler #170 (interval_hours/daily_time/once_at, actions primitives) Socle étendu, jamais remplacé ; les tâches existantes des utilisateurs continuent de fonctionner
Runs et politiques (phase 0) Tout travail automatique est un run sous politique ; les plafonds par tâche s'ajoutent aux plafonds par run
Tâches RRULE, plan, revues (phase 1) Les rappels s'appuient sur l'index des tâches ; le briefing-plan consomme le plan ; les rituels appellent plan_review
File d'approbations (phase 1) Contradictions de consolidation, propositions d'automatisations et faits pending y convergent
Notifications #168 + Web Push #67 Bras de livraison des rappels et des alertes, sous budget d'interruption

4. Modèle de données

Pas de nouvelle base : extensions de data/assistant.sqlite3 et du fichier des tâches planifiées existant.

CREATE TABLE automation_runs (          -- journal d'exécution des automatisations
  id TEXT PRIMARY KEY, automation_id TEXT NOT NULL,  -- note d'automatisation
  event_key TEXT NOT NULL,              -- clé de déduplication de l'événement
  run_id TEXT,                          -- run phase 0 associé (si agent_prompt)
  outcome TEXT NOT NULL,                -- fired|skipped_freq|skipped_cond|failed|dry_run
  created_at TEXT NOT NULL
);
CREATE UNIQUE INDEX idx_autorun_event ON automation_runs(automation_id, event_key);
CREATE TABLE event_log (                -- journal échantillonné du bus
  id TEXT PRIMARY KEY, type TEXT NOT NULL, payload_summary TEXT,
  created_at TEXT NOT NULL
);

Les automatisations elles-mêmes sont des notes (99_Assistant/Automatisations/<nom>.md, frontmatter du parent §12.2) : pas de table de définition, un index en mémoire reconstruit par le watcher, comme les tâches. Les compteurs du circuit-breaker vivent en base (état, pas contenu).

Amendement du scheduler : chaque tâche planifiée gagne cron_expr (optionnel), misfire (skip|run_once|run_all, défaut run_once pour les tâches agent_prompt et reminder, skip sinon) et idempotency_scope (tâche + occurrence) ; l'ancien format reste lisible (migration douce au chargement, réécriture au premier enregistrement).

5. Tickets de travail

Convention : chaque ticket est indépendamment testable ; « Fichiers » donne les points d'ancrage d'après la V2.1 — à confirmer contre le code réel au démarrage du ticket.

Agent programmé & briefing — #200

P2-T01 — Action agent_prompt dans le scheduler. Fichiers : backend/scheduler.py, backend/tools/scheduled.py. Travail : nouveau type d'action lançant run_agent avec un prompt, une whitelist de capacités (défaut du parent §12.2 : READ libre, WRITE 99_Assistant/**, DANGEROUS et écritures externes interdits, allowed_extra_tools explicite par tâche), plafonds propres (itérations, tokens) ; la tâche déclare ses capacités dans l'UI des tâches planifiées (liste lisible, pas du JSON brut). Acceptation : une tâche agent_prompt tentant d'écrire hors de son périmètre échoue proprement, l'échec est journalisé et visible ; aucune tâche existante (#170) n'est affectée.

P2-T02 — Unification aux runs et reprise. Travail : chaque exécution planifiée crée un agent_runs (origin='scheduled', origin_ref = tâche) ; un run planifié interrompu par redémarrage est repris selon les règles de la phase 0 (steps WRITE incertaines → approbation) ou marqué échoué avec motif, selon sa politique de rattrapage ; last_run_at/last_error persistés et broadcast schedule_failure existant conservé. Acceptation : tuer le conteneur pendant le briefing puis le relancer donne un run unique, repris ou échoué explicitement — jamais un briefing en double ni un silence.

P2-T03 — Briefing-plan du matin. Travail : la tâche intégrée de génération de plan (phase 1, P1-T14) est rebranchée : le plan déterministe reste produit par le moteur #204 ; #200 ajoute l'amorce rédactionnelle (skill /brief : synthèse du plan, faits pending du jour, points d'attention) écrite dans Briefings/YYYY-MM-DD.md et notifiée selon les canaux et le budget ; en cas d'agenda externe absent, le briefing le dit (données du vault uniquement). Acceptation : à l'heure configurée, Briefings/ contient la note du jour citant ses sources ; /brief régénère à la demande sans dupliquer le plan.

Consolidation nocturne — #194

P2-T04 — Collecte incrémentale. Fichiers : backend/memory/consolidator.py. Travail : sessions créées/modifiées depuis le dernier run + notes modifiées (index/watcher, plafonds 200 fichiers × 30 Ko) + tâches clôturées et revues de la période ; redact_file_content() systématique avant tout envoi LLM ; watermark persisté dans consolidation_runs (un run interrompu reprend sa fenêtre, pas plus). Acceptation : un second run sans nouveauté consomme zéro token LLM ; le watermark avance seulement sur succès de l'étape d'écriture.

P2-T05 — Extraction et réconciliation. Travail : prompt d'extraction du parent (annexe B amendée : procedure, entité principale, marqueur contradiction) ; validation Pydantic stricte de la sortie (rejet des faits non sourcés) ; étape déterministe de résolution d'entités (liaison ou proposition) ; réconciliation : supersede bi-temporel, contradictions avec decision/procedure → carte contradiction dans la file unifiée (jamais de supersede automatique), dossiers sensibles → pending. Acceptation : G5 passe (un secret présent dans les notes n'est jamais extrait ; un fait santé est en pending) ; une contradiction produit une carte avec les deux sources citées.

P2-T06 — Écriture, cartes et budget. Travail : écriture des faits + miroir avec protection de course (hash comparé avant et après l'appel LLM ; section éditée entre-temps = écriture abandonnée pour cette section, replanifiée) ; faits pending → file d'approbations ; budget dur OBSIGATE_CONSOLIDATION_MAX_TOKENS (arrêt propre, watermark partiel journalisé) ; compte rendu dans Journal.md ; réglage candidats connecteurs (§9.6 du parent) présent, défaut off, sans source cette phase. Acceptation : une nuit de test sur le vault fixture produit ≥ 1 fait utile et respecte le budget ; éditer Profil.md pendant le run ne perd ni l'édition ni le fait.

P2-T07 — Déclenchement. Travail : tâche intégrée daily_time 23:30 (configurable, OBSIGATE_TZ) via #200 (whitelist memory.*) ; skill /consolider à la demande ; le run apparaît dans le centre de contrôle avec ses compteurs (faits ajoutés/validés/rejetés — métriques #212). Acceptation : la consolidation est visible, désactivable, et son coût de la nuit est affiché le lendemain dans Aujourd'hui (activité de l'assistant).

Rappels — #199

P2-T08 — Action reminder et outils. Fichiers : backend/tools/reminders.py, scheduler. Travail : action typée {user_id, text, deliver:[channels], rrule?} ; outils reminder_create (dates relatives résolues côté serveur et confirmées dans la carte — « dans 3 semaines » affiche la date absolue avant création), reminder_list, reminder_snooze (compteur persisté), reminder_cancel ; les rappels sont des tâches de l'index phase 1 vues par le scheduler de livraison (§7.2). Acceptation : G1 passe (« rappelle-moi d'appeler le dentiste dans 3 semaines » → livraison à la bonne date, heure murale, fuseau Toronto).

P2-T09 — Livraison, escalade, section Rappels. Travail : à l'échéance : Web Push + notify.broadcast sur les canaux choisis + trace dans l'historique de Rappels.md (vue générée) ; acquittement (depuis la notification, Aujourd'hui ou en conversation) ; escalade optionnelle des rappels critique (canal externe si non acquitté après N minutes) ; les rappels dus entrent dans le compileur de contexte (section Aujourd'hui) ; snooze ≥ 3 sur le même rappel = donnée exposée aux insights (phase 4), pas de notification supplémentaire. Acceptation : un rappel non acquitté critique escalade une fois, puis s'arrête ; un rappel ordinaire n'émet qu'une livraison par occurrence (idempotence du scheduler amendé, P2-T13).

Automatisations événementielles — #208

P2-T10 — Bus d'événements. Fichiers : backend/automations/bus.py. Travail : émission depuis le watcher (vault.file.*), l'index des tâches (task.created|completed|overdue), l'inbox, les runs (run.finished), l'horloge (schedule.tick), les webhooks entrants existants ; schéma connector.object.* déclaré (aucun émetteur cette phase) ; journal échantillonné event_log ; bus en mémoire, aucun broker externe (P1). Acceptation : chaque type d'événement déclaré a au moins un test d'émission ; un abonné lent ne bloque pas l'émetteur (file bornée, perte journalisée).

P2-T11 — Moteur d'automatisations. Fichiers : backend/automations/engine.py. Travail : chargement des notes Automatisations/*.md (frontmatter validé, erreurs de schéma = automatisation désactivée + carte explicative, jamais de crash) ; évaluation déclencheur → conditions déterministes → actions : primitives (task_create, reminder_create, create_file/append_to_file dans le périmètre, notify, classement inbox) ou agent_prompt (via #200, whitelist propre à l'automatisation) ; chaque exécution est journalisée (automation_runs) et, si LLM, un run phase 0. Acceptation : l'exemple du parent §12.2 (forme sans connecteur : « note modifiée dans Projets/ → tâche de relecture ») fonctionne de bout en bout ; une automatisation mal formée est signalée, pas silencieusement ignorée.

P2-T12 — Gardes : fréquence, dédup, circuit-breaker, dry-run. Travail : frequence_max obligatoire (refus d'activation sans elle) ; dédup par clé d'événement (index unique §4) ; profondeur d'enchaînement ≤ 2 (automation → run → automation au-delà = refus journalisé) ; 3 échecs consécutifs → suspension + insight dans Insights.md ; dry-run : rejouer les événements des 7 derniers jours et afficher ce qui aurait été fait, sans aucun effet. Acceptation : G8 passe (déclencheur répété 5 fois le même jour avec frequence_max: 1/jour → 1 exécution, 4 ignorées journalisées) ; le dry-run ne crée ni tâche ni notification (vérifié aux stores).

P2-T13 — Scheduler amendé. Travail : expressions cron complètes en plus des modes existants ; politique misfire (§4) ; idempotence par (tâche, occurrence) ; file des échecs avec rejeu manuel depuis les Configurations ; ancrage heure murale zoneinfo pour les horaires quotidiens. Acceptation : une occurrence ratée pendant un arrêt du conteneur suit sa politique au redémarrage (test par horloge simulée) ; aucune occurrence n'est livrée deux fois.

P2-T14 — Rappels contextuels et recettes initiales. Travail : déclencheurs d'ouverture (note/projet ouvert → rappels ctx correspondants proposés dans le panneau, pas de push) rattachés au bus ; publication des recettes de l'annexe D du parent livrables sans connecteur (briefing-plan, revues, veille de page par fetch_url + diff, anniversaires depuis les entités connues, entretien récurrent) comme modèles d'automatisations/skills pré-remplis, activables un par un. Acceptation : la recette « veille de page » détecte un changement et produit une note + un item d'activité, sans notification hors budget.

Rituels & habitudes — #214

P2-T15 — Rituels assemblés. Travail : les rituels sont des recettes (pas un moteur nouveau) : matin = briefing-plan (P2-T03) ; soir = revue du jour (plan_review) avec reports explicites des tâches non faites (nouvelle date choisie ou retour au projet — l'assistant propose, Bruno tranche en un écran) ; semaine = revue de semaine (phase 1) + focus proposés (3 projets max) ; inbox zéro = triage en lot en fin de journée ; chaque rituel est activable/désactivable séparément, à heure configurable. Acceptation : une tâche non faite trois soirs de suite n'a jamais glissé silencieusement : chaque report est daté et motivé dans l'historique de la tâche.

P2-T16 — Habitudes et séries. Travail : une habitude = tâche récurrente RRULE liée à un objectif (phase 1) ; série calculée par l'index (occurrences faites / attendues, fenêtre glissante) ; affichage dans la revue de semaine et la note de l'objectif ; série cassée → au plus un insight hebdomadaire regroupé (P15), jamais de rappel quotidien de culpabilisation. Acceptation : la série d'une habitude « 3×/semaine » est calculée correctement sur 4 semaines de fixture, semaines incomplètes (en cours) exclues du jugement.

Finitions

P2-T17 — Budget d'interruption : mécanique. Travail : compteur quotidien des notifications sortantes de l'assistant (briefing = 1 ; alertes jusqu'à OBSIGATE_NOTIFY_DAILY_BUDGET, défaut 3 ; rappels demandés par Bruno hors budget ; critique peut dépasser, 1/jour max) ; sévérités critique|normale|info (l'info attend la revue du soir) ; chaque notification porte son pourquoi et le lien de l'objet ; compteur visible au centre de contrôle. Les détecteurs qui consommeront ce budget sont en phase 4 (#201) ; la mécanique s'applique dès cette phase aux rappels et aux échecs de runs planifiés. Acceptation : un scénario générant 6 alertes normales en un jour en livre 3 et range les autres dans la revue du soir (vérifié au journal).

P2-T18 — i18n, docs, guides. Travail : clés FR/EN (tâches planifiées et leurs capacités, automatisations, rappels, rituels) ; fiches docs/features/ pour #200, #194, #199, #208, #214 ; guide « Automatisations et rituels » + pas-à-pas de création d'une automatisation ; CHANGELOG + ROADMAP. Acceptation : DoD du §12 vérifiée point par point.

6. API livrée par la phase

Route Rôle Ticket
GET/POST/PATCH /api/scheduler/tasks (étendu) Tâches planifiées : agent_prompt, cron, misfire, capacités affichées P2-T01/T13
POST /api/scheduler/tasks/{id}/run (existant) Exécution manuelle — produit un run unifié P2-T02
GET /api/automations · `POST /api/automations/{id}/dry-run enable disable`
GET/POST /api/reminders · `POST /api/reminders/{id}/snooze cancel ack`
GET /api/memory/consolidation Derniers runs de consolidation et leurs compteurs P2-T06

7. Comportements détaillés

7.1 Une tâche planifiée se relit comme un contrat

L'UI des tâches planifiées affiche pour chaque tâche agent_prompt : le prompt, la whitelist effective, les plafonds, le dernier run (lien) et son résultat. Ce qui n'est pas affiché n'est pas autorisé : la whitelist par défaut ne s'étend que par allowed_extra_tools explicite, tracé dans l'audit.

7.2 Rappel = tâche + livraison

Il n'y a pas de second store de rappels : un rappel est une tâche de l'index portant ctx: rappel ou créée par reminder_create, à laquelle le scheduler rattache une livraison (canaux, acquittement, snooze, escalade). Rappels.md est une vue générée de l'index. Compléter la tâche acquitte le rappel ; snoozer décale la tâche (historique conservé).

7.3 Le dry-run est un droit, pas une option cachée

Toute automatisation peut être dry-runée avant activation et à tout moment ensuite, sur une fenêtre choisie. Le résultat du dry-run fait partie de son journal : une automatisation jamais dry-runée porte un badge « jamais testée » dans les Configurations.

7.4 Consolidation et vie privée

La consolidation ne lit que le vault et les conversations de l'utilisateur propriétaire (jamais inter-utilisateurs) ; les dossiers sensibles configurables forcent pending quelle que soit la confiance extraite ; les compteurs de validation (faits acceptés/rejetés) alimentent la métrique de dégradation du consolidateur (#212 : un taux de rejet en hausse durable est un signal, affiché au centre de contrôle).

8. Tests et golden tasks

  • Unitaires : whitelist agent_prompt (tentatives d'évasion), watermark de consolidation, gardes d'automatisation (fréquence, dédup, profondeur), cron + misfire par horloge simulée, séries d'habitudes.
  • Intégration : nuit de consolidation complète sur fixture ; briefing après redémarrage ; rappel critique avec escalade ; automatisation de veille avec changement de page simulé.
  • Golden tasks de la phase : G1 (rappel à 3 semaines), G5 (secret jamais extrait, fait santé pending), G8 (frequence_max) — définitions au parent §16.1.

9. Critères d'acceptation de la phase

  1. Le briefing du matin paraît à l'heure, cite ses sources, et un redémarrage du conteneur ne produit ni doublon ni silence.
  2. Une nuit de consolidation produit des faits et des cartes traçables, respecte son budget dur, et ne perd aucune édition humaine concurrente.
  3. « Dans 3 semaines » devient un rappel livré à la bonne date ; le snooze répété est compté et visible.
  4. Une automatisation se dry-rune sans effet, s'active, respecte sa frequence_max, et se suspend proprement après 3 échecs.
  5. Aucune notification de la phase ne sort sans pourquoi ni lien, et le budget quotidien est tenu et affiché.

10. Risques spécifiques et vigilance

Risque Vigilance
agent_prompt devient un cheval de Troie de périmètre Whitelist par tâche affichée comme contrat (§7.1) ; toute extension est un événement d'audit ; DANGEROUS structurellement absent des whitelists
La consolidation dégrade la mémoire en silence Compteurs de validation suivis (#212) ; bouton « relire le Journal » dans Aujourd'hui ; possibilité de suspendre la consolidation sans perdre les faits
Les automatisations notifient trop (mort par mille alertes) Budget d'interruption dès cette phase (P2-T17), sévérité info rangée en revue, frequence_max obligatoire
Dérive horaire (DST) sur rappels et rituels Ancrage heure murale partout ; tests d'horloge sur les deux changements d'heure de America/Toronto

11. Ordre d'exécution

P2-T01 → T02 → T03          (#200 — le briefing rebranche la tâche intégrée de la phase 1)
P2-T04 → T05 → T06 → T07    (#194 — après T01 : la consolidation est une tâche agent_prompt)
P2-T13 (scheduler amendé, tôt : il sert T08 et T11)
P2-T08 → T09                (#199)
P2-T10 → T11 → T12 → T14    (#208 — T14 après T09 pour les rappels contextuels)
P2-T15 → T16                (#214 — après T03, T11 et le plan de la phase 1)
P2-T17 (budget — avant T09/T14 en pratique) → P2-T18 (clôture)

12. Définition de « terminé »

DoD du document de phase 0 §12, inchangée, plus : les golden tasks G1, G5 et G8 vertes en CI ; chaque tâche planifiée et chaque automatisation livrée affiche son contrat (capacités, plafonds, budget) dans l'UI.