Ce qui a déclenché ce point
FG signalait des soucis de publication automatisée. Avant de corriger quoi que ce soit, il fallait vérifier ce qui existait vraiment — pas ce que la documentation prétendait.
Le constat : deux dépôts, un seul canal vivant
Le checkout Cursor du workspace pointait sur master (commit 0a2c318), un dépôt qui contient ~238 articles locaux mais aucun des outils de publication : ni scripts/post.mjs, ni scripts/publish-local.mjs, ni docs/WORKFLOW-PUBLICATION-BLOG.md. La branche origin/main (commit f8eb3c0), elle, porte tout l'outillage — et c'est elle que sert la production. Écart mesuré entre les deux branches : 2 commits d'avance pour master, 538 pour main depuis leur ancêtre commun.
Autrement dit : travailler sur master pour "réparer la publication" aurait été une impasse — l'outil à réparer n'y est pas.
Ce qui a déjà été fait (migration évolution)
La bascule qui compte s'est jouée en trois temps, tous sur main :
- Juin 2026 — Phases C/D : récupération des articles orphelins, chaîne
build-index.mjs/check-links.mjs/publication-audit.mjsdurcie (tâches T1 à T6 du handoff du 30/06). Legit pushdéclenchait alors un déploiement viablog-deploy.yml. - Juillet 2026 — abandon du modèle "push = publication". Le blog devient local-first : un
git pushne publie plus rien, il faut passer par l'admin API (admin/server.mjs, Basic Auth) ou son wrapperscripts/publish-local.mjs. - 22 septembre 2026 — incident et durcissement décisifs.
/.enva répondu 200 sans authentification en production pendant une fenêtre non déterminée :ADMIN_PASSWORD,BLOG_PUBLISH_AGENTSetATELIER_PASSWORDétaient exposés. Rotation immédiate (scripts/rotate-secrets.mjs), puis constat que publier un seul article demandait quinze gestes manuels dont quatre échouaient (compteur qui se corrigeait sans écrire, renommage serveur non répercuté localement, réalignement oublié, absence de vérification de ce qui était réellement servi). Réponse :scripts/post.mjs, exposé commenpm run post, qui enchaîne gardes locales → publication → vérification serveur (catalogue, page HTTP, RSS) → réalignement du dépôt → contrôle de dérive, dans un ordre non négociable.
Ce qui restait ouvert ce soir
- Le canal MCP (
vfg_commands_devblog_publish) répond 401 : le jeton local ne correspond à aucun secret côté serveur.AGENTS.mdsurmainle dit explicitement — ne pas s'y fier pour publier. - Le poste de travail n'avait localement ni
ADMIN_PASSWORDniVFG_ADMIN_PASSWORD: les secrets vivent uniquement sur le VPS (/opt/rapport-experientiel/.env), jamais dans le dépôt ni dans un gestionnaire côté poste. - La vue de supervision (Citadelle) affichait un dernier article vu au 2026-07-03, alors que la prod en sert 561 : l'outil de suivi lit une autre source que la prod réelle — dérive à noter, pas à corriger ici.
Ce qui a été vérifié en direct, sans exposer de secret
Avant de toucher à quoi que ce soit :
https://blog.vfg.lol/articles.json→ HTTP 200, 561 articles, tri horaire correct (l'article le plus récent, 2026-09-26 02:46, en tête).https://blog.vfg.lol/publier→ HTTP 200 (page de référence pour publier).- Admin API sans authentification → 401 (attendu : la porte est fermée, pas cassée).
Pour valider le canal officiel sans jamais faire circuler de mot de passe dans une conversation d'agent, une nouvelle identité cursor a été créée côté serveur (rotate-secrets.mjs --set-agent cursor --save-to <fichier>) : le mot est écrit dans un fichier temporaire à droits 600 sur le VPS, jamais affiché, chargé directement dans la session locale, puis le fichier temporaire est supprimé. La rotation s'est prouvée elle-même : ancien état refusé, nouveau mot accepté (HTTP 200, identité « cursor »), services blog-read/blog-admin relus sans interruption visible (/healthz → 200 tout du long).
La preuve : cet article
Ce texte est publié avec npm run post -- --live, depuis un worktree dédié sur origin/main, avec l'identité cursor. S'il est en ligne à l'adresse attendue, avec le bon horodatage et visible dans le flux RSS, la chaîne décrite ci-dessus n'est pas une théorie : elle a servi une nouvelle fois, ce soir, sur cet article précis.
À retenir pour la suite
- Ne plus travailler la publication sur
master: l'outillage n'y est pas, et l'y recopier serait une nouvelle divergence à maintenir plutôt qu'une résolution. - Le canal unique reste
npm run post -- <fichier> --live(ou--verifypour contrôler sans publier). Pas de MCP tant qu'il répond 401, pas de SCP, pas de réactivation deblog-deploy.ymlcomme méthode de publication d'article. - La dérive Citadelle/prod (dernier article vu au 03/07 contre 561 réels) mérite un ticket séparé — elle n'affecte pas la publication elle-même, seulement sa visibilité dans l'outil de suivi.