diff --git a/docs/OPS-LOCALHOST-AUTO-SYNC.md b/docs/OPS-LOCALHOST-AUTO-SYNC.md
new file mode 100644
index 0000000..c426481
--- /dev/null
+++ b/docs/OPS-LOCALHOST-AUTO-SYNC.md
@@ -0,0 +1,964 @@
+# 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.
\ No newline at end of file
diff --git a/docs/START-HERE.md b/docs/START-HERE.md
index 6e4f949..003a256 100644
--- a/docs/START-HERE.md
+++ b/docs/START-HERE.md
@@ -1,51 +1,147 @@
-# START-HERE — Archicratie / Édition Web (v2)
-> Onboarding + exploitation “nickel chrome” (DEV → Gitea → CI → Release → Blue/Green → Edge/SSO)
+# START-HERE — Archicratie / Édition Web (v3)
+> Onboarding + exploitation “nickel chrome” (DEV → Gitea → CI → Release → Blue/Green → Edge/SSO → localhost auto-sync)
## 0) TL;DR (la règle d’or)
-- **Gitea = source canonique**.
-- **main est protégé** : toute modification passe par **branche → PR → CI → merge**.
-- **Le NAS n’est pas la source** : si un hotfix est fait sur NAS, on **backporte** via PR immédiatement.
-- **Le site est statique Astro** : la prod sert du HTML (nginx), l’accès est contrôlé au niveau reverse-proxy (Traefik + Authelia).
+
+- **Gitea = source canonique**.
+- **`main` est protégée** : toute modification passe par **branche → PR → CI → merge**.
+- **Le NAS n’est pas la source** : si un hotfix est fait sur NAS, il doit être **backporté immédiatement** via PR.
+- **Le site est statique Astro** : la prod sert du HTML via nginx ; l’accès est contrôlé au niveau reverse-proxy (Traefik + Authelia).
+- **Le localhost automatique n’est pas le repo de dev** : il tourne depuis un **worktree dédié**, synchronisé sur `origin/main`.
+
+---
## 1) Architecture mentale (ultra simple)
-- **DEV (Mac Studio)** : édition + tests + commit + push
-- **Gitea** : dépôt canon + PR + CI (CI.yaml)
-- **NAS (DS220+)** : déploiement “blue/green”
- - `web_blue` (staging upstream) → `127.0.0.1:8081`
- - `web_green` (live upstream) → `127.0.0.1:8082`
-- **Edge (Traefik)** : route les hosts
+
+- **DEV canonique (Mac Studio)** : édition, dev, tests, commits, pushes
+- **Gitea** : dépôt canonique, PR, CI, workflows éditoriaux
+- **NAS (DS220+)** : déploiement blue/green
+ - `web_blue` → staging upstream → `127.0.0.1:8081`
+ - `web_green` → live upstream → `127.0.0.1:8082`
+- **Edge (Traefik)** : routage des hosts
- `staging.archicratie...` → 8081
- `archicratie...` → 8082
- **Authelia** devant, via middleware `chain-auth@file`
+- **Localhost auto-sync**
+ - un **repo canonique de développement**
+ - un **worktree localhost miroir de `origin/main`**
+ - un **agent de sync**
+ - un **agent Astro**
+
+---
## 2) Répertoires & conventions (repo)
+
### 2.1 Contenu canon (édition)
-- `src/content/**` : contenu MD / MDX canon (Astro content collections)
-- `src/pages/**` : routes Astro (index, [...slug], etc.)
-- `src/components/**` : composants UI (SiteNav, TOC, SidePanel, etc.)
-- `src/layouts/**` : layouts (EditionLayout, SiteLayout)
+
+- `src/content/**` : contenu MD / MDX canon
+- `src/pages/**` : routes Astro
+- `src/components/**` : composants UI
+- `src/layouts/**` : layouts
- `src/styles/**` : CSS global
### 2.2 Annotations (pré-Édition “tickets”)
+
- `src/annotations//.yml`
- - Exemple : `src/annotations/archicrat-ia/prologue.yml`
-- Objectif : stocker “Références / Médias / Commentaires” par page et par paragraphe (`p-...`).
+- Exemple :
+ `src/annotations/archicrat-ia/prologue.yml`
+
+Objectif :
+stocker “Références / Médias / Commentaires” par page et par paragraphe (`p-...`).
### 2.3 Scripts (tooling / build)
-- `scripts/inject-anchor-aliases.mjs` : injection aliases dans dist
-- `scripts/dedupe-ids-dist.mjs` : retire IDs dupliqués dans dist
-- `scripts/build-para-index.mjs` : index paragraphes (postbuild / predev)
-- `scripts/build-annotations-index.mjs` : index annotations (postbuild / predev)
-- `scripts/check-anchors.mjs` : contrat stabilité d’ancres (CI)
+
+- `scripts/inject-anchor-aliases.mjs` : injection aliases dans `dist`
+- `scripts/dedupe-ids-dist.mjs` : retrait IDs dupliqués
+- `scripts/build-para-index.mjs` : index paragraphes
+- `scripts/build-annotations-index.mjs` : index annotations
+- `scripts/check-anchors.mjs` : contrat stabilité d’ancres
- `scripts/check-annotations*.mjs` : sanity YAML + médias
-> Important : les scripts sont **partie intégrante** de la stabilité (IDs/ancres/indexation).
-> On évite “la magie” : tout est scripté + vérifié.
+> Important : ces scripts ne sont pas accessoires.
+> Ils font partie du contrat de stabilité éditoriale.
-## 3) Workflow Git “pro” (main protégé)
-### 3.1 Cycle standard (toute modif)
-en bash :
+---
+## 3) Les trois espaces à ne jamais confondre
+
+### 3.1 Repo canonique de développement
+
+```text
+/Volumes/FunIA/dev/archicratie-edition/site
+```
+
+Usage :
+
+- développement normal
+- branches de travail
+- nouvelles fonctionnalités
+- corrections manuelles
+- commits
+- pushes
+- PR
+
+### 3.2 Worktree localhost miroir de `main`
+
+```text
+/Users/s-funia/ops-local/archicratie/localhost-worktree
+```
+
+Branche attendue :
+
+```text
+localhost-sync
+```
+
+Usage :
+
+- exécuter le localhost automatique
+- refléter `origin/main`
+- ne jamais servir d’espace de développement
+
+### 3.3 Ops local hors repo
+
+```text
+/Users/s-funia/ops-local/archicratie
+```
+
+Usage :
+
+- scripts d’exploitation
+- état
+- logs
+- automatisation `launchd`
+
+---
+
+## 4) Pourquoi cette séparation existe
+
+Il ne faut pas utiliser le repo canonique de développement 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.
+
+La séparation retenue est donc :
+
+- **repo canonique** = espace de développement
+- **worktree localhost** = miroir exécutable de `origin/main`
+- **ops local** = scripts et automatisation
+
+C’est cette séparation qui rend le système lisible, robuste et opérable.
+
+---
+
+## 5) Workflow Git “pro” (main protégée)
+
+### 5.1 Cycle standard (toute modif)
+
+```bash
git checkout main
git pull --ff-only
@@ -60,37 +156,48 @@ npm run test:anchors
git add -A
git commit -m "xxx: description claire"
git push -u origin "$BR"
+```
-### 3.2 PR vers main
+### 5.2 PR vers `main`
-Ouvrir PR dans Gitea
+- ouvrir une PR dans Gitea
+- attendre une CI verte
+- merger
+- laisser les workflows faire le reste
-CI doit être verte
+### 5.3 Cas spécial : hotfix prod (NAS)
-Merge PR → main
+On peut faire un hotfix d’urgence côté NAS si nécessaire.
-### 3.3 Cas spécial : hotfix prod (NAS)
+Mais l’état final doit toujours revenir dans Gitea :
-On peut faire un hotfix “urgence” en prod/staging si nécessaire…
+- branche
+- PR
+- CI
+- merge
-MAIS : l’état final doit revenir dans Gitea : branche → PR → CI → merge.
+---
-## 4) Déploiement (NAS) — principe
-### 4.1 Release pack
+## 6) Déploiement (NAS) — principe
-On génère un pack “reproductible” (source + config + scripts) puis on déploie.
+### 6.1 Release pack
-### 4.2 Blue/Green
+On génère un pack reproductible, puis on déploie.
-web_blue = staging upstream (8081)
+### 6.2 Blue/Green
-web_green = live upstream (8082)
+- `web_blue` = staging (`8081`)
+- `web_green` = live (`8082`)
-Edge Traefik sélectionne quel host pointe vers quel upstream.
+Le reverse-proxy choisit l’upstream selon le host demandé.
-## 5) Check-list “≤ 10 commandes” (happy path complet)
-### 5.1 DEV (Mac)
+---
+## 7) Happy path complet
+
+### 7.1 DEV (Mac)
+
+```bash
git checkout main && git pull --ff-only
git checkout -b chore/my-change-$(date +%Y%m%d)
@@ -99,55 +206,258 @@ rm -rf .astro node_modules/.vite dist
npm run build
npm run test:anchors
npm run dev
+```
-### 5.2 Push + PR
+### 7.2 Push + PR
+```bash
git add -A
git commit -m "chore: my change"
git push -u origin chore/my-change-YYYYMMDD
-# ouvrir PR dans Gitea
+```
-### 5.3 Déploiement NAS (résumé)
+Puis ouvrir la PR dans Gitea.
-Voir docs/runbooks/DEPLOY-BLUE-GREEN.md.
+### 7.3 Déploiement NAS
-## 6) Problèmes “classiques” + diagnostic rapide
-### 6.1 “Le staging ne ressemble pas au local”
+Voir :
-# Comparer upstream direct 8081 vs 8082 :
+```text
+docs/runbooks/DEPLOY-BLUE-GREEN.md
+```
+---
+
+## 8) Localhost auto-sync — ce qu’il faut retenir
+
+Le localhost automatique sert à voir **la vérité de `main`**, pas à développer du neuf.
+
+### 8.1 Scripts principaux
+
+#### Script de sync
+
+```text
+~/ops-local/archicratie/auto-sync-localhost.sh
+```
+
+Rôle :
+
+- fetch `origin/main`
+- réaligner le worktree localhost
+- lancer `npm ci` si besoin
+- redéclencher l’agent Astro si nécessaire
+
+#### Script Astro
+
+```text
+~/ops-local/archicratie/run-astro-localhost.sh
+```
+
+Rôle :
+
+- lancer `astro dev`
+- depuis le bon worktree
+- avec le bon runtime Node
+- sur `127.0.0.1:4321`
+
+> Oui : ce script est nécessaire.
+> Il isole proprement le lancement du serveur Astro dans un contexte `launchd` stable.
+
+### 8.2 LaunchAgents
+
+#### Agent sync
+
+```text
+~/Library/LaunchAgents/me.archicratie.localhost-sync.plist
+```
+
+#### Agent Astro
+
+```text
+~/Library/LaunchAgents/me.archicratie.localhost-astro.plist
+```
+
+### 8.3 Document de référence
+
+Pour tout le détail d’exploitation du localhost automatique, lire :
+
+```text
+docs/OPS-LOCALHOST-AUTO-SYNC.md
+```
+
+---
+
+## 9) Règle d’or : il y a deux usages locaux distincts
+
+### 9.1 Voir ce qui est réellement sur `main`
+
+Utiliser :
+
+```text
+http://127.0.0.1:4321
+```
+
+Ce localhost doit être considéré comme :
+
+**un miroir local exécutable de `origin/main`**
+
+### 9.2 Développer / tester une nouvelle fonctionnalité
+
+Utiliser le repo canonique :
+
+```bash
+cd /Volumes/FunIA/dev/archicratie-edition/site
+npm run dev
+```
+
+Donc :
+
+- **localhost auto-sync** = vérité de `main`
+- **localhost de dev manuel** = expérimentation en cours
+
+Il ne faut pas les confondre.
+
+---
+
+## 10) Ce qu’il ne faut pas faire
+
+### 10.1 Ne pas développer dans le worktree localhost
+
+Le worktree localhost est piloté automatiquement.
+
+Il peut être :
+
+- réaligné
+- nettoyé
+- redémarré
+
+Donc :
+
+- pas de commits dedans
+- pas de dev feature dedans
+- pas d’expérimentation de fond dedans
+
+### 10.2 Ne pas utiliser le repo canonique comme miroir auto-sync
+
+Sinon on mélange :
+
+- espace de dev
+- état publié
+- serveur local permanent
+
+### 10.3 Ne pas remettre les scripts ops sur un volume externe
+
+Les scripts d’ops doivent rester sous `HOME`.
+
+Le fait de les mettre sous `/Volumes/...` a déjà provoqué des erreurs du type :
+
+```text
+Operation not permitted
+```
+
+### 10.4 Ne pas supprimer `run-astro-localhost.sh`
+
+Ce script fait partie de l’architecture actuelle.
+Le supprimer reviendrait à réintroduire le flou entre sync Git et exécution d’Astro.
+
+---
+
+## 11) Commandes de contrôle essentielles
+
+### 11.1 État global
+
+```bash
+~/ops-local/archicratie/doctor-localhost.sh
+```
+
+### 11.2 É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
+```
+
+### 11.3 É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'
+```
+
+### 11.4 É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
+```
+
+### 11.5 É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
+```
+
+### 11.6 Vérification contenu
+
+```bash
+curl -s http://127.0.0.1:4321/archicrat-ia/prologue/ | grep -n "taxe Zucman"
+```
+
+---
+
+## 12) Problèmes classiques + diagnostic
+
+### 12.1 “Le staging ne ressemble pas au local”
+
+Comparer les upstream directs :
+
+```bash
curl -sS http://127.0.0.1:8081/ | head -n 2
curl -sS http://127.0.0.1:8082/ | head -n 2
+```
-# Vérifier quel routeur edge répond (header diag) :
+Vérifier le routeur edge :
+```bash
curl -sSI -H 'Host: staging.archicratie.trans-hands.synology.me' http://127.0.0.1:18080/ \
| grep -iE 'HTTP/|location:|x-archi-router'
+```
-# Lire docs/runbooks/EDGE-TRAEFIK.md.
+Voir :
-### 6.2 Canonical incorrect (localhost en prod)
+```text
+docs/runbooks/EDGE-TRAEFIK.md
+```
-Cause racine : site dans Astro = PUBLIC_SITE non injecté au build.
+### 12.2 Canonical incorrect
-Fix canonique : voir docs/runbooks/ENV-PUBLIC_SITE.md.
+Cause probable : `PUBLIC_SITE` mal injecté au build.
Test :
+```bash
curl -sS http://127.0.0.1:8082/ | grep -oE 'rel="canonical" href="[^"]+"' | head -1
+```
-### 6.3 Contrat “anchors” en échec après migration d’URL
+Voir :
-Quand on déplace des routes (ex: /archicratie/archicrat-ia/* → /archicrat-ia/*), le test d’ancres peut échouer même si les IDs n’ont pas changé, car les pages ont changé de chemin.
+```text
+docs/runbooks/ENV-PUBLIC_SITE.md
+```
-# Procédure safe :
+### 12.3 Contrat anchors en échec après migration d’URL
-Backup baseline :
+Procédure safe :
+```bash
cp -a tests/anchors-baseline.json /tmp/anchors-baseline.json.bak.$(date +%F-%H%M%S)
-Mettre à jour les clés (chemins) sans toucher aux IDs :
-
node - <<'NODE'
import fs from 'fs';
const p='tests/anchors-baseline.json';
@@ -161,16 +471,213 @@ fs.writeFileSync(p, JSON.stringify(out,null,2)+'\n');
console.log('updated keys:', Object.keys(j).length, '->', Object.keys(out).length);
NODE
-Re-run :
-
npm run test:anchors
+```
-## 7) Ce que l’étape 9 doit faire (orientation)
+### 12.4 “Le localhost auto-sync ne montre pas les dernières modifs”
-Stabiliser le pipeline “tickets → YAML annotations”
+Commande réflexe :
-Formaliser la spec YAML + merge + anti-doublon (voir docs/EDITORIAL-ANNOTATIONS-SPEC.md)
+```bash
+~/ops-local/archicratie/doctor-localhost.sh
+```
-Durcir l’onboarding (ce START-HERE + runbooks)
+Puis :
-Éviter les régressions par tests (anchors / annotations / smoke)
\ No newline at end of file
+```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 l’agent sync a un problème
+
+### 12.5 “Le SHA est bon mais le contenu web est faux”
+
+Vérifier quel Astro écoute réellement :
+
+```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
+```
+
+Attendu :
+- commande contenant `astro dev`
+- cwd = `~/ops-local/archicratie/localhost-worktree`
+
+### 12.6 Erreur `EBADENGINE`
+
+Cause probable :
+- Node 23 utilisé au lieu de Node 22
+
+Résolution :
+- forcer `node@22` dans les scripts et les LaunchAgents
+
+### 12.7 Erreur `Operation not permitted`
+
+Cause probable :
+- scripts d’ops placés sous `/Volumes/...`
+
+Résolution :
+- garder les scripts sous :
+
+```text
+~/ops-local/archicratie
+```
+
+### 12.8 Erreur `EPERM` sur `astro.mjs`
+
+Cause probable :
+- ancien worktree sur volume externe
+- ancien chemin résiduel
+- Astro lancé depuis un mauvais emplacement
+
+Résolution :
+- worktree localhost sous :
+
+```text
+~/ops-local/archicratie/localhost-worktree
+```
+
+- scripts cohérents avec ce chemin
+- réinstallation propre via :
+
+```bash
+~/ops-local/archicratie/install-localhost-sync.sh
+```
+
+---
+
+## 13) Redémarrage machine
+
+Après reboot, le comportement attendu est :
+
+1. le LaunchAgent sync se recharge
+2. le LaunchAgent Astro se recharge
+3. le worktree localhost est réaligné
+4. Astro redémarre sur `127.0.0.1:4321`
+
+### Vérification rapide après reboot
+
+```bash
+~/ops-local/archicratie/doctor-localhost.sh
+```
+
+Si nécessaire :
+
+```bash
+~/ops-local/archicratie/install-localhost-sync.sh
+```
+
+---
+
+## 14) Procédure de secours manuelle
+
+### Forcer un sync
+
+```bash
+~/ops-local/archicratie/auto-sync-localhost.sh
+```
+
+### Réinstaller proprement le dispositif local
+
+```bash
+~/ops-local/archicratie/install-localhost-sync.sh
+```
+
+### Diagnostic complet
+
+```bash
+~/ops-local/archicratie/doctor-localhost.sh
+```
+
+---
+
+## 15) 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 Git
+- **LaunchAgent Astro** = exécution stable du serveur local
+- **Astro local** = lancé uniquement depuis le worktree localhost
+
+Cette séparation rend le dispositif plus :
+
+- lisible
+- robuste
+- opérable
+- antifragile
+
+---
+
+## 16) 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
+/Users/s-funia/ops-local/archicratie/localhost-worktree
+```
+
+### Pour développer
+
+Travailler dans :
+
+```text
+/Volumes/FunIA/dev/archicratie-edition/site
+```
+
+avec les commandes habituelles.
+
+### Pour réparer vite
+
+```bash
+~/ops-local/archicratie/doctor-localhost.sh
+~/ops-local/archicratie/auto-sync-localhost.sh
+```
+
+---
+
+## 17) Mémoire courte
+
+Si un jour plus rien n’est clair, repartir de ces commandes :
+
+```bash
+~/ops-local/archicratie/doctor-localhost.sh
+git -C ~/ops-local/archicratie/localhost-worktree rev-parse HEAD
+git -C /Volumes/FunIA/dev/archicratie-edition/site ls-remote origin refs/heads/main
+lsof -nP -iTCP:4321 -sTCP:LISTEN
+```
+
+Puis lire :
+
+```bash
+tail -n 120 ~/ops-local/archicratie/logs/auto-sync-localhost.log
+tail -n 120 ~/ops-local/archicratie/logs/astro-localhost.log
+```
+
+---
+
+## 18) Statut actuel visé
+
+Quand tout fonctionne correctement :
+
+- le worktree localhost 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.
\ No newline at end of file