Files
ObsiGate/docs/Assistant-V2/assistant-v21-phase-1-le-travail.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 Blame History

Assistant V2.1 ObsiGate — Phase 1 : Le travail (tâches, Aujourd'hui, planification, capture)

Champ Valeur
Phase 1 sur 5 — le premier jalon « assistant personnel »
Document parent ASSISTANT-V2.1.md — en particulier §6 (tâches), §7 (planification), §8 (capture), §14 (UX)
Version 1.0 — 9 octobre 2026
Auteur Spark, pour Bruno
Statut Prêt à implémenter
Tranches #202 (tâches, projets, objectifs), #203 (vue Aujourd'hui, file d'approbations unifiée, centre de contrôle), #204 (moteur de planification), #205 (capture universelle & Inbox)
Effort estimé 14–18 jours
Prérequis Phase 0 terminée : mémoire (#192/#193), politiques (#213), runs persistants et niveaux d'autonomie (#206)
Dépendances #202 ← #193 ; #203 ← #202, #206 ; #204 ← #202 ; #205 ← #202. Pas de dépendance à #200 : voir §7.1 pour la résolution explicite
Débloque Phase 2 (rappels liés aux tâches, revues ritualisées, briefing-plan), phase 4 (engagements rattachés aux tâches et aux personnes)

Résultat visible à la fin de cette phase. L'assistant planifie et agit sur le vault sans aucun connecteur. Les tâches vivent dans les notes (checklists enrichies), indexées et interrogeables ; un projet sans prochaine action se voit. Chaque matin, Bruno peut demander son plan du jour : agenda du vault + tâches dues + capacité déclarée → proposition en blocs de temps qui signale la surcharge au lieu de la cacher, négociable en conversation. L'écran Aujourd'hui montre le plan, les priorités, la file unique de tout ce qui attend sa décision, et l'activité de l'assistant. Et tout ce qui lui passe par la tête se capture en 5 secondes (panneau, mobile, voix) dans une Inbox que l'assistant trie en propositions validables.


Table des matières

  1. Objectif et principe directeur
  2. Périmètre
  3. État d'entrée — ce que la phase 0 a livré
  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 : le travail est un objet, pas un texte (P10). À la fin de la phase, rien d'important pour Bruno n'existe seulement « dans une conversation » ou « quelque part dans une note » : c'est une tâche datée, un projet avec une prochaine action, ou un item d'inbox en attente de tri.

Corollaires :

  • Markdown d'abord, comme la mémoire. La tâche vit sur sa ligne, dans la note du projet ; l'index SQLite est reconstructible et tout désaccord se résout en faveur de la note.
  • Le plan propose, il n'ordonne pas. Le moteur calcule (déterministe), le modèle rédige et négocie ; la validation est humaine (ou déléguée bornée, phase 0).
  • La surcharge se dit. Si les tâches retenues dépassent la capacité, le plan le signale et propose des reports explicites. Un plan irréaliste est un défaut du système.
  • Une seule file de décisions. Faits pending, plans, triages : tout passe par la même file (#203), pour que « ce que l'assistant attend de moi » tienne en un écran et moins de 5 minutes par jour.

2. Périmètre

2.1 Inclus

  • #202 : syntaxe de tâche (états, attributs [due::] [pri::] [est::] [ctx::] [energy::] [every::]), parseur et réécriture de lignes, index data/tasks.sqlite3 maintenu par le watcher, projets et objectifs par frontmatter, récurrence RRULE (sous-ensemble RFC 5545), outils task.*/project.*/goal_review, API tâches.
  • #203 : GET /api/today et la vue Aujourd'hui (plan, priorités, file de décisions, inbox, activité) ; file d'approbations unifiée approvals (migration des cartes mémoire de la phase 0) ; centre de contrôle v1 (runs, délégations, budgets, reconstruction d'index).
  • #204 : moteur de planification déterministe (scoring explicable, capacité et créneaux protégés tirés du profil), plan du jour en note Plans/YYYY-MM-DD.md + objet plan, time blocking dans les trous d'agenda, négociation par plan_update, replanification du reste de journée, agrégats de revue (jour/semaine) — le plan automatique du matin est livré comme tâche intégrée typée du scheduler (§7.1), la généralisation agent_prompt restant en phase 2.
  • #205 : Inbox (store, API, outil inbox_add), canaux de capture (panneau ⚡, préfixe + au chat, Web Share Target PWA, API/MCP), triage assisté par cartes (tâche/note/rappel/fait candidat/événement/à jeter), file hors-ligne rejouée avec horodatage de capture.

2.2 Exclu (phases ultérieures)

  • Les rappels comme objets livrés à heure dite (#199, phase 2) : le triage peut proposer un rappel, sa création effective attend #199 ; en phase 1, la proposition est convertie en tâche due datée (comportement documenté dans l'UI de la carte).
  • Le briefing (#200, phase 2) et les rituels complets (#214, phase 2) : la phase livre le plan et les données de revue ; leur mise en rituel automatique est en phase 2.
  • Tout agenda externe : l'« agenda » de la phase = événements notés dans le vault (notes datées, section Temps du profil) ; l'écriture des blocs dans Google/Outlook arrive en phase 3 avec les connecteurs. Les blocs du plan vivent dans la note du plan.
  • La transcription vocale (#209, phase 4) : la capture voix de la phase utilise la dictée du navigateur quand elle existe, sinon un texte saisi.

3. État d'entrée — ce que la phase 0 a livré

Élément Usage en phase 1
Runs persistants, plans, approbations par run (#206) Le triage, la génération de plan et ses ajustements sont des runs ; la file d'approbations consomme les demandes d'approbation des runs
Moteur de politiques (#213) Toute création de tâche/note depuis l'inbox ou un plan passe par la politique (provenance incluse)
Mémoire et compileur de contexte (#192) Le plan consomme capacité et créneaux protégés depuis le profil ; le compileur reçoit la section « Aujourd'hui » (plan résumé, tâches dues)
Miroir à balises gérées (#193) Même patron pour Plans/, Taches.md et les sections gérées des notes projets
Watcher et index du vault Source des événements de re-parse des tâches

4. Modèle de données

Repris du parent : table tasks (§6.1 — id ancré, états, projet/objectif, échéances, priorité, estimation, contexte, énergie, rrule, waiting_on, source), table inbox_items (§8.2). Ajouts de la phase :

CREATE TABLE plans (
  id TEXT PRIMARY KEY, user_id TEXT NOT NULL,
  date TEXT NOT NULL,                    -- jour local du plan
  status TEXT NOT NULL DEFAULT 'proposed'  -- proposed|validated|in_progress|closed
    CHECK (status IN ('proposed','validated','in_progress','closed')),
  capacity_min INTEGER NOT NULL,         -- capacité retenue pour ce jour
  blocks_json TEXT,                      -- blocs : tâche/événement, début, fin, source
  overload_json TEXT,                    -- surcharge calculée + reports proposés
  note_path TEXT,                        -- 99_Assistant/Plans/YYYY-MM-DD.md
  created_at TEXT NOT NULL, updated_at TEXT NOT NULL
);
CREATE TABLE approvals (
  id TEXT PRIMARY KEY, user_id TEXT NOT NULL,
  type TEXT NOT NULL,        -- fait|plan|envoi|action_write|action_dangerous|
                             -- triage|contradiction|delegation_review
  run_id TEXT,               -- run demandeur (nullable pour les cartes mémoire)
  payload_json TEXT NOT NULL,          -- ce qui est à décider, affichable tel quel
  status TEXT NOT NULL DEFAULT 'pending'  -- pending|approved|rejected|expired
    CHECK (status IN ('pending','approved','rejected','expired')),
  created_at TEXT NOT NULL, decided_at TEXT, expires_at TEXT
);
CREATE INDEX idx_approvals_pending ON approvals(user_id, status, created_at);

approvals vit dans data/assistant.sqlite3 (créé en phase 0). Une approbation périmée ne s'exécute jamais : à l'expiration, le run demandeur est notifié et l'action associée est abandonnée (journalisé).

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.

Tâches & projets — #202

P1-T01 — Syntaxe et parseur de tâches. Fichiers : nouveau backend/tasks/model.py. Travail : grammaire des états ([ ] [/] [x] [-] [!] + motif « bloqué : » en sous-ligne) et des attributs entre crochets (tous optionnels, ordre libre, texte libre préservé) ; parse d'un fichier markdown → tâches avec position (ligne) ; réécriture d'une ligne à l'identique hors la modification demandée (aucune reformatage parasite) ; ancrage t-<uuid4> en commentaire HTML discret seulement pour les tâches référencées (rappel, run, plan). Acceptation : aller-retour parse → réécriture sans changement = fichier identique au caractère près ; les checklists Obsidian existantes du vault de test sont lues sans perte.

P1-T02 — Index des tâches et watcher. Fichiers : backend/tasks/store.py, data/tasks.sqlite3, branchement au watcher existant. Travail : DDL du parent §6.1 ; re-parse incrémental par fichier modifié ; reconstruction complète à la demande (bouton centre de contrôle) et au démarrage si l'index est absent/corrompu ; le désaccord se résout en faveur de la note. Acceptation : créer/modifier/cocher une tâche dans l'éditeur met l'index à jour en < 2 s ; supprimer l'index et redémarrer le reconstruit à l'identique.

P1-T03 — Projets et objectifs. Travail : détection par frontmatter (obsigate: projet|objectif) ou dossier projets configurable ; état du projet (actif/pause/terminé/archivé), prochaine action = première tâche ouverte liée ; calcul « projet sans prochaine action » exposé à l'index et à l'API (le détecteur d'insight est en phase 4, la donnée est ici) ; objectifs : horizon, mesure, projets liés. Acceptation : un projet actif sans tâche ouverte est retourné par project_status avec le drapeau no_next_action = true.

P1-T04 — Récurrence RRULE. Fichiers : backend/tasks/rrule.py (stdlib + zoneinfo, sous-ensemble RFC 5545 : FREQ, INTERVAL, BYDAY, BYMONTHDAY, COUNT, UNTIL). Travail : ancrage à l'heure murale dans OBSIGATE_TZ (jamais un timestamp UTC figé) ; à la complétion d'une occurrence, création de la suivante selon le mode (série/instance) ; dates de fin respectées. Acceptation : « tous les mar/jeu pendant 8 semaines » produit exactement 16 occurrences ; le passage à l'heure d'hiver ne décale aucune heure murale (tests sur America/Toronto).

P1-T05 — Outils tâches et API. Fichiers : backend/tools/tasks.py, backend/routers/tasks.py. Travail : task_list (filtres today/overdue/project/context/waiting), task_create (note cible : note du projet, sinon 99_Assistant/Taches.md), task_update, task_complete (avec récurrence T04), project_status, goal_review ; endpoints REST miroirs + recherche plein texte sur les titres. Acceptation : une tâche créée en conversation se retrouve dans la note, dans l'index et dans la réponse de task_list(filter=today) si elle est due ce jour.

Aujourd'hui & approbations — #203

P1-T06 — Agrégat GET /api/today. Fichiers : backend/routers/today.py. Travail : assemblage lecture seule : plan du jour + capacité restante, 3 priorités, compteurs file de décisions, inbox (nombre, plus ancien), tâches dues/en retard, activité des runs (24 h), alertes (index périmé, run en échec) ; chaque section porte ses liens d'objet ; temps de réponse cible < 300 ms sur le vault de test (agrégats indexés, aucun balayage de fichiers). Acceptation : l'agrégat est cohérent avec les endpoints de détail (tests croisés) ; aucune section ne fait échouer les autres (dégradation par section).

P1-T07 — Vue Aujourd'hui. Fichiers : frontend (SPA), patron de la maquette du parent §14.1. Travail : sections plan/priorités/décisions/inbox/activité ; actions sur place (valider un bloc, reporter une tâche, ouvrir la file) sans quitter l'écran ; états vides honnêtes (« pas de plan : en proposer un ») ; responsive et PWA (c'est l'écran d'accueil mobile de l'assistant). Acceptation : tests JSDOM sur les sections et les actions ; l'écran reste utilisable avec zéro connecteur, zéro plan et une inbox vide.

P1-T08 — File d'approbations unifiée. Fichiers : backend/routers/approvals.py, migration des cartes mémoire. Travail : table approvals (§4) ; les cartes pending de la phase 0 (faits) sont re-présentées comme des approvals de type fait sans perte d'état ; regroupement par run et par lot (dépliable) ; expiration honorée ; historique des décisions dans l'audit ; badge de compteur partagé (Aujourd'hui, panneau, Configurations). Acceptation : un fait pending, un plan à valider et un lot de triages coexistent dans une seule file triée par ancienneté ; approuver un lot de 12 items crée 12 décisions tracées, pas une.

P1-T09 — Centre de contrôle v1. Travail : page Configurations « Assistant » : runs (liste/détail/reprise/annulation — déjà en phase 0, ici intégrés), délégations et niveaux par domaine, budgets (tokens, et compteur d'approbations du jour), santé des index (tâches, mémoire) + bouton « reconstruire l'index des tâches », liens vers les miroirs 99_Assistant/. Acceptation : chaque compteur affiché correspond à une métrique journalisée (pas d'affichage décoratif) ; la reconstruction d'index est un run visible.

Planification — #204

P1-T10 — Moteur de scoring et capacité. Fichiers : backend/tasks/planner.py. Travail : entrées déterministes (§7.1 du parent) : événements du vault, tâches dues + en retard, capacité déclarée (réglage + section « Temps » du profil : heures de focus, créneaux protégés), rituels absents cette phase ; scoring explicable (échéance > priorité > âge > lien objectif ; pénalité d'énergie incompatible, règle issue du profil uniquement) ; chaque tâche retenue ou écartée porte sa raison affichable. Acceptation : à entrées égales, plan proposé identique (déterminisme) ; la raison d'exclusion d'une tâche est consultable et correcte.

P1-T11 — Génération du plan du jour. Travail : objet plans (§4) + note 99_Assistant/Plans/YYYY-MM-DD.md à balises gérées ; time blocking dans les trous d'agenda (durée estimée, défaut 45 min marqué estimé) ; calcul de surcharge : si la somme dépasse la capacité, overload_json liste les reports proposés (jamais de compression silencieuse) ; rédaction LLM (1 appel, modèle de routage « planification ») avec citation de la source de chaque ligne. Acceptation : G2 passe (journée surchargée → surcharge signalée, reports proposés, aucun bloc inventé) ; la note du plan et l'objet plan restent synchronisés après édition des blocs gérés.

P1-T12 — Négociation et replanification. Fichiers : backend/tools/planner.py (plan_today, plan_propose, plan_update, plan_review). Travail : ajustements conversationnels (« déplace X à demain », « je n'ai que 2 h ») → réécriture de la proposition, revalidation ; replanification du reste de journée uniquement, diff lisible (« X glisse à 15 h 30, Y reporté ») ; seuil d'impact : tout report d'une tâche pri: haute+ exige validation. Acceptation : une replanification ne touche jamais un bloc passé ; le diff affiché correspond exactement aux changements appliqués à la validation.

P1-T13 — Revues : agrégats jour et semaine. Travail : plan_review(period) déterministe sans LLM : fait/pas fait/reporté (avec compteur de reports par tâche — la donnée du détecteur « reportée ≥ 3 fois » de la phase 4), projets sans prochaine action, progrès objectifs ; rédaction de la note de revue de semaine (le rituel automatisé est en phase 2, la fonction est ici, appelable à la demande et par skill /revue). Acceptation : une tâche reportée 3 fois est comptée 3 fois, avec ses dates ; la revue ne contient aucun chiffre non traçable à l'index.

P1-T14 — Déclenchement du plan sans #200. Travail : tâche intégrée typée du scheduler existant (action: plan_propose, heure configurable, défaut 07:00, politique de rattrapage simple : si l'occurrence du jour manque, proposer à la première ouverture d'Aujourd'hui) ; skill /planjour ; aucune utilisation d'agent_prompt générique (phase 2). Acceptation : à 7 h, la proposition du jour existe ; conteneur arrêté à 7 h puis rouvert à 9 h → la proposition est générée à l'ouverture, datée du jour, sans doublon.

Capture & Inbox — #205

P1-T15 — Store Inbox et outil d'ajout. Fichiers : backend/inbox/store.py, backend/tools/inbox.py, data/assistant.sqlite3. Travail : table inbox_items (parent §8.2) ; inbox_add (WRITE sans classement — la capture ne décide rien), inbox_list ; POST /api/inbox authentifié, exposé au MCP ; horodatage de capture conservé séparément de l'horodatage de synchronisation. Acceptation : un item ajouté par API, par chat et par MCP a la même forme et le même statut initial new.

P1-T16 — Canaux de capture. Travail : bouton « ⚡ Capture » du panneau (aucun appel LLM) ; préfixe + dans le chat général et le chat de fichier ; Web Share Target de la PWA (titre + URL + texte) ; bouton capture de la vue Aujourd'hui mobile ; dictée navigateur si disponible (sinon saisie texte). Acceptation : capture mobile de bout en bout en < 5 s (mesuré sur le parcours PWA) ; une capture ne déclenche aucun run LLM (vérifié au journal).

P1-T17 — Triage assisté. Fichiers : backend/tools/inbox.py (inbox_triage), prompt de triage (annexe B.1 du parent). Travail : proposition typée par item (tâche avec échéance uniquement si énoncée ou déductible d'une date explicite — aucune date inventée ; note avec dossier proposé ; rappel → tâche datée cette phase, §2.2 ; fait candidat → pipeline mémoire pending ; événement vault ; à jeter) ; présentation en cartes dans la file unifiée (type triage), validation/correction/rejet unitaire ou en lot pour les évidents ; application = un run par lot, via la politique (provenance inbox). Acceptation : G4 passe (compte rendu collé dans l'inbox → tâches datées + proposition d'engagement en cartes, rien créé sans validation) ; un item sans date explicite produit une tâche sans échéance.

P1-T18 — Hors-ligne. Travail : les captures PWA hors-ligne entrent dans la file IndexedDB existante avec leur horodatage d'origine et sont rejouées à la reconnexion ; la résolution des dates relatives (« demain ») se fait à la date de capture ; sur Tauri hors-ligne, même file locale ; le triage différé (serveur injoignable) ne perd ni ne duplique aucun item. Acceptation : capture hors-ligne puis reconnexion = un seul item, daté de la capture ; rejouer deux fois la file ne crée aucun doublon (clé d'idempotence par item).

Finitions

P1-T19 — Skills et surfaces conversationnelles. Travail : skills /planjour, /revue, /trier, /taches ; section « Aujourd'hui » du compileur de contexte (plan résumé + tâches dues, budget borné) ; libellés ai.step.* pour les outils tâches/plan/inbox. Acceptation : « qu'est-ce que j'ai aujourd'hui ? » en conversation répond depuis l'agrégat Aujourd'hui, sources citées, sans accès fichier direct.

P1-T20 — i18n, docs, guides. Travail : clés FR/EN (vue Aujourd'hui, cartes, plans, inbox) ; fiches docs/features/ pour #202–#205 ; guide utilisateur « Tâches, plan du jour et capture » ; CHANGELOG + ROADMAP. Acceptation : DoD du §12 vérifiée point par point.

6. API livrée par la phase

Route Rôle Ticket
GET /api/today Agrégat de la vue Aujourd'hui P1-T06
GET/POST/PATCH /api/tasks · /api/tasks/{id}/complete CRUD et complétion des tâches (miroir des outils) P1-T05
GET /api/projects · GET /api/projects/{id}/status Projets et leur état calculé P1-T03/T05
GET /api/plans/{date} · `POST /api/plans/{date}/propose update validate`
GET /api/approvals · POST /api/approvals/{id}/decide · POST /api/approvals/decide-batch File de décisions unifiée P1-T08
GET/POST /api/inbox · POST /api/inbox/{id}/triage Capture et triage P1-T15/T17

7. Comportements détaillés

7.1 Dépendance #204 → #200 : résolution

Le tableau des tranches du parent donnait #204 dépendant de #200 (agent_prompt), alors que l'ordre des phases place #200 en phase 2. Résolution adoptée dans les documents de phase : le plan du matin n'a pas besoin d'un prompt libre — c'est une fonction typée. La phase 1 le livre comme tâche intégrée du scheduler (P1-T14) ; la phase 2 généralise (#200 : agent_prompt arbitraire, briefing comme amorce rédactionnelle du plan) sans changer le comportement du plan. Le parent est corrigé en conséquence (§19.2 : dépendance de #204 = #202, #193).

7.2 Tâche ou rappel ?

En phase 1, il n'existe qu'un objet daté : la tâche. La carte de triage qui propose « rappel » crée une tâche due avec ctx: rappel ; en phase 2, #199 rattache la livraison (push/canaux, snooze, escalade) à ces mêmes tâches — aucune migration d'objets, un enrichissement de comportement.

7.3 Édition concurrente d'une ligne de tâche

Si la ligne d'une tâche a changé dans la note entre la lecture et la réécriture demandée par un outil (édition humaine entre-temps), l'outil refuse avec un conflit lisible et relit l'état courant — jamais d'écrasement. Le backup automatique existant couvre les écritures.

7.4 Capacité et créneaux protégés

La capacité vient d'abord du réglage, puis de la section « Temps » de Profil.md si Bruno l'édite (source user, prioritaire). Le moteur n'infère jamais une capacité depuis l'historique sans la proposer en carte (ce serait une procédure — phase 2 via la consolidation, validation humaine).

8. Tests et golden tasks

  • Unitaires : parseur (aller-retour sans perte), RRULE (16 occurrences, heure d'hiver), scoring (déterminisme, raisons), surcharge (aucune compression), approvals (expiration, lots).
  • Intégration : tâche créée par 3 surfaces → même objet ; plan généré → négocié → validé → revu ; capture hors-ligne → synchro → triage.
  • Golden tasks de la phase : G2 (surcharge), G4 (triage d'un compte rendu) — définitions au parent §16.1 ; plus deux scénarios locaux : « tâche créée en chat visible aux 3 surfaces » et « plan du matin après redémarrage » (P1-T14).

9. Critères d'acceptation de la phase

  1. Une tâche créée en conversation, dans l'éditeur ou par triage d'inbox est le même objet dans la note, l'index et Aujourd'hui.
  2. Le plan d'une journée surchargée signale la surcharge et propose des reports ; aucun bloc n'est inventé et aucune tâche n'est compressée en silence.
  3. La file de décisions contient faits, plans et triages ; le temps de décision quotidien est mesuré et affiché au centre de contrôle.
  4. Une capture mobile prend moins de 5 secondes ; une capture hors-ligne n'est ni perdue ni dupliquée.
  5. Aucun connecteur n'est requis pour l'ensemble de la phase.

10. Risques spécifiques et vigilance

Risque Vigilance
Friction de la syntaxe d'attributs dans les notes Tous les attributs sont optionnels ; une checklist ordinaire reste une tâche valide (échéance absente = jamais proposée comme « due »)
L'index et les notes divergent (édition externe, Syncthing) Reconstruction complète toujours disponible ; les conflits de ligne sont des refus lisibles (§7.3), pas des écrasements
Le plan du jour est ignoré s'il arrive trop tard Proposition à 7 h et à la première ouverture d'Aujourd'hui ; la métrique « plans validés/modifiés/ignorés » est suivie dès cette phase (#212)
La file de décisions devient un deuxième travail Lots, expiration, et métrique du temps de décision : au-delà de 5 min/jour en moyenne, c'est un signal de défaut à traiter (parent §20)

11. Ordre d'exécution

P1-T01 → T02 → T03 → T04 → T05        (#202 — T04 peut paralléliser après T01)
P1-T06 → T07 ; P1-T08 ; P1-T09        (#203 — T08 après T05, T06 après T11 pour le plan réel,
                                        mais livrable avant avec section plan vide honnête)
P1-T10 → T11 → T12 → T13 → T14        (#204)
P1-T15 → T16 → T17 → T18              (#205)
P1-T19 → T20                          (finitions)

12. Définition de « terminé »

DoD du document de phase 0 §12, inchangée, plus : les golden tasks G2 et G4 vertes en CI ; la reconstruction d'index démontre l'égalité index ↔ notes sur le vault de test.