Files
archicratie-edition/docs/OPS-LOCALHOST-AUTO-SYNC.md
Archicratia 69c91cb661
All checks were successful
SMOKE / smoke (push) Successful in 9s
CI / build-and-anchors (push) Successful in 47s
CI / build-and-anchors (pull_request) Successful in 45s
docs: formalize localhost auto-sync architecture
2026-03-16 21:14:41 +01:00

22 KiB
Raw Blame History

OPS — Localhost auto-sync

Objet

Ce document fige larchitecture locale qui permet de garder le localhost éditorial aligné sur origin/main, sans dépendre de la mémoire de lopérateur.

But recherché :

  • quand une PR est mergée sur main, le localhost doit pouvoir se réaligner automatiquement ;
  • le serveur local Astro doit tourner depuis un worktree dédié ;
  • le dépôt de développement principal ne doit pas être pollué par ce mécanisme ;
  • lexploitation doit rester simple à diagnostiquer ;
  • linstallation doit pouvoir être réappliquée proprement après oubli, incident, ou redémarrage machine.

Principes

Larchitecture locale repose sur trois espaces distincts :

  1. Repo canonique de développement

    • Chemin : /Volumes/FunIA/dev/archicratie-edition/site
    • Usage : développement normal, nouvelles fonctionnalités, corrections manuelles, branches de travail, commits, PR.
  2. Worktree localhost dédié

    • Chemin : ~/ops-local/archicratie/localhost-worktree
    • Branche locale : localhost-sync
    • Usage : exécuter astro dev sur une copie locale réalignée automatiquement sur origin/main.
  3. Ops local hors repo

    • Chemin : ~/ops-local/archicratie
    • Usage : scripts dexploitation, logs, état, automatisation LaunchAgent.

Pourquoi cette séparation

Il ne faut pas utiliser le dépôt de développement principal comme serveur localhost permanent.

Sinon on mélange :

  • travail en cours ;
  • commits non poussés ;
  • essais temporaires ;
  • état réellement publié sur main.

Le résultat devient ambigu.

Le worktree localhost sert donc de miroir exécutable de main, tandis que le repo canonique reste lespace de développement.


Vue densemble

Flux logique :

  1. origin/main avance après merge dune PR.
  2. Un agent local de sync :
    • fetch origin/main depuis le repo canonique ;
    • réaligne le worktree localhost ;
    • exécute npm ci si nécessaire ;
    • déclenche le redémarrage de lagent Astro local.
  3. Un agent Astro local :
    • démarre astro dev depuis le worktree localhost ;
    • écoute sur 127.0.0.1:4321.
  4. Le site local accessible sur http://127.0.0.1:4321 reflète alors main.

Référence des chemins

Repo canonique

/Volumes/FunIA/dev/archicratie-edition/site

Worktree localhost

/Users/s-funia/ops-local/archicratie/localhost-worktree

Ops local

/Users/s-funia/ops-local/archicratie

Scripts principaux

/Users/s-funia/ops-local/archicratie/auto-sync-localhost.sh
/Users/s-funia/ops-local/archicratie/run-astro-localhost.sh
/Users/s-funia/ops-local/archicratie/doctor-localhost.sh
/Users/s-funia/ops-local/archicratie/install-localhost-sync.sh

Logs ops

/Users/s-funia/ops-local/archicratie/logs/auto-sync-localhost.log
/Users/s-funia/ops-local/archicratie/logs/astro-localhost.log

État du dernier sync

/Users/s-funia/ops-local/archicratie/last-sync.env

LaunchAgents

~/Library/LaunchAgents/me.archicratie.localhost-sync.plist
~/Library/LaunchAgents/me.archicratie.localhost-astro.plist

Logs launchd

~/Library/Logs/archicratie-localhost-sync.out.log
~/Library/Logs/archicratie-localhost-sync.err.log
~/Library/Logs/archicratie-localhost-astro.out.log
~/Library/Logs/archicratie-localhost-astro.err.log

Architecture retenue

1. Le repo canonique

Le repo canonique reste la source locale de travail :

cd /Volumes/FunIA/dev/archicratie-edition/site

Cest ici quon fait :

  • création de branches ;
  • développement ;
  • tests manuels de nouvelles fonctionnalités ;
  • commits ;
  • pushes ;
  • PR.

2. Le worktree localhost

Le localhost ne tourne pas depuis le repo canonique.
Il tourne depuis un worktree dédié :

cd ~/ops-local/archicratie/localhost-worktree
git branch --show-current

Branche attendue :

localhost-sync

Ce worktree suit origin/main via le script dauto-sync.

3. Le dossier ops local

Les scripts dexploitation ne doivent pas être mis dans le repo, ni sur un volume externe soumis à des restrictions de lancement.
Ils sont placés sous HOME :

~/ops-local/archicratie

Motif :

  • compatibilité avec launchd ;
  • logs persistants ;
  • visibilité claire ;
  • indépendance du dépôt.

Pourquoi les scripts et le worktree localhost ne sont plus sur /Volumes/...

Deux difficultés réelles ont été rencontrées.

1. Exécution LaunchAgent depuis un volume externe

Erreur observée :

/bin/bash: /Volumes/FunIA/dev/_ops-local/archicratie/auto-sync-localhost.sh: Operation not permitted

Conclusion :

  • le LaunchAgent peut échouer si le script est lancé depuis un chemin sur volume externe ;
  • le plus robuste est de placer les scripts ops sous HOME.

2. Exécution Astro depuis lancien localhost sous /Volumes/...

Erreur observée :

Error: EPERM: operation not permitted, open '/Volumes/FunIA/dev/archicratie-localhost/node_modules/astro/bin/astro.mjs'

Conclusion :

  • lancien localhost situé sur /Volumes/FunIA/dev/archicratie-localhost nest plus une base fiable pour lexploitation automatisée ;
  • le worktree localhost doit lui aussi être placé sous HOME.

Donc :

  • bon choix : ~/ops-local/archicratie
  • mauvais choix : /Volumes/FunIA/dev/_ops-local/...
  • ancien chemin obsolète : /Volumes/FunIA/dev/archicratie-localhost

Rôle exact du script auto-sync-localhost.sh

Le script a quatre responsabilités :

  1. Vérifier lenvironnement

    • git
    • bash
    • node
    • npm
  2. Garantir le runtime Node

    • Node 22.x
    • npm 10.x
  3. Réaligner le worktree localhost

    • fetch du repo canonique ;
    • sassurer que le worktree localhost existe ;
    • checkout localhost-sync ;
    • reset hard sur origin/main ;
    • clean si nécessaire ;
    • npm ci si nécessaire.
  4. Déclencher le redémarrage dAstro

    • relancer lagent LaunchAgent Astro ;
    • laisser run-astro-localhost.sh porter le démarrage réel du serveur.

Rôle exact du script run-astro-localhost.sh

Ce script a une responsabilité unique :

  • démarrer astro dev depuis le worktree localhost ;
  • sur 127.0.0.1:4321 ;
  • avec le bon runtime Node ;
  • en produisant les logs Astro dédiés.

Il ne doit jamais démarrer depuis le repo canonique.


Rôle exact du script doctor-localhost.sh

Le doctor sert à produire un diagnostic lisible et opératoire sur :

  • le runtime Node ;
  • les LaunchAgents ;
  • le worktree localhost ;
  • lalignement sur origin/main ;
  • létat du serveur Astro ;
  • la réponse HTTP de localhost:4321 ;
  • les fichiers détat et les logs.

Cest la commande de référence pour savoir si linstallation est saine.


Rôle exact du script install-localhost-sync.sh

Le script dinstallation sert à reconstruire proprement toute larchitecture locale :

  • écrire ou réécrire auto-sync-localhost.sh ;
  • écrire ou réécrire run-astro-localhost.sh ;
  • écrire ou réécrire les deux LaunchAgents ;
  • recharger les LaunchAgents ;
  • exécuter doctor-localhost.sh en fin dinstallation.

Cest la commande de réinstallation standard après oubli, casse, dérive ou changement de configuration.


Runtime Node requis

Le projet exige :

{
  "node": ">=22 <23",
  "npm": ">=10 <11"
}

Le runtime retenu localement est donc :

/opt/homebrew/opt/node@22/bin/node
/opt/homebrew/opt/node@22/bin/npm

Vérification :

"$(brew --prefix node@22)/bin/node" -v
"$(brew --prefix node@22)/bin/npm" -v

Résultat attendu :

v22.x
10.x

LaunchAgents

Larchitecture finale repose sur deux LaunchAgents, avec des responsabilités distinctes.

1. LaunchAgent sync

Fichier :

~/Library/LaunchAgents/me.archicratie.localhost-sync.plist

Rôle :

  • réaligner périodiquement le worktree localhost sur origin/main ;
  • relancer lagent Astro si nécessaire.

2. LaunchAgent Astro

Fichier :

~/Library/LaunchAgents/me.archicratie.localhost-astro.plist

Rôle :

  • exécuter run-astro-localhost.sh ;
  • lancer astro dev depuis le worktree localhost.

Contenu de référence du LaunchAgent sync

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
  <dict>
    <key>Label</key>
    <string>me.archicratie.localhost-sync</string>

    <key>ProgramArguments</key>
    <array>
      <string>/bin/bash</string>
      <string>/Users/s-funia/ops-local/archicratie/auto-sync-localhost.sh</string>
    </array>

    <key>RunAtLoad</key>
    <true/>

    <key>StartInterval</key>
    <integer>60</integer>

    <key>WorkingDirectory</key>
    <string>/Users/s-funia</string>

    <key>EnvironmentVariables</key>
    <dict>
      <key>HOME</key>
      <string>/Users/s-funia</string>
      <key>PATH</key>
      <string>/opt/homebrew/opt/node@22/bin:/opt/homebrew/bin:/usr/local/bin:/usr/bin:/bin:/usr/sbin:/sbin</string>
      <key>LANG</key>
      <string>fr_FR.UTF-8</string>
      <key>LC_ALL</key>
      <string>fr_FR.UTF-8</string>
    </dict>

    <key>StandardOutPath</key>
    <string>/Users/s-funia/Library/Logs/archicratie-localhost-sync.out.log</string>

    <key>StandardErrorPath</key>
    <string>/Users/s-funia/Library/Logs/archicratie-localhost-sync.err.log</string>
  </dict>
</plist>

Contenu de référence du LaunchAgent Astro

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
  <dict>
    <key>Label</key>
    <string>me.archicratie.localhost-astro</string>

    <key>ProgramArguments</key>
    <array>
      <string>/bin/bash</string>
      <string>/Users/s-funia/ops-local/archicratie/run-astro-localhost.sh</string>
    </array>

    <key>RunAtLoad</key>
    <true/>

    <key>KeepAlive</key>
    <false/>

    <key>WorkingDirectory</key>
    <string>/Users/s-funia</string>

    <key>EnvironmentVariables</key>
    <dict>
      <key>HOME</key>
      <string>/Users/s-funia</string>
      <key>PATH</key>
      <string>/opt/homebrew/opt/node@22/bin:/opt/homebrew/bin:/usr/local/bin:/usr/bin:/bin:/usr/sbin:/sbin</string>
      <key>LANG</key>
      <string>fr_FR.UTF-8</string>
      <key>LC_ALL</key>
      <string>fr_FR.UTF-8</string>
    </dict>

    <key>StandardOutPath</key>
    <string>/Users/s-funia/Library/Logs/archicratie-localhost-astro.out.log</string>

    <key>StandardErrorPath</key>
    <string>/Users/s-funia/Library/Logs/archicratie-localhost-astro.err.log</string>
  </dict>
</plist>

Installation / réinstallation des LaunchAgents

Vérifier les plists

plutil -lint ~/Library/LaunchAgents/me.archicratie.localhost-sync.plist
plutil -lint ~/Library/LaunchAgents/me.archicratie.localhost-astro.plist

Recharger proprement

launchctl bootout "gui/$(id -u)" ~/Library/LaunchAgents/me.archicratie.localhost-sync.plist 2>/dev/null || true
launchctl bootout "gui/$(id -u)" ~/Library/LaunchAgents/me.archicratie.localhost-astro.plist 2>/dev/null || true

launchctl bootstrap "gui/$(id -u)" ~/Library/LaunchAgents/me.archicratie.localhost-sync.plist
launchctl bootstrap "gui/$(id -u)" ~/Library/LaunchAgents/me.archicratie.localhost-astro.plist

launchctl kickstart -k "gui/$(id -u)/me.archicratie.localhost-sync"
launchctl kickstart -k "gui/$(id -u)/me.archicratie.localhost-astro"

Inspecter létat

launchctl print "gui/$(id -u)/me.archicratie.localhost-sync" | sed -n '1,160p'
launchctl print "gui/$(id -u)/me.archicratie.localhost-astro" | sed -n '1,160p'

État attendu :

  • pas derreur Operation not permitted ;
  • pas derreur EX_CONFIG ;
  • le LaunchAgent sync tourne périodiquement ;
  • le LaunchAgent Astro peut être vu comme running, spawn scheduled ou not running selon le moment dobservation ;
  • létat réel de vérité reste le doctor et la réponse HTTP sur 4321.

Vérifications de bon fonctionnement

1. Vérifier que le worktree suit bien origin/main

git -C ~/ops-local/archicratie/localhost-worktree rev-parse HEAD
git -C /Volumes/FunIA/dev/archicratie-edition/site ls-remote origin refs/heads/main

Les deux SHA doivent être identiques.

2. Vérifier la branche du worktree localhost

git -C ~/ops-local/archicratie/localhost-worktree branch --show-current

Résultat attendu :

localhost-sync

3. Vérifier le dernier état sync

cat ~/ops-local/archicratie/last-sync.env

Exemple attendu :

LAST_SYNC_AT="2026-03-16 20:29:43"
LAST_SYNC_SHA="a1bfbf4405d1342c635caec5b219c14b83b36d5e"
LAST_SYNC_STATUS="noop"

4. Vérifier les logs de sync

tail -n 120 ~/ops-local/archicratie/logs/auto-sync-localhost.log

5. Vérifier les logs Astro

tail -n 120 ~/ops-local/archicratie/logs/astro-localhost.log

6. Vérifier quAstro écoute bien sur 4321

lsof -nP -iTCP:4321 -sTCP:LISTEN

7. Vérifier le processus Astro exact

PID="$(lsof -tiTCP:4321 -sTCP:LISTEN | head -n 1)"
ps -p "$PID" -o pid=,command=
lsof -a -p "$PID" -d cwd

Attendu :

  • commande contenant astro dev
  • cwd = ~/ops-local/archicratie/localhost-worktree

8. Vérifier le contenu servi

Exemple :

curl -s http://127.0.0.1:4321/archicrat-ia/prologue/ | grep -n "taxe Zucman"

Le texte renvoyé doit correspondre à la version attendue sur main.

9. Vérifier globalement toute linstallation

~/ops-local/archicratie/doctor-localhost.sh

Verdict attendu :

✅ aucun problème bloquant détecté
✅ aucun avertissement

Interprétation des statuts

status=updated

Le worktree localhost a été réaligné sur un nouveau SHA ou nettoyé, puis lagent Astro a été relancé.

status=noop

Le worktree localhost était déjà aligné et le serveur local tournait correctement.
Aucun changement de contenu nétait nécessaire.


Usage normal au quotidien

Cas A — travail produit / publié

Quand on veut simplement consulter localement létat réel de main :

  • on laisse tourner les LaunchAgents ;
  • on consulte http://127.0.0.1:4321.

Dans ce mode, le localhost doit être considéré comme :

un miroir local exécutable de origin/main.

Cas B — développement de nouvelles fonctionnalités

Quand on veut modifier du code, tester un comportement, créer une branche :

cd /Volumes/FunIA/dev/archicratie-edition/site
git switch -c feat/ma-branche
npm run dev

Dans ce mode, on travaille dans le repo canonique, pas dans le worktree localhost.


Règle dor

Il existe désormais deux usages distincts :

1. Voir ce qui est réellement sur main

Utiliser :

http://127.0.0.1:4321

qui sert depuis :

~/ops-local/archicratie/localhost-worktree

2. Développer / tester du neuf

Utiliser :

/Volumes/FunIA/dev/archicratie-edition/site

avec branche locale, commandes manuelles, tests de dev.


Ce quil ne faut pas faire

Ne pas développer dans le worktree localhost

Le worktree localhost est un miroir piloté.
Il peut être reset automatiquement.

Donc :

  • pas de commits dedans ;
  • pas de modifications de fond dedans ;
  • pas de dev feature dedans.

Ne pas utiliser le repo canonique comme miroir auto-sync

Sinon on mélange :

  • environnement de dev ;
  • état publié ;
  • serveur local permanent.

Ne pas conserver lancien chemin localhost comme référence

Le chemin :

/Volumes/FunIA/dev/archicratie-localhost

nest plus la référence opérationnelle.
Il est obsolète pour cette architecture.

Ne pas déplacer les scripts ops sur un volume externe

Sinon launchd peut échouer avec :

Operation not permitted

Procédure de redémarrage machine

Après reboot, le comportement attendu est :

  1. les LaunchAgents se rechargent ;
  2. le script dauto-sync sexécute ;
  3. le worktree localhost est réaligné ;
  4. Astro redémarre sur 127.0.0.1:4321.

Vérification rapide après reboot

launchctl print "gui/$(id -u)/me.archicratie.localhost-sync" | sed -n '1,120p'
launchctl print "gui/$(id -u)/me.archicratie.localhost-astro" | sed -n '1,120p'
tail -n 80 ~/ops-local/archicratie/logs/auto-sync-localhost.log
lsof -nP -iTCP:4321 -sTCP:LISTEN

Procédure de secours manuelle

Forcer un resync

~/ops-local/archicratie/auto-sync-localhost.sh

Forcer un diagnostic complet

~/ops-local/archicratie/doctor-localhost.sh

Réinstaller tout le dispositif

~/ops-local/archicratie/install-localhost-sync.sh

Symptômes fréquents et diagnostic

Symptôme 1 — localhost ne montre pas les dernières modifs

Vérifier :

git -C ~/ops-local/archicratie/localhost-worktree rev-parse HEAD
git -C /Volumes/FunIA/dev/archicratie-edition/site ls-remote origin refs/heads/main

Si les SHA diffèrent :

  • le sync na pas tourné ;
  • ou le LaunchAgent sync ne sexécute pas.

Symptôme 2 — SHA bon, mais contenu web pas à jour

Vérifier :

lsof -nP -iTCP:4321 -sTCP:LISTEN
PID="$(lsof -tiTCP:4321 -sTCP:LISTEN | head -n 1)"
ps -p "$PID" -o pid=,command=
lsof -a -p "$PID" -d cwd

Cause probable :

  • Astro tourne depuis le mauvais dossier ;
  • ou un ancien astro dev manuel tourne encore ailleurs.

Symptôme 3 — LaunchAgent présent, mais rien ne tourne

Vérifier :

tail -n 80 ~/Library/Logs/archicratie-localhost-sync.err.log
tail -n 80 ~/Library/Logs/archicratie-localhost-astro.err.log
tail -n 120 ~/ops-local/archicratie/logs/auto-sync-localhost.log
tail -n 120 ~/ops-local/archicratie/logs/astro-localhost.log

Causes possibles :

  • mauvais PATH ;
  • Node 22 absent ;
  • script non exécutable ;
  • erreur dans un plist ;
  • ancien chemin encore référencé ;
  • worktree localhost absent ;
  • node_modules non installés dans le worktree.

Symptôme 4 — erreur Operation not permitted

Cause probable :

  • script ops ou agent lancé depuis un chemin sous /Volumes/....

Résolution :

  • conserver les scripts sous ~/ops-local/archicratie.

Symptôme 5 — erreur EBADENGINE

Cause probable :

  • Node 23 utilisé à la place de Node 22.

Résolution :

  • forcer PATH avec node@22 dans les LaunchAgents et dans les scripts.

Symptôme 6 — erreur EPERM sur astro.mjs

Cause probable :

  • Astro essaie encore de démarrer depuis lancien emplacement localhost ;
  • ou une incohérence persiste dans les chemins des scripts.

Résolution :

  • vérifier que tous les scripts pointent vers ~/ops-local/archicratie/localhost-worktree ;
  • vérifier que doctor-localhost.sh confirme le bon cwd ;
  • réinstaller via install-localhost-sync.sh.

Commandes de contrôle essentielles

État Git

git -C ~/ops-local/archicratie/localhost-worktree rev-parse HEAD
git -C /Volumes/FunIA/dev/archicratie-edition/site ls-remote origin refs/heads/main
git -C ~/ops-local/archicratie/localhost-worktree branch --show-current

État LaunchAgents

launchctl print "gui/$(id -u)/me.archicratie.localhost-sync" | sed -n '1,160p'
launchctl print "gui/$(id -u)/me.archicratie.localhost-astro" | sed -n '1,160p'

État logs

tail -n 120 ~/ops-local/archicratie/logs/auto-sync-localhost.log
tail -n 120 ~/ops-local/archicratie/logs/astro-localhost.log
tail -n 80 ~/Library/Logs/archicratie-localhost-sync.err.log
tail -n 80 ~/Library/Logs/archicratie-localhost-astro.err.log

État serveur

lsof -nP -iTCP:4321 -sTCP:LISTEN
PID="$(lsof -tiTCP:4321 -sTCP:LISTEN | head -n 1)"
ps -p "$PID" -o pid=,command=
lsof -a -p "$PID" -d cwd
curl -I -s http://127.0.0.1:4321/ | head -n 5

Vérification contenu

curl -s http://127.0.0.1:4321/archicrat-ia/prologue/ | grep -n "taxe Zucman"

Décision dexploitation finale

La politique retenue est la suivante :

  • repo canonique = espace de développement ;
  • worktree localhost = miroir automatique de main ;
  • ops sous HOME = scripts, logs, automation ;
  • LaunchAgent sync = réalignement périodique ;
  • LaunchAgent astro = exécution dAstro ;
  • Astro local = lancé uniquement depuis le worktree localhost.

Cette séparation rend le dispositif plus :

  • lisible ;
  • robuste ;
  • opérable ;
  • antifragile.

Résumé opératoire

Pour voir la vérité de main

Ouvrir :

http://127.0.0.1:4321

Le serveur doit provenir de :

~/ops-local/archicratie/localhost-worktree

Pour développer

Travailler dans :

/Volumes/FunIA/dev/archicratie-edition/site

avec tes commandes habituelles.

Pour réparer vite

~/ops-local/archicratie/doctor-localhost.sh
~/ops-local/archicratie/auto-sync-localhost.sh

Pour tout réinstaller proprement

~/ops-local/archicratie/install-localhost-sync.sh

Mémoire courte

Si un jour plus rien nest clair, repartir de ces six commandes :

git -C ~/ops-local/archicratie/localhost-worktree rev-parse HEAD
git -C /Volumes/FunIA/dev/archicratie-edition/site ls-remote origin refs/heads/main
launchctl print "gui/$(id -u)/me.archicratie.localhost-sync" | sed -n '1,120p'
launchctl print "gui/$(id -u)/me.archicratie.localhost-astro" | sed -n '1,120p'
lsof -nP -iTCP:4321 -sTCP:LISTEN
~/ops-local/archicratie/doctor-localhost.sh

Et lire :

tail -n 120 ~/ops-local/archicratie/logs/auto-sync-localhost.log
tail -n 120 ~/ops-local/archicratie/logs/astro-localhost.log

Statut actuel visé

Quand tout fonctionne correctement :

  • ~/ops-local/archicratie/localhost-worktree pointe sur le même SHA que origin/main ;
  • astro dev écoute sur 127.0.0.1:4321 ;
  • son cwd est ~/ops-local/archicratie/localhost-worktree ;
  • le contenu servi correspond au contenu mergé sur main.

Cest létat de référence à préserver.