blog.vfg.lol

Du bateau qui fuit au port qui tient — le journal de ces deux jours

Il y a deux choses qu'on n'avait pas faites depuis longtemps : réparer la chaîne qui montre qui travaille, et mettre les données d'un vrai jeu à l'abri. Entre les deux, une campagne de stabilisation menée au chrono, quatre aperçus publiés, un agent local jugé sur pièces, et un déploiement qu'un geste anodin aurait pu transformer en effacement de quatre mois de vie. Voici, dans l'ordre, tout ce qui a été débugué, livré, corrigé et prototypé — avec les liens, les chiffres et les captures.

TL;DR — Deux jours de travail, une seule question de fond : comment savoir, sans se raconter d'histoires, ce qui tourne vraiment et ce qui va vraiment bien ? On a réparé la télémétrie des agents (morte en silence pendant la nuit), fait passer un vrai jeu en production sans perdre une seule donnée du joueur, stabilisé la campagne de correctifs de Jah en montant de 4.0.16 à 4.0.18 puis 4.0.21 jusqu'à la clôture 13/13, évalué un agent local en le jugeant sur pièces, et publié quatre présentations visuelles pour rendre tout ça lisible. Les chiffres, les liens et les captures sont plus bas.

Pourquoi ces deux jours comptent

Il y a deux choses qu'on n'avait pas faites depuis longtemps.

La première, c'est de réparer la chaîne qui montre qui travaille. Toute une mécanique de présence — des crochets qui signalent « un agent est en train de faire quelque chose, là, maintenant » — alimente un tableau de bord. Sauf qu'elle s'était arrêtée pendant la nuit, sans prévenir personne, et qu'on ne l'a vu qu'en regardant le tableau de bord vide au matin.

La seconde, c'est de mettre les données d'un vrai jeu à l'abri. Le site du héros (le petit jeu en ligne « Hero ») tournait encore sur une version de juin, et sa page publique publiait le jeton d'écriture en clair. En préparant le grand nettoyage, on a découvert que la base de données vivait dans un dossier temporaire — celle qu'on croyait sauvegarder n'était jamais sauvegardée.

Entre ces deux pôles, tout le reste : une campagne de stabilisation menée au chrono, quatre présentations visuelles publiées, un agent local jugé sur pièces, et une méthode qui s'écrit elle-même en marchant.

Le fil rouge de tout ce qui suit : on ne déduit rien, on mesure. Chaque affirmation de ce récit est adossée à une commande, un chiffre ou une capture.


1. La chaîne de présence, morte en silence

Ce qu'on a trouvé

Le matin du 5 octobre, trois services qui composent la chaîne de présence (la porte :5191, le registre temporel :4344, le tableau de bord :4477) ne répondaient tout simplement plus. Refus de connexion sur les trois.

Le diagnostic, mesuré, a trouvé deux causes racines distinctes :

  1. Une mise à jour de l'environnement d'exécution — on est passé de Node 22 à Node 24 — avait non seulement tué les processus en cours, mais aussi cassé un module natif (better-sqlite3) : le module avait été compilé pour l'ancienne version. Le registre temporel ne pouvait plus redémarrer. Erreur explicite dans son journal : ERR_DLOPEN_FAILED.
  2. La tâche planifiée qui relançait la chaîne avait été configurée sur un déclencheur « à l'ouverture de session », sans répétition. Autrement dit : si elle tombait en cours de journée, personne ne la relançait avant la prochaine ouverture de session.

Ce qu'on a fait

  • Recompilé le module natif (npm rebuild better-sqlite3) → le registre temporel réécoute.
  • Reprogrammé la garde pour qu'elle se relance toute seule toutes les 15 minutes, avec un script idempotent qui vérifie d'abord si le service répond avant de le démarrer.

La preuve

Le script de santé est passé de 3 refus à 12/12 OK (la porte, le registre, le tableau de bord, le proxy d'usage, Ollama, les relais, le spool, les 4 configurations de crochets, la tâche planifiée). Bout-en-bout : un événement de test émis comme le ferait un agent a été vu dans le tableau de bord en ~11 secondes (synthetic:false, session active). Et le mode « sans perte » a été prouvé : en émettant vers une porte volontairement morte, l'événement est allé dans la file d'attente locale, puis a rattrapé son retard tout seul.

Le temps de la réparation : 01:15 → 01:50, soit 45 minutes du constat à la preuve.

La présentation visuelle

Une page dédiée raconte cette réparation pas à pas, avec le tableau « 3 ports refusés → 12/12 OK » :

Un outil réutilisable en est sorti

On a fabriqué un tableau de bord de présence rejouable, qui photographie l'état courant des agents, des événements et des abonnés au bus :

node D:\GitRepos\vfg-dispatcher\scripts\presence-dashboard.mjs

Il produit une page autonome (elle montre même la chaîne si elle est coupée) et retente une lecture en direct. Découverte au passage, importante : le tableau de bord « Fil » n'est autre que le projet Chronowflow (:4477), avec 8 vues (guide, présence, flux, journal, projets, tâche, boîte de réception, carte mentale).


2. Jah : la campagne de stabilisation, menée au chrono

Jah Messenger, c'est le village-jeu en ligne avec son messagerie rétro devant. Le soir du 4 octobre, la production était en 4.0.16, et il restait une campagne de 13 correctifs à mener, un par un, chacun derrière sa barrière de vérification complète.

Ce qui a été livré

  • 4.0.17 puis 4.0.18 le soir même, en deux temps d'une quinzaine de minutes : le correctif du « Tope-là » qui ne sonnait pas (#273), puis la pile STAB-01 + 02 + 03 (grille des salons mobile, HUD du monde, palettes du compositeur).

La leçon la plus utile : cinq petites barrières en parallèle coûtent plus cher qu'une seule

C'est le genre de leçon qu'on ne croit qu'après l'avoir chiffrée. Cinq petites pull-requests lancées ensemble devaient aller plus vite. Mesure faite :

ApprocheMur ressenti (l'humain qui attend)Minutes machine
5 vérifications en parallèle76 min~2 h 28
5 vérifications en séquence~37 min~25 min

En clair : le parallèle a pris le double de temps ressenti et six fois plus de travail machine, parce que les vérifications se sont mises en file d'attente sur la même ressource, avec des reprises. Le coût est fixe par pull-request, pas proportionnel à la taille du correctif.

Ce que ça veut dire concrètement : sur ce projet, moins de grosses pull-requests lancées ensemble battent beaucoup de petites lâchées en même temps.

L'outillage visuel qui a accompagné le chantier

Pendant que le code avançait, on a fabriqué un visualiseur HTML en direct, en 8 vues (global, prod, releases, lots, pull-requests, temps, critique vs fluide, suite à venir), puis une version en ligne :

  • 📊 Visualiseur STAB (8 vues) → https://blog.vfg.lol/jah-stab-vues
  • Vue Temps (camemberts et frise, 117 exécutions / 110 lots) via npm run metrics → .metrics/index.html
  • Captures : devblog/assets/screenshots/vfjah/2026-10-04/jah-stab-vue1-lots.png … jah-stab-vue8-eta.png

La suite

La campagne n'est pas restée à 4/13. En trois vagues, elle est montée : 12/13 le 5 au soir, avec le dernier correctif (STAB-10) et la release de clôture 4.0.22 partis en une session solo — parce que FG avait mesuré que faire tourner les visualisateurs en parallèle du développement polluait l'avancement (commits croisés sur une même branche, fichiers piqués dans le partage). Résultat côté prod, lu à l'instant :

https://jah.vfg.lol/readyz → {"status":"ready","version":"4.0.22"}

Trois articles ont accompagné la soirée Jah, tous en ligne : « Jah au 4 octobre 2026 : la prod est en 4.0.18 », « Jah : soirée STAB — de 4.0.16 à 4.0.18, critique vs fluide », et « Voir le temps : visualiseur STAB du soir ».


3. Hero : un déploiement qui aurait pu effacer quatre mois de vie

C'est l'histoire la plus importante de ces deux jours — et la moins visible.

Le point de départ

hero.vfg.lol (le site du héros) servait une version du 14 juin, avec un jeton d'écriture publié en clair dans sa page publique, et une API à 88 jours d'uptime (donc jamais redémarrée depuis des mois). Deux chaînes de déploiement coexistaient pour la même adresse : un FTP qui échouait à chaque poussée, et une chaîne Docker bridée par des secrets manquants.

Le piège invisible

C'est en cherchant à exporter les données que le vrai danger est apparu. La base vivait dans un dossier éphémère du conteneur, alors que le volume persistant — celui qu'on sauvegardait — était monté sur un dossier voisin. Conséquence : la base n'était jamais sauvegardée, et le script de sauvegarde archivait un volume vide. Une simple redémarrage aurait effacé niveau, XP, quêtes et journal.

Les six gestes

La session s'est donc déroulée comme une suite de gestes, chacun mesuré :

  1. Figer la version réellement servie dans une « release de retour » exacte (le tag existant était deux commits trop ancien).
  2. Exporter la base vivante sans arrêter le service (empreinte stable, en-tête SQLite valide, contenu relu pour être sûr d'emporter de vraies données).
  3. Déployer la v2 en corrigeant le compose pour monter le volume au bon dossier, avec la bonne propriété.
  4. Migrer en place : la nouvelle version fait évoluer la base sur place, migrations idempotentes — les données survivent.
  5. Tourner le jeton (il avait été public), et recâbler le pont entre Hero et la porte, en corrigeant au passage un chemin d'environnement erroné qui aurait bloqué la rotation.
  6. Clore : six contrôles de sortie, tous verts.

Le résultat

ContrôleRésultat
page publique env.jsaucun jeton
écriture sans sessionrefusée
fiche publique200 — niveau 7, 997 XP, 9 quêtes
page d'adminredirigée vers la connexion
santé APIOK, uptime faible (bien redémarrée)
front200, assets v2

Le retour reste possible à tout moment : une commande pour remettre l'image de juin, et les sauvegardes de configuration conservées à côté.

La leçon n'est pas « on a déployé une v2 ». C'est qu'un déploiement fait sans mesurer ce qui tourne et où vivent les données aurait pu effacer quatre mois sans un seul message d'erreur.

La présentation visuelle et l'article


4. L'agent local, jugé sur pièces

À côté du développement, on évalue depuis plusieurs jours une autre façon de travailler : laisser un modèle qui tourne sur la machine locale (pas dans le nuage) mener des tâches, avec des outils. Ces deux jours ont donné un verdict net.

Ce qui marche

Un harnais — un « banc » — appelé Fast Coder fait travailler l'agent local en boucle : il exécute des outils, vérifie le résultat, recommence. Le dépôt vfg-coder porte ce harnais : 35 tests sur 35 passent, et le banc donne, en mode déterministe, loop = 6/6 corrects (100 % du premier coup, ~3 tours) contre single = 6/6 en un seul tour sans vérification en boucle.

Ce qui ne marche pas

On a demandé à l'agent local d'écrire lui-même une clôture de session et un rapport de métriques, puis on a comparé ses dires à la réalité à la source. Résultat :

  • Le gemma local fait une clôture factuelle et ancrée (~20 s) : il cite les vrais commits, ses « vérifications » sont exactes.
  • Un autre modèle (bonsai) a injecté des balises XML dans un nom de fichier et rappelé un outil inutilement.
  • Surtout : un modèle local (qwen3:14b) invité à rédiger un article a inventé quatre commandes et un fait faux — hallucination prouvée par recoupement.
  • Le rapport de métriques du local lisait bien les chiffres (y compris une incohérence subtile entre deux champs) mais dessinait de fausses barres : il réinventait les proportions sans recalculer.

La conclusion est devenue une règle : le verdict doit venir d'un runner, jamais du modèle qui se juge lui-même. Un modèle qui signe son propre « PASS » sans rien exécuter produit du bruit, pas une preuve.

Les deux présentations visuelles

Et pour choisir le bon modèle

On a construit un comparateur de modèles rejouable : 18 modèles catalogués (16 dans le nuage, 2 locaux) avec identité, architecture, contexte, capacités, scores publics, coûts et usages — plus une sonde qui mesure la latence et le débit (tok/s). Enseignement mesuré : le débit cloud va de ~189 tok/s (le plus rapide) à ~80 tok/s, tandis que le local tourne à ~10 tok/s. Et un piège : un modèle ne sait pas s'identifier — plusieurs se disent « Claude » ou « GPT-4o » quand ils ne le sont pas. La référence, c'est le catalogue, pas la réponse du modèle.


5. Le tableau de bord des statuts et l'urgence fantôme

Un projet s'affichait en urgence haute depuis 98 jours sur le tableau de bord des statuts, sans qu'aucune alerte ne lui corresponde.

La cause, mesurée : ce n'était pas le tableau de bord. Le projet avait été déplacé sous un autre dossier, l'ancien chemin de recherche ne le trouvait plus, et son statut vieillissait à l'écran en silence (motif « pas de STATUS.md » → projet figé). Correction faite, plus deux défauts découverts en chemin (un mode « à blanc » qui écrivait quand même, et un « 0 résultat » muet). Après correction : 0 projet en urgence haute.

Au passage a été figée une règle durable : le tableau /statuts-projets/ est une projection automatique — on ne le « met à jour » jamais à la main, c'est le défaut qui est en amont qu'il faut corriger.


6. Les outils qui se regardent eux-mêmes

Deux autres chantiers d'un jour, discrets mais structurants :

La carte de tout notre outillage visuel

On avait trois « chantiers des lots » qui coexistaient — trois tableaux qui répondent à la même question « où en est-on ? ». Un seul était régénérable ; les deux autres étaient des relevés faits à la main, figés au 01/10 et au 30/09, jamais remis à jour. D'où l'impression de vues « oubliées ».

Réponse : une carte unique qui recense toutes les vues d'avancement (lots, frises, tableaux de bord, captures), leur commande de régénération et leur URL.

La synchronisation des dépôts, mesurée

Un audit par la mesure de 49 dépôts et 82 copies de travail a établi qui est à jour et qui diverge — sans rien pousser ni tirer. Constat principal : un dépôt divergeait (7 en avance / 2 en retard, avec du travail d'un autre agent dessus) et il a été décidé de ne pas forcer le passage, plutôt que d'écraser le travail en cours.

La méthode qui s'écrit une fois et se sert partout

Un savoir a été écrit une seule fois et rangé à chaque étage de ce qu'on appelle l'« arbre de connaissance » : la règle dans le méta-dépôt, l'article sur le blog, l'accès par le serveur de documentation (MCP), et le rappel dans l'outillage de développement. La règle produite : tout rapport de fin de session doit déclarer son origine d'exécution (bionic-native, api-lmstudio, cloud, agent-cli, human) — parce que, mesuré, aucun journal ne distinguait ces origines.

Et un trou a été fermé : la règle existait mais n'était pas servie par le serveur de documentation (le dossier des règles n'était pas dans la liste autorisée). Après correction et redéploiement du serveur, la requête réelle renvoie bien indexedFiles: 1195 et sert la règle. Le piège retenu tient en cinq mots : « autorisé » n'est pas « servi ».


7. Le hub : tout est rangé sous un seul toit

Toutes les présentations visuelles de ces deux jours — et quelques-unes de la veille — vivent sous un même hub, atteignable depuis les articles :

État mesuré : 13 présentations · 9 sujets. Les quatre du 5 octobre sont celles ci-dessus (agent local ×2, télémétrie, urgence fantôme) plus la cartographie de l'outillage et le récit Hero. S'y ajoutent les sujets Jah (fiche, diaporama, CD-ROM éducatif), la méthode « ouvrir la maison entière » (deux tons), les idées « lore », et la course de modèles locaux.

Note honnête : ces pages sont des essais, pas des portes du menu. Elles vivent sous /prototypes/, atteintes depuis les articles qui les présentent.


Ce qu'on retient, en trois phrases

  1. On ne déduit pas, on mesure. Le tableau de bord n'inventait rien (c'était un chemin de dossier périmé) ; la base n'était pas sauvegardée (mauvais volume) ; le jeton n'était pas seulement exposé, il était encore actif. À chaque fois, c'est la mesure qui a nommé la vraie cause.

  2. Le verdict doit venir d'un runner. Un modèle — local ou non — qui s'auto-valide produit du bruit. Le rapport de métriques l'a prouvé : chiffres lus correctement, mais barres réinventées.

  3. Moins de grosses portes, pas plus de petites. Cinq vérifications en parallèle ont coûté six fois plus de machine et deux fois plus de temps ressenti qu'en séquence.


Annexe — tout ce qui est en ligne aujourd'hui

SujetLien
Hub des aperçus (13 présentations)https://blog.vfg.lol/prototypes/apercus/
Agent local jugé par ses traceshttps://blog.vfg.lol/prototypes/apercus/2026-10-05-rapport-agent-local-bionic.html
Deux articles face à face (hallucinations)https://blog.vfg.lol/prototypes/apercus/2026-10-05-comparaison-articles-agent-local.html
Télémétrie réparée en 45 minuteshttps://blog.vfg.lol/prototypes/apercus/2026-10-05-reparation-telemetrie-presence.html
98 jours d'urgence fantômehttps://blog.vfg.lol/prototypes/apercus/2026-10-05-urgence-fantome-statuts.html
Carte de l'outillage visuelhttps://blog.vfg.lol/prototypes/apercus/2026-10-05-cartographie-outillage-visuel.html
Hero v2 : les six gesteshttps://blog.vfg.lol/prototypes/apercus/2026-10-05-hero-v2-six-gestes.html
Visualiseur Jah STAB (8 vues)https://blog.vfg.lol/jah-stab-vues
Article : le juge ne peut pas être le sujethttps://blog.vfg.lol/devblog/posts/metaprojet/2026-10-05-0447_le-juge-ne-peut-pas-etre-le-sujet.md
Article : Hero v2 en productionhttps://blog.vfg.lol/devblog/posts/metaprojet/2026-10-05-0544_hero-v2-en-production-donnees-migrees-jeton-tourne.md

Sondes live (au moment d'écrire) : jah.vfg.lol/readyz → 4.0.22 · hero.vfg.lol → 200 · blog.vfg.lol/prototypes/apercus/ → 200.

source markdown

Concepts de cet article

VFG HerogardeMCP

Partage le plus de concepts avec