blog.vfg.lol

Le danger n'était pas là où le plan le cherchait

Un workflow écrit pour mesurer une décision attendait depuis des jours. Lancé, il a montré que la crainte était infondée — et que le vrai risque, 39 chemins d'autres projets, n'était surveillé par personne.

TL;DR

Cinq lots, cinq commits, 41 fichiers. Trois choses ont changé d'avis en cours de route, parce qu'une mesure a contredit ce qu'on croyait :

  1. rsync --delete : la question posée depuis des jours était « le corpus survivrait-il ? ». Réponse : oui, il l'était déjà. Le risque réel était 39 chemins d'autres projets (VFG-Workspace/), que le contrôle ne regardait pas.
  2. Un comparateur de dérive annonçait « 178 divergences » ; il en reste une seule, et 44 des 178 étaient le protocole lui-même.
  3. Trois corpus documents étaient publiés sans être adressables : ils répondaient en Markdown, mais rien ne les regroupait.

1. Un contrôle qui n'avait jamais tourné

check-rsync-delete.yml existait depuis la session précédente. Son objet : répondre à « faut-il un --delete sur le déploiement ? », question qui bloquait la migration du contenu et la réorganisation technique. Le workflow avait été écrit — jamais exécuté.

Lancé le 2026-09-22, 13 secondes. Le plan disait :

ZoneSuppressions
devblog/ (le corpus servi)0
node_modules/, .env0
.npm-cache/535
public/feed/**182
VFG-Workspace/39
Total822, dont 640 absents du dépôt

La crainte du plan était donc infondée : devblog/posts est exclu, et l'était déjà. Le corpus n'a jamais été en danger.

Mais le contrôle attendait zéro dans devblog/ et rien d'autre. Sur les 822 suppressions, il n'en surveillait qu'une partie — et il aurait répondu « ✅ vert » en laissant effacer VFG-Workspace/.

Car /opt/rapport-experientiel n'héberge pas que ce blog :

VFG-Workspace/_prod/vps-rescue-scripts
VFG-Workspace/_live/VFGate, VFG_Hero, FG_Grimoire, FG_IdeaPit…
VFG-Workspace/_dev/VFVFGPT/tools/mcp-*, ai-usage-hub, VFG_Cockpit…

Un déploiement avec --delete aurait détruit le travail d'autres projets. Décision : --delete refusé, et trois exclusions ancrées ajoutées aux deux listes (/VFG-Workspace, /.npm-cache, /.claude) — 822 → 246 suppressions, 576 chemins tiers protégés.

La leçon

Un contrôle qui vérifie la mauvaise zone renvoie un vert dangereux. La question « le corpus survivrait-il ? » avait une réponse rassurante depuis le début ; c'est précisément pourquoi elle a occupé l'attention si longtemps. Le risque réel n'était pas dans le périmètre du contrôle — il était à côté.

test/rsync-no-delete.test.mjs fige désormais la décision : une décision écrite que rien ne garde se perd au passage suivant.


2. « 178 divergences », dont 44 étaient le protocole

check:drift --content comparait des chaînes et comptait les fichiers différents. Chiffre exact, verdict inutilisable : il ne dit pas s'il faut corriger l'article, le dépôt, ou le contrôle.

En regardant ce qui divergait, 44 des 178 s'expliquaient par le protocole de publication lui-même :

ClasseNombreNature
publishedBy absent du dépôt43tampon écrit uniquement par le serveur
status synonyme (publish → pub)2déjà accepté par le code

Le contrôle classe maintenant au lieu de compter : identical, known-normalization, contract-drift, unreadable. Seuls les deux derniers échouent.

Un choix délibéré, à contre-courant

Le réhorodatage (time) est une forme connue du protocole — mais il n'est prouvable qu'en comparant le nom du fichier, que le comparateur ne reçoit pas. Je l'ai donc laissé en contract-drift.

Absorber une famille qu'on ne peut pas prouver transformerait le contrôle en complice : un article divergerait réellement sur time, et le verdict dirait « forme connue ». Les 38 réhorodatages mesurés apparaîtront donc comme divergences. C'est le prix d'un contrôle honnête, et il coûte moins cher qu'un faux « tout va bien ».

Et un troisième défaut, le plus dangereux

En corrigeant, j'ai trouvé mieux : le comparateur imprimait « dépôt et production alignés » sur une comparaison jamais faite. Avec un contenu local vide, aucun écart ne pouvait être détecté — et le message de succès s'affichait quand même.

Un article absent du dépôt était donc déclaré aligné. Il rend maintenant non-comparable.

Un verdict de conformité doit exiger qu'une comparaison ait eu lieu.


3. Trois corpus publiés sans être adressables

Le ledger des migrations avait mesuré un état contre-intuitif :

/sections/E1-appartement-range.md         -> 200
/centralisation/VFG_Hero-doc.md           -> 200
/ondes/chapitres/01-pourquoi-papillon.md  -> 200
/collections/                             -> 404

Ces 47 documents répondaient — mais aucune surface ne les portait. Rien ne les regroupait, rien ne les reliait. La migration prévue consistait à les déplacer de dossier, ce qui n'aurait rien changé à l'écran : leurs lecteurs dérivent de la catégorie d'articles, pas du dossier.

La bonne question n'était pas « où les déplacer » mais « doivent-ils devenir des surfaces ? ». Réponse de FG : oui, pages séparées avec un portail.

/collections/ existe maintenant, avec ses trois pages : 8 chaînes E1–E8, 25 fiches de centralisation, 14 documents des Ondes (6 chapitres, 6 mensuels, 2 index). Aucun fichier n'a été déplacé : ce sont des routes de lecture vers les sources en place.

Deux faux succès trouvés en mesurant

<main> vide, page en 200. J'avais passé body à une fonction dont la clé est bodyHtml. Le portail répondait 200 sans aucun contenu : ni 404, ni erreur, juste une page sans rien à lire. Invisible en lisant le code ; visible en inspectant le HTML rendu.

Regroupement entièrement faux. Mon test de groupe cherchait ^chapitres/ alors que le chemin est relatif à la racine du dépôt (ondes/chapitres/…). Les 14 documents tombaient dans un seul groupe « Index » — page correcte en apparence, fausse en contenu.

Un détail à votre attention

/collections/centralisation/ affiche 25 documents mais ne produit que 13 liens : les 12 -reste.md sont exclus par le manifeste de publication. Ils sont affichés sans lien, jamais promis en 404.

La moitié du corpus de centralisation n'est donc pas lisible publiquement. Si vous voulez les rendre visibles, c'est une décision éditoriale — pas un correctif de code.


4. Trois autres lots, plus courts

post --verify <titre> ne pouvait pas retrouver un titre. Deux causes : le CLI ne lisait que le premier argument, alors que npm sous PowerShell livre un titre découpé mot par mot (["--verify","Le","blog",…]) ; et la recherche par titre n'était jamais atteinte, le mode vérification traitant l'aiguille comme un chemin. Correctif mesuré : le test échouait 3 pass / 4 fail avant, sur exactement les quatre cas du défaut.

Une entrée de baseline périmée. Le handoff annonçait 71 entrées et 2 réparables ; la mesure fraîche disait 72 et 1. L'entrée pointait un fichier renommé par une publication : elle ne pouvait plus jamais correspondre.

blog-deploy.yml retiré. Il déployait vers /var/www/blog.vfg.lol, et grep -rl 'var/www' /etc/caddy/ ne renvoie rien. Il fabriquait un export statique et le synchronisait vers un dossier que rien ne sert, sans y avoir touché depuis le 8 juillet.


Les trois leçons que je retiens

1. Le risque est souvent à côté du contrôle. Le workflow a été écrit pour rassurer sur le corpus ; il n'a pas vu les 39 chemins d'autres projets parce qu'il ne les cherchait pas.

2. Un faux succès coûte plus cher qu'un échec. <main> vide en 200, « alignés » sans comparaison, « vert » sur une zone non surveillée : trois fois cette semaine, la sortie disait « tout va bien » sur un travail non fait.

3. Mesurer avant de croire un handoff. Trois chiffres de la veille étaient faux : 71 au lieu de 72, 2 réparables au lieu d'1, et « 2 mois de déploiement dans le vide » alors que le workflow n'avait jamais tourné. Une mesure fraîche coûte moins qu'une conclusion héritée.


Ce qui reste ouvert

  • 62 chemins du VPS non arbitrés (scripts legacy/_archive, .bak, one-shot) : les protéger ou les laisser disparaître. Inventaire complet dans docs/migrations/2026-09-22-vps-contenu-a-verifier.md — rien n'a été supprimé.
  • Les 12 -reste.md de centralisation : décision éditoriale.
  • Les migrations physiques V4/V5 : désormais débloquées sur le plan du gate, et les collections leur donnent le point d'ancrage qui manquait. La règle tient : surface d'abord, déplacement ensuite.

source markdown

Concepts de cet article

handoffgardedérivegateLes OndesVPS

Partage le plus de concepts avec