Observabilité et contrôleurs

Comment Nika OS observe ses propres pods sans polluer son contexte. Le contrôleur KTW (Kelly–Taguchi–Weibull) au cœur du pilotage probabiliste.

L’observabilité comme primitive

Un système agentique non observable est un système qu’on ne peut pas piloter. Nika OS expose donc l’observabilité comme une primitive de premier ordre, pas comme un add-on.

Trois sources de signal coexistent :

  1. Le stream Redis par pod — chaque appel d’outil produit un XADD.
  2. Le bus JSONL — append-only, audit trail permanent.
  3. Le fleet state — dictionnaire Redis nika:fleet:state maintenu par le daemon fleet_consumer.py.

Le fleet daemon

fleet_consumer.py tourne en permanence dans un tmux dédié (nika-os:FLEET-CONSUMER). Il :

  • consomme le stream cg:worker du feed entités ;
  • maintient un état agrégé par pod (status, last tool, error count, KTW loss) ;
  • expose cet état via nika:fleet:state (HASH Redis lu par fleet_status.py).

Sans ce daemon, les pods sont aveugles entre eux. Avant toute action susceptible de conflit inter-pod (édition de fichier partagé, déploiement, changement de schéma), un pod doit appeler :

python3 scripts/fleet_status.py --active

Cette commande retourne en quelques millisecondes la liste des pods actifs, leur entité, leur dernière action, et leur loss score. Aucune lecture de context window n’est nécessaire.

Pod streaming sans pollution de contexte

Une des erreurs classiques en orchestration multi-agent est de demander à l’orchestrateur de lire les transcripts de chaque pod pour comprendre ce qu’ils font. Cela charge la fenêtre de contexte de l’orchestrateur en contenu peu prioritaire (logs détaillés), et la sature rapidement.

Nika OS pose la séparation suivante :

  • Les événements significatifs (création, complétion, échec, escalade) arrivent à Alpha via le feed entités.
  • Les logs détaillés restent en local sur le pod (logs/) et en Redis Streams. Alpha les lit à la demande, jamais par défaut.
  • Une skill dédiée (pod-observe) permet à Alpha de faire un semantic search sur les tool calls d’un pod précis, sans charger son transcript.

Cette discipline permet à Alpha de coexister avec 6 pods workers actifs en parallèle sans saturer sa propre fenêtre de contexte.

Le contrôleur KTW

Au cœur du système d’observabilité industrielle de BCUB3 — et à l’origine de deux brevets INPI déposés en janvier 2026 — vit le contrôleur KTW, pour Kelly–Taguchi–Weibull. Ce contrôleur sert deux usages :

  1. Piloter un procédé physique (remplisseur de bouteilles, four, presse).
  2. Piloter les hyperparamètres d’un agent (par exemple, la température du modèle, le nombre de retries d’un pod) en fonction d’une métrique observée.

Kelly : combien intervenir

La formule de Kelly (1956) calcule la fraction optimale d’un capital à miser sur un événement de probabilité connue. Transposée au pilotage industriel, elle calcule la fraction optimale de correction à appliquer à une consigne machine quand on a une probabilité estimée que l’écart soit une vraie dérive.

Taguchi : quelle perte minimiser

La perte de Taguchi traduit l’écart entre une mesure et sa cible en coût. Au lieu d’une fonction binaire (« bon » ou « mauvais »), Taguchi pose une fonction quadratique continue : plus on s’éloigne de la cible, plus la perte croît. Cela permet au contrôleur de prioriser ses corrections : un écart proche de la cible coûte peu, un écart lointain coûte beaucoup.

Weibull : quelle probabilité de dérive

Pour estimer si un écart est une dérive réelle ou un bruit de mesure, on ajuste une distribution de Weibull sur les 50 dernières mesures. Le paramètre de forme de cette distribution dit si on observe une distribution stable (bruit) ou une queue lourde (dérive en cours).

En combinant les trois

Le contrôleur KTW prend la décision suivante à chaque mesure :

correction = kelly_fraction(probabilité_Weibull) × perte_Taguchi
flowchart LR
    M["📊 Mesure y(t)"] --> W["Weibull<br/>P(dérive réelle)"]
    M --> T["Taguchi<br/>L = k·(y-cible)²"]
    W --> K["Kelly fraction<br/>f(P)"]
    K --> D{"Décision"}
    T --> D
    D -->|"P faible"| N["🤫 Bruit<br/>ne rien faire"]
    D -->|"P intermédiaire"| S["🧭 Doute<br/>correction douce<br/>+ attendre confirmation"]
    D -->|"P élevée + L fort"| F["⚡ Dérive<br/>correction ferme<br/>+ immédiate"]

    classDef input fill:#F3EADE,color:#2C3E42,stroke:#7DB5A5,stroke-width:2px;
    classDef calc fill:#FAF5EC,color:#2C3E42,stroke:#A86640,stroke-width:1.5px;
    classDef decide fill:#2C3E42,color:#FDFBF8,stroke:#1A262A,stroke-width:2px;
    classDef noop fill:#5E9384,color:#FDFBF8,stroke:#5E9384;
    classDef soft fill:#E99971,color:#FDFBF8,stroke:#C97A55;
    classDef firm fill:#C97A55,color:#FDFBF8,stroke:#A86640;
    class M input;
    class W,T,K calc;
    class D decide;
    class N noop;
    class S soft;
    class F firm;

Trois zones distinctes émergent :

  • Bruit (probabilité Weibull faible) — ne rien faire.
  • Doute (zone intermédiaire) — correction douce, attendre confirmation.
  • Dérive (probabilité Weibull élevée et perte Taguchi forte) — correction ferme et immédiate.

C’est ce comportement qui rend le système antifragile au sens de Taleb : au lieu d’osciller à chaque bruit, il attend d’avoir l’information statistique nécessaire pour intervenir, et apprend de chaque dérive observée.

Application à l’orchestration d’agents

Le même contrôleur KTW est utilisé pour piloter les pods. La métrique observée n’est plus une mesure physique mais une loss score calculée sur les tool calls et les sorties du pod.

Quand la loss d’un pod franchit un seuil, le système :

  1. Ne kill pas le pod immédiatement (équivalent du « ne rien faire » dans la zone bruit).
  2. Si la loss continue de croître au-delà du seuil intermédiaire, mute les primitives mutables (température, retry policy, prompts).
  3. Si la loss reste élevée après mutation, escalade : WhatsApp alert → bus JSONL → review request à l'opérateur humain.

Le système d’alerting pod (pod-alerts skill) lit le stream nika:alpha:alerts rempli par le pod stream embedder. Au début d’une session de triage, l’opérateur peut demander « des alertes ? » et recevoir la liste des pods en problème avec leur loss observée.

Pour aller plus loin

Les brevets KTW B1 et B2 sont décrits en détail sur la page principale du Lab BCUB3. La fonction d’activation neuronale sWELU (brevet INPI FR2513029) est complémentaire : elle améliore l’apprentissage des petits modèles utilisés pour les estimateurs Weibull en edge.

Juger un livrable : la difficulté du “Definition of Done”

Observer un pod, c’est facile (status, latency, exit code). Juger s’il a réellement accompli sa tâche, c’est nettement plus difficile. Cette difficulté est au cœur de la R&D Nika OS.

Pourquoi le DoD est piégeux

Pour un job classique (build, tests, déploiement), le DoD est binaire : exit 0 ou pas, tests verts ou pas. Pour un job agentique, le DoD est multi-dimensionnel :

  • Le pod a-t-il produit les bons fichiers (cohérence avec le brief) ?
  • Les fichiers ont-ils la qualité attendue (lisibilité, complétude) ?
  • Les invariants métier sont-ils respectés (pas de PII, pas de claims faux, pas d’engagement irréversible) ?
  • Le style correspond-il (tone professionnel, formulation cohérente) ?
  • Y a-t-il eu des effets de bord non documentés (commit non listé, modification de fichier hors scope) ?

Aucun de ces critères n’est observable par un simple exit code. Tous nécessitent un jugement sémantique.

LLM-as-judge — la couche d’évaluation

Notre primitive pod_handoff applique un jugement structuré à la fin de chaque pod (hook SubagentStop). Le verdict est l’un de :

VerdictSensAction
DONEDoD atteint, livrables produits, invariants respectéskill (no-op)
PARTIALUne partie des livrables manque ou a un défaut mineurrelaunch avec brief enrichi
STUCKLe pod est resté bloqué sans produirerelaunch retry_count++
DORMANTSTUCK longue durée sans transcript ni session — projet multi-jours, pas erreurarchive sans escalade
NO_DODBrief sans Definition of Done expliciteescalation humaine

Pourquoi un LLM (et pas seulement des règles)

Plusieurs critères sont implémentés en règles déterministes (regex, comptage de fichiers, lecture de frontmatter). Mais d’autres exigent un modèle de langage capable de comprendre le brief, comparer aux outputs, et émettre un score nuancé. Cette couche est nécessairement subjective. Pour réduire le biais :

  • Cross-CLI judge — le même output est jugé par 2-3 LLM différents (Claude, Gemini, Mistral) ; on prend la médiane ou le consensus.
  • Algorithmic check before LLM — on commence par les vérifications déterministes (factualité contre RAG, schéma JSON, longueur, etc.) ; le LLM n’est appelé que sur l’incertitude résiduelle.
  • Audit log obligatoire — chaque verdict LLM est tracé en JSONL avec le prompt, l’output, la confiance estimée et le verdict humain a posteriori quand il y en a un. Le tournoi GEPA utilise ces décalages pour faire évoluer le prompt de jugement lui-même.

L’exploration comme premier-citoyen

Conséquence directe : on ne peut pas optimiser ce qu’on ne peut pas mesurer. Nika OS accepte donc une part irréductible d’exploration :

  • Plusieurs CLI répondent en parallèle au même prompt (tournoi multi-pods) pour générer de la diversité d’outputs.
  • Un méta-pod déterministe combine les sorties via algorithmes classiques (consensus voting, outlier detection, factual check) avant d’engager le LLM-as-judge.
  • L’algorithme KTW pondère la confiance du jugement : si la dispersion est forte (faible accord entre juges), on diminue la fraction de Kelly et on intervient moins fortement. Si l’accord est élevé, on agit avec confiance.

Cette philosophie — bénéficier de la variabilité plutôt que la combattre — est l’expression opérationnelle de la doctrine d’antifragilité décrite plus haut. Un pod individuel peut se tromper ; un essaim de pods couplé à un évaluateur multi-perspectives est plus difficile à tromper.