# OPS — Localhost auto-sync ## Objet Ce document fige l’architecture locale qui permet de garder le **localhost éditorial** aligné sur `origin/main`, sans dépendre de la mémoire de l’opé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 ; - l’exploitation doit rester simple à diagnostiquer ; - l’installation doit pouvoir être **réappliquée proprement** après oubli, incident, ou redémarrage machine. --- ## Principes L’architecture 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 d’exploitation, 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 l’espace de développement. --- ## Vue d’ensemble Flux logique : 1. `origin/main` avance après merge d’une 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 l’agent 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 ```text /Volumes/FunIA/dev/archicratie-edition/site ``` ### Worktree localhost ```text /Users/s-funia/ops-local/archicratie/localhost-worktree ``` ### Ops local ```text /Users/s-funia/ops-local/archicratie ``` ### Scripts principaux ```text /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 ```text /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 ```text /Users/s-funia/ops-local/archicratie/last-sync.env ``` ### LaunchAgents ```text ~/Library/LaunchAgents/me.archicratie.localhost-sync.plist ~/Library/LaunchAgents/me.archicratie.localhost-astro.plist ``` ### Logs launchd ```text ~/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 : ```bash cd /Volumes/FunIA/dev/archicratie-edition/site ``` C’est ici qu’on 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é : ```bash cd ~/ops-local/archicratie/localhost-worktree git branch --show-current ``` Branche attendue : ```text localhost-sync ``` Ce worktree suit `origin/main` via le script d’auto-sync. ### 3. Le dossier ops local Les scripts d’exploitation ne doivent pas être mis dans le repo, ni sur un volume externe soumis à des restrictions de lancement. Ils sont placés sous `HOME` : ```text ~/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 : ```text /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 l’ancien localhost sous `/Volumes/...` Erreur observée : ```text Error: EPERM: operation not permitted, open '/Volumes/FunIA/dev/archicratie-localhost/node_modules/astro/bin/astro.mjs' ``` Conclusion : - l’ancien localhost situé sur `/Volumes/FunIA/dev/archicratie-localhost` n’est **plus** une base fiable pour l’exploitation 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 l’environnement** - `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 ; - s’assurer 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 d’Astro** - relancer l’agent 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 ; - l’alignement sur `origin/main` ; - l’état du serveur Astro ; - la réponse HTTP de `localhost:4321` ; - les fichiers d’état et les logs. C’est la **commande de référence** pour savoir si l’installation est saine. --- ## Rôle exact du script `install-localhost-sync.sh` Le script d’installation sert à **reconstruire proprement toute l’architecture 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 d’installation. C’est la **commande de réinstallation standard** après oubli, casse, dérive ou changement de configuration. --- ## Runtime Node requis Le projet exige : ```json { "node": ">=22 <23", "npm": ">=10 <11" } ``` Le runtime retenu localement est donc : ```text /opt/homebrew/opt/node@22/bin/node /opt/homebrew/opt/node@22/bin/npm ``` Vérification : ```bash "$(brew --prefix node@22)/bin/node" -v "$(brew --prefix node@22)/bin/npm" -v ``` Résultat attendu : ```text v22.x 10.x ``` --- ## LaunchAgents L’architecture finale repose sur **deux LaunchAgents**, avec des responsabilités distinctes. ### 1. LaunchAgent sync Fichier : ```text ~/Library/LaunchAgents/me.archicratie.localhost-sync.plist ``` Rôle : - réaligner périodiquement le worktree localhost sur `origin/main` ; - relancer l’agent Astro si nécessaire. ### 2. LaunchAgent Astro Fichier : ```text ~/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 Label me.archicratie.localhost-sync ProgramArguments /bin/bash /Users/s-funia/ops-local/archicratie/auto-sync-localhost.sh RunAtLoad StartInterval 60 WorkingDirectory /Users/s-funia EnvironmentVariables HOME /Users/s-funia PATH /opt/homebrew/opt/node@22/bin:/opt/homebrew/bin:/usr/local/bin:/usr/bin:/bin:/usr/sbin:/sbin LANG fr_FR.UTF-8 LC_ALL fr_FR.UTF-8 StandardOutPath /Users/s-funia/Library/Logs/archicratie-localhost-sync.out.log StandardErrorPath /Users/s-funia/Library/Logs/archicratie-localhost-sync.err.log ``` --- ## Contenu de référence du LaunchAgent Astro ```xml Label me.archicratie.localhost-astro ProgramArguments /bin/bash /Users/s-funia/ops-local/archicratie/run-astro-localhost.sh RunAtLoad KeepAlive WorkingDirectory /Users/s-funia EnvironmentVariables HOME /Users/s-funia PATH /opt/homebrew/opt/node@22/bin:/opt/homebrew/bin:/usr/local/bin:/usr/bin:/bin:/usr/sbin:/sbin LANG fr_FR.UTF-8 LC_ALL fr_FR.UTF-8 StandardOutPath /Users/s-funia/Library/Logs/archicratie-localhost-astro.out.log StandardErrorPath /Users/s-funia/Library/Logs/archicratie-localhost-astro.err.log ``` --- ## Installation / réinstallation des LaunchAgents ### Vérifier les plists ```bash plutil -lint ~/Library/LaunchAgents/me.archicratie.localhost-sync.plist plutil -lint ~/Library/LaunchAgents/me.archicratie.localhost-astro.plist ``` ### Recharger proprement ```bash 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 ```bash 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 d’erreur `Operation not permitted` ; - pas d’erreur `EX_CONFIG` ; - le LaunchAgent sync tourne périodiquement ; - le LaunchAgent Astro peut être vu comme `running`, `spawn scheduled` ou `not running` selon le moment d’observation ; - 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` ```bash 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 ```bash git -C ~/ops-local/archicratie/localhost-worktree branch --show-current ``` Résultat attendu : ```text localhost-sync ``` ### 3. Vérifier le dernier état sync ```bash cat ~/ops-local/archicratie/last-sync.env ``` Exemple attendu : ```text LAST_SYNC_AT="2026-03-16 20:29:43" LAST_SYNC_SHA="a1bfbf4405d1342c635caec5b219c14b83b36d5e" LAST_SYNC_STATUS="noop" ``` ### 4. Vérifier les logs de sync ```bash tail -n 120 ~/ops-local/archicratie/logs/auto-sync-localhost.log ``` ### 5. Vérifier les logs Astro ```bash tail -n 120 ~/ops-local/archicratie/logs/astro-localhost.log ``` ### 6. Vérifier qu’Astro écoute bien sur 4321 ```bash lsof -nP -iTCP:4321 -sTCP:LISTEN ``` ### 7. Vérifier le processus Astro exact ```bash 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 : ```bash 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 l’installation ```bash ~/ops-local/archicratie/doctor-localhost.sh ``` Verdict attendu : ```text ✅ 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 l’agent 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 : ```bash 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 d’or Il existe désormais **deux usages distincts** : ### 1. Voir ce qui est réellement sur `main` Utiliser : ```text http://127.0.0.1:4321 ``` qui sert depuis : ```text ~/ops-local/archicratie/localhost-worktree ``` ### 2. Développer / tester du neuf Utiliser : ```text /Volumes/FunIA/dev/archicratie-edition/site ``` avec branche locale, commandes manuelles, tests de dev. --- ## Ce qu’il 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 l’ancien chemin localhost comme référence Le chemin : ```text /Volumes/FunIA/dev/archicratie-localhost ``` n’est 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 : ```text Operation not permitted ``` --- ## Procédure de redémarrage machine Après reboot, le comportement attendu est : 1. les LaunchAgents se rechargent ; 2. le script d’auto-sync s’exécute ; 3. le worktree localhost est réaligné ; 4. Astro redémarre sur `127.0.0.1:4321`. ### Vérification rapide après reboot ```bash 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 ```bash ~/ops-local/archicratie/auto-sync-localhost.sh ``` ### Forcer un diagnostic complet ```bash ~/ops-local/archicratie/doctor-localhost.sh ``` ### Réinstaller tout le dispositif ```bash ~/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 : ```bash 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 n’a pas tourné ; - ou le LaunchAgent sync ne s’exécute pas. ### Symptôme 2 — SHA bon, mais contenu web pas à jour Vérifier : ```bash 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 : ```bash 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 l’ancien 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 ```bash 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 ```bash 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 ```bash 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 ```bash 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 ```bash curl -s http://127.0.0.1:4321/archicrat-ia/prologue/ | grep -n "taxe Zucman" ``` --- ## Décision d’exploitation 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 d’Astro ; - **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 : ```text http://127.0.0.1:4321 ``` Le serveur doit provenir de : ```text ~/ops-local/archicratie/localhost-worktree ``` ### Pour développer Travailler dans : ```text /Volumes/FunIA/dev/archicratie-edition/site ``` avec tes commandes habituelles. ### Pour réparer vite ```bash ~/ops-local/archicratie/doctor-localhost.sh ~/ops-local/archicratie/auto-sync-localhost.sh ``` ### Pour tout réinstaller proprement ```bash ~/ops-local/archicratie/install-localhost-sync.sh ``` --- ## Mémoire courte Si un jour plus rien n’est clair, repartir de ces six commandes : ```bash 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 : ```bash 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`. C’est l’état de référence à préserver.