- 21 docs/*.md: audits, design notes, deployment plans, checklists, memos - Coordination: ROLES, runbooks (DGX reboot, Lea live), patches, registre, syntheses, systemd, QG template - Handoffs: 6 Codex handoff documents + README + template
13 KiB
Cartographie — Chaîne d'apprentissage & mise en commun des connaissances (2026-06-16)
Question Dom : « Comment le savoir appris sur chaque poste est-il mutualisé dans un fonds commun unique partagé par tous les postes, et exploité vers l'autonomie ? » Méthode : graphify (graphe code 58k nodes) + 3 agents Explore + vérif code directe. Cross-checks Codex (pipeline server_v1) & Qwen (fédération/FAISS) en cours — ce doc sera enrichi. ⚠️ Verdicts = état runtime constaté ce jour (
poc-dgx@2b1743c20), pas la doc d'intention.
TL;DR (réponse directe)
Le « fonds commun → autonomie » est partiellement construit, mais les maillons clés sont soit silotés par machine, soit dormants :
- ✅ Ce qui EST déjà commun : les compétences YAML (
core/competences/) et les embeddings (CLIP→FAISS) — partagés serveur, tous postes. - ❌ Ce qui est SILOTÉ par machine (codé en dur) : le stockage workflows/sessions (
{machine_id}/) et surtout le cross-session learning qui refuse de matcher entre machines (if workflow_machine != machine_id: continue). C'est l'anti-pattern direct vs la vision. - 🌙 Ce qui est DORMANT : la fédération (
core/federation: LearningPack, GlobalFAISSIndex) — le vrai mécanisme de fonds commun — est bien conçue, globale et anonymisée (Qwen confirmé : zéro machine_id, clépack_source_hash), mais doublement inerte au runtime : (a) alimentée seulement par l'endpoint import manuel (jamais auto-déclenché) ; (b) sonsearch()n'est JAMAIS appelé (faiss_global.py:199défini, zéro consommateur actif) → index write-only, jamais consulté → contribue zéro au comportement/à l'autonomie aujourd'hui. - 🚧 Ce qui manque pour l'autonomie : la couche graphe (WorkflowGraph) EST construite en live (
finalize_session→GraphBuilder, import lazystream_processor.py:3017-3022, DBSCAN) — correction d'un faux "orphelin" — mais le graphe est siloté par machine (persisté sousworkflows/{machine_id}/) et le merge cross-session est machine-filtré. La progression Shadow→Copilot→Autonomous reste du design, pas du runtime (Shadow observe+log).
⚠️ Caveat méthodo : ce code utilise massivement des imports lazy dans les handlers/méthodes. Les verdicts "orphelin" basés sur grep d'imports top-level sont non fiables (federation ET GraphBuilder étaient ainsi faussement classés orphelins, puis confirmés WIRED). Tout "orphelin" ci-dessous non vérifié par lazy-import est à recontrôler.
→ Aujourd'hui, par défaut, chaque poste est un silo cognitif : il n'apprend pas des autres, sauf pour les compétences YAML et les embeddings centralisés.
Tableau de synthèse (WIRED ? · COMMUN/SILOTÉ)
A. Capture → construction → stockage (agent Explore #1)
| Composant | fichier:ligne | WIRED | COMMUN/SILOTÉ |
|---|---|---|---|
| TraceStreamer (tag machine_id) | agent_v1/network/streamer.py:91 |
✅ (main.py:227) | tague machine_id sur chaque POST |
| register/stream/finalize | server_v1/api_stream.py:1748/1801/2336 |
✅ endpoints | session taguée machine_id |
_persist_workflow |
server_v1/stream_processor.py:4417 (appelé 3066) |
✅ | SILOTÉ : écrit data/training/workflows/{machine_id}/ + tag _machine_id |
| Store disque sessions | data/training/live_sessions/{machine_id}/ |
✅ | SILOTÉ (arbo 1:1 par machine) |
_run_cross_session_learning / _find_best_cross_session_match |
stream_processor.py:3149 / 3273 |
✅ (via finalize) | SILOTÉ CODÉ : if workflow_machine != machine_id: continue (L3284-3286) → un poste n'apprend jamais d'un autre |
Listing list_workflows |
api_stream.py:2799 + stream_processor.py:4518 |
✅ | BIMODAL : machine_id=None → tous ; sinon filtré |
Client list_workflows() |
lea_ui/server_client.py:228 |
✅ (smart_tray:802) | COMMUN : n'envoie PAS machine_id → reçoit tous |
| Dashboard list_sessions | web_dashboard/app.py:2289 |
✅ | filtre disque par machine_id (optionnel) |
| Replay ciblage | api_stream.py:3064 + replay_engine.py:1559 |
✅ | machine_id = ROUTE l'exécution vers le bon poste (légitime) |
B. Apprentissage / cognition / compétences (agent Explore #2)
| Module | fichier:ligne | WIRED | COMMUN/SILOTÉ |
|---|---|---|---|
target_memory_store (mémoire cibles, phase 1) |
core/learning/target_memory_store.py:77 |
✅ hot-path resolve_engine.py:1869 |
SILOTÉ par machine (data/learning/target_memory.db local, sauf RPA_LEARNING_DIR partagé) |
continuous_learner |
core/learning/continuous_learner.py |
✅ (stream_processor.py:3145) |
SILOTÉ par session |
replay_learner |
server_v1/replay_learner.py:90 |
✅ (api_stream.py:2436) |
SILOTÉ par session |
learning_manager (états workflow VWB) |
core/learning/learning_manager.py:37 |
✅ singleton VWB | COMMUN |
| Compétences YAML (catalog/replay/persist/verdicts/promotions) | core/competences/* |
✅ endpoints api_stream + dashboard |
✅ COMMUN (tous lisent data/competences/) — c'est le vrai fonds commun qui marche |
observe_reason_act (ORALoop) |
core/execution/observe_reason_act.py:145 |
✅ (VWB api_v3/execute.py) |
siloté par exécution |
feedback_processor, versioned_store, core/cognition/*, core/knowledge, core/coaching, core/healing, core/supervision |
— | ⚠️ ORPHELINS (tests seuls) | — |
C. Graphe / embeddings / autonomie (agent Explore #3)
| Composant | fichier:ligne | WIRED | COMMUN/SILOTÉ |
|---|---|---|---|
| ScreenState (perception) | core/pipeline/workflow_pipeline.py |
✅ serveur | COMMUN |
| StateEmbedding + Builder (fusion 512d) | core/models/state_embedding.py:44 / core/embedding/state_embedding_builder.py:25 |
✅ stream_processor startup |
COMMUN (vecteurs data/training/embeddings/*.npy centralisés) |
| CLIP (OpenCLIP ViT-B-32) | core/embedding/clip_embedder.py |
✅ | COMMUN |
| FAISSManager (similarité) | core/embedding/faiss_manager.py:40 |
✅ stream_processor |
COMMUN serveur mais index per-session en mémoire (pas un index global persistant) |
| WorkflowGraph builder (couche 4) | core/graph/graph_builder.py:148 |
✅ WIRED (import lazy stream_processor.py:3017, instancié :3022 dans finalize_session, DBSCAN) — corrigé : Agent #3 l'avait dit orphelin à tort |
SILOTÉ : graphe construit par session, persisté workflows/{machine_id}/ ; merge cross-session machine-filtré |
| WorkflowNode/Edge (modèles couche 4) | core/models/workflow_graph.py:384 |
✅ utilisés par GraphBuilder | siloté (idem) |
| Shadow observer | core/workflow/shadow_observer.py:25 |
⚠️ partiel (api_stream:2700 observe + LOG seulement) |
pas d'apprentissage collectif |
| Copilot / Autonomous | core/learning/learning_engine.py |
❌ design papier, pas runtime | — |
audit_trail.execution_mode (shadow/assisted/autonomous) |
server_v1/audit_trail.py:50 |
✅ enregistré | mais pas exploité pour décider |
D. Fédération = LE fonds commun par design (vérif directe + Qwen en cours)
| Composant | fichier:ligne | WIRED | COMMUN/SILOTÉ |
|---|---|---|---|
LearningPackExporter |
core/federation/learning_pack.py |
🌙 endpoint manuel GET /api/v1/traces/stream/learning-pack/export (api_stream.py:6278, import lazy L6292) |
conçu commun |
LearningPack + GlobalFAISSIndex |
core/federation/learning_pack.py:294 / faiss_global.py:51 |
🌙 endpoint manuel POST .../learning-pack/import (api_stream.py:6323, L6334-6353 GlobalFAISSIndex() ré-instancié) |
conçu commun |
| Déclenchement automatique | — | ❌ AUCUN : rien dans le flux capture→learn n'appelle export/import | → fonds commun dormant |
Verdict fédération (Claude + Qwen) :
- ✅ Bien architecturé (Qwen) :
LearningPackanonymise (machine_id blacklisté_SENSITIVE_METADATA_KEYS:64,source_hashSHA-256),GlobalFAISSIndexest global (clépack_source_hash+workflow_skeleton_id+node_name+app_name, aucun machine_id), persistant (.faiss+.meta.json,save/loadL245/277). Export prend tous les workflows (processor._workflows.values()L6305) sans filtre machine. - ❌ Mais doublement inerte : (a) pas d'auto-déclenchement (rien dans capture→learn n'appelle export/import) ; (b)
search()jamais appelé —_global_faiss_indexn'est référencé QU'aux lignesapi_stream.py:6351-6372(instanciation +add_packà l'import). Aucun chemin de résolution/apprentissage/replay ne lit l'index global. → write-only, jamais consulté : contribue 0 au runtime.
Conclusion : le fonds commun fédéré est codé correctement mais débranché du runtime — c'est exactement le maillon à activer pour la vision.
Où machine_id cloisonne vs route
- ROUTE (légitime) : ciblage d'un replay/d'une session vers le bon poste (
replay_engine.py:1559,start_replay). - CLOISONNE (à corriger vs vision) : (1) dossiers de stockage
{machine_id}/; (2) filtre dur du cross-session learning (stream_processor.py:3284) ; (3)target_memory.dblocal par machine. + machine_id instable (nouvel ID à chaque relance) qui fragmente même au sein d'un poste.
Gap vs vision « fonds commun → autonomie » (constats, pas décisions)
Pour réaliser la vision, il manque le câblage de :
- Dé-siloter le savoir workflows/sessions : retirer le filtre machine_id du cross-session learning + stockage commun (ou index commun), en gardant machine_id pour le seul routing.
- Activer la fédération en continu (auto-export/import ou store partagé) au lieu du manuel dormant — c'est l'endroit conçu pour ça.
- Câbler la couche graphe (4) en live (aujourd'hui orpheline) pour un knowledge graph commun.
- Implémenter Shadow→Copilot→Autonomous (aujourd'hui observe+log / design) consommant ce fonds commun.
- Stabiliser machine_id (persisté) pour ne pas fragmenter.
Ce qui marche DÉJÀ comme fonds commun (à capitaliser)
- Compétences YAML (
core/competences/) : micro-workflows réutilisables, états supervisés, lus par tous les postes. C'est le modèle commun qui fonctionne → piste à étendre. - Embeddings centralisés (
data/training/embeddings/) : matière première commune déjà là.
E. Pipeline server_v1 (cross-check Codex — intégré)
- Pipeline WIRED : capture →
_worker_queue.txt→run_worker.py→StreamProcessor.reprocess_session()→ workflow JSON → replay → apprentissage.api_stream.pyimporte+instancieReplayLearner/StreamProcessor/StreamWorker(:32/40/41,:562-563, startup:1626-1629). ReplayLearner= commun mais faiblement effectif :ActionOutcomesansmachine_id, stockage globaldata/learning/replay_results/; MAISquery_similar()ne lit que le cache mémoire_recent(:273-304) etbuild_replay_from_raw_events()crée une nouvelle instance (stream_processor.py:2379-2382) → l'historique JSONL global n'est pas exploité après restart/hors instance globale.- Risque ambiguïté : la queue worker ne porte que
session_id, pasmachine_id(api_stream.py:734-760) → résolution disque ambiguë si 2 machines ont le mêmesession_id. machine_idroute légitimement :/replay,/replay/nextrefusent les actions d'une autre machine (:3978-3982,:4033-4054),_find_active_agent_sessionfiltremachine_id/bg_<machine_id>(replay_engine.py:1559-1588).
Pistes de correction CONVERGENTES (constats Codex+Claude — NON décidées, mapping seulement)
- Cantonner
machine_idau routing/fleet/replay-target/audit — pas au stockage ni au matching du savoir. - Dé-siloter les workflows appris : sortir du stockage logique
workflows/{machine_id}/(ou neutraliser ce marqueur en lecture/matching). - Retirer/rendre optionnel le filtre machine dans
_run_cross_session_learning()/_find_best_cross_session_match()(stream_processor.py:3193-3203,3283-3286) → apprendre sur tous les workflows compatibles. - Brancher le fonds commun fédéré : (a) alimenter le
GlobalFAISSIndexen continu (auto export/import ou store partagé) ; (b) appeler sonsearch()dans le hot-path résolution/apprentissage (aujourd'hui jamais lu). - Rendre
ReplayLearnerdurable : charger/interroger l'historique JSONL global, réutiliser l'instance globale (pas une neuve par session). - Stabiliser
machine_id(persisté) pour ne pas fragmenter intra-poste. - Étendre le modèle "compétences communes" (
core/competences/, déjà commun + supervisé) comme colonne vertébrale du fonds commun.
Sources : graphify-out (58k nodes) ; agents Explore #1/#2/#3 (⚠ verdicts "orphelin" sur imports top-level corrigés par lazy-import) ; cross-checks Codex (server_v1, msg 16:43) & Qwen (federation/FAISS, msg 16:50) intégrés ; vérifs directes api_stream.py:6271-6372, faiss_global.py:199, stream_processor.py:3017-3022.