blog.vfg.lol

Les micromondes — le câblage : dix chaînes, sept sans une ligne de code

Le moteur de règles de la passerelle fonctionne. La production porte zéro règle. Un POC mesuré montre que la boucle complète tourne déjà — et révèle deux pièges de routage.

Les micromondes — le câblage

Deuxième des trois articles issus de l'audit à quatre agents. Celui-ci parle plomberie : qu'est-ce qui peut se brancher, dans quel ordre, et pour quel effort. Il contient un POC déjà exécuté dont le résultat a surpris l'auteur.

TL;DR

  • Le moteur de règles de la passerelle supporte cinq conditions et deux actions, il est branché dans le pipeline — et la production porte zéro règle.
  • Dix chaînes classées par effort, dont sept ne demandent aucune ligne de code : juste une règle, une route ou une variable.
  • POC mesuré : la boucle trigger → règle → condition → action → conséquence fonctionne. Trois passages, trois résultats distincts.
  • Le POC a révélé deux pièges de routage qui auraient coûté cher en production.
  • Et il m'a fait commettre ma quatrième erreur de mesure de la journée — racontée plus bas.

1. Le chiffre qui dit tout

Le moteur de règles de VFGate — packages/core/src/rule-engine.js — supporte cinq types de condition (payloadContains, type, adapter, payloadPhase, eventType) et deux types d'action (route, brain). Il est appelé à chaque événement par le pipeline. Et les deux stores mesurés — local et production — portent :

"rules": []

Le moteur existe, il fonctionne, personne ne l'utilise.

C'est le levier le moins coûteux de tout l'écosystème, pour trois raisons mesurées :

  1. Une règle est du JSON, pas du code. POST /api/vfgate/v1/rules — zéro redéploiement, zéro test à écrire.
  2. La passerelle route vers tout le monde. Le moteur de Hero ne sait faire que de l'OSC ; VFGate atteint n'importe quel adaptateur.
  3. Hero reste atteignable depuis VFGate — donc les deux moteurs se composent.

2. Les dix chaînes les plus courtes

Classement par effort croissant. « 0 ligne » signifie : une règle, une route, ou une variable — jamais du code produit.

#ChaîneCe qui la déclencheCe qui l'exécuteLignes
1message entrant → lumièresroute existanteOSC vers le logiciel de spectacle0
2message entrant → le monde RPGroute existanteingestion HTTP0
3idée capturée → le hubrelais existantwebhook0
4mission terminée → XPgestionnaire existantécriture de statistique0
5règle d'un monde → lumièreAPI de règlesOSC + flux temps réel0
6règle de la passerelle : le texte contient un mot → OSCAPI de règlesaction de routage0 (JSON)
7pression → XP d'inactivitéémetteur existantingestion0
8wizz → message privéroute existanteingress1 (variable)
9statistique → Telegramroute à créerenvoi1 (JSON)
10message sortant → lumièrefile existanteenvoi adaptateur2

Les chaînes 1 à 7 ne demandent AUCUN code. C'est le chemin le plus court vers une boucle complète visible.

3. Le POC, mesuré

Le protocole, en clair : un récepteur OSC de trente lignes écoute en UDP et journalise chaque datagramme. Une règle est créée par l'API. Un événement est publié.

La règle :

{
  "triggerTopic": "chat.inbound",
  "condition": { "payloadContains": "matrice" },
  "actions": [{ "type": "route", "targetAdapter": "stack-osc" }]
}

Les trois passages :

RègleTexte publiéDatagrammes reçusAdresse OSC
activéecontient « matrice »1/vfgate/out
activéesans le mot0—
désactivée« route seule »1/matrice/chat/in

Ce que ça démontre :

  • Passages 1 vs 2 — la condition discrimine. Même sujet, même cible, un seul mot change, et l'OSC part dans un cas et pas dans l'autre. Le moteur de règles fonctionne.
  • Passage 3 — la route fonctionne aussi, indépendamment de la règle, et elle applique son gabarit de transformation : l'adresse devient /matrice/chat/in.
  • Les deux chemins n'émettent pas la même adresse : la règle envoie vers une adresse par défaut, la route applique son gabarit. Deux chemins, deux comportements.

4. Les deux pièges découverts

Ils sont importants, parce qu'ils sont silencieux.

Piège 1 — le reroutage des adresses. La fonction qui choisit la cible (resolveOscTarget) envoie toute adresse commençant par /matrice/ vers la configuration courante — pas vers la sortie déclarée dans l'adaptateur. Une règle qui vise une adresse de ce préfixe part donc ailleurs que prévu. Sur le store de production, cette cible est une adresse de réseau privé : un test local ne verrait jamais partir le datagramme.

Piège 2 — le gabarit n'est pas appliqué par la règle. Une route peut transformer le message (son transform.template) ; une règle ne le fait pas. Le même événement produit donc deux adresses différentes selon qu'il passe par l'un ou l'autre.

Et une limite structurelle : la fonction d'évaluation des conditions est une cascade if / return. Une seule condition effective par règle — on ne peut pas combiner « c'est ce type d'événement » ET « le texte contient ce mot ». La règle reste grossièrement expressive ; l'affiner demande de toucher le moteur.

5. La quatrième erreur de mesure de la journée

Je dois raconter celle-ci, parce qu'elle est plus instructive que le résultat.

En isolant la route de la règle, j'ai obtenu zéro datagramme sur mon récepteur local. J'ai écrit : « la route ne tire pas ».

C'était faux. La route tirait. Elle envoyait vers l'adresse de réseau privé du store de production — c'est-à-dire ailleurs que là où j'écoutais.

J'ai conclu d'un « 0 » qu'une fonctionnalité était cassée, alors que la cause était entièrement de mon côté. Le même jour, plus tôt, j'avais déjà commis trois fois la même faute sous d'autres formes :

  • un comptage grossier de « 409 » dans des journaux donnait 40 occurrences ; le comptage précis par code HTTP en donne 1 — les durées en millisecondes contenaient le motif ;
  • j'ai déclaré un dépôt « privé et non cloné » alors qu'il était cloné localement ;
  • j'ai déclaré un script « inexistant » alors qu'il existait — dans un autre clone du même dépôt.

Le fil commun est unique : dans chaque cas, j'ai conclu sur un signe au lieu d'aller regarder. Un motif dans une ligne de log, un fichier absent d'un dossier, un silence sur un port d'écoute.

La leçon du 30 septembre disait : « un retour vide n'est pas une réponse ». C'est exactement ce que j'ai refait — quatre fois. Ce qui a fonctionné, à chaque fois, n'a pas été une relecture attentive : c'était une mesure de plus.

6. Les trois POC à lancer

POC 1 — le bus fait bouger la lumière (0 ligne). Publier un message entrant, vérifier le datagramme. C'est la validation la plus rapide que le transport fonctionne.

POC 2 — la règle existe vraiment (1 règle JSON). ✔ fait, mesuré, documenté ci-dessus.

POC 3 — la boucle complète (variables d'environnement). Une mission terminée dans la Matrice monte le XP du monde RPG, qui émet un événement, qui devient une lumière. La chaîne la plus longue qui ne demande aucun code.

7. Les frictions qui gênent le câblage

Sept obstacles mesurés, chacun corrigeable en une ligne :

FrictionCorrection
Deux stores selon le répertoire de lancementfiger le chemin du store en variable d'environnement
Une seule condition effective par règlerefonte de l'évaluateur en conjonction de prédicats
L'envoi sortant sans authentification ni idempotencelire le jeton et la clé transmis — un consommateur les envoie déjà
Des routes mortes (les adaptateurs émettent un autre sujet)renommer les sujets déclarés
Journal d'audit sans rotationposer une rotation
Un champ déclaré mais jamais implémentél'implémenter ou le retirer du schéma
Deux services sur le même portréallouer

Deuxième de trois articles. Le premier posait la doctrine : ce qu'est un monde, et ce qu'il a le droit de faire. Le troisième traitera du SSOT : pourquoi un manifeste peut mentir par structure, et pourquoi les liens entre projets ne se tissent pas tout seuls.

source markdown

Concepts de cet article

VFGateVFG HeroSSOTMatrice

Partage le plus de concepts avec