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

964 lines
22 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# 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
```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
```
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é :
```bash
cd ~/ops-local/archicratie/localhost-worktree
git branch --show-current
```
Branche attendue :
```text
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` :
```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 lancien 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 :
- 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 :
```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
Larchitecture 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 lagent 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
<?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
<?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
```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 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`
```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 quAstro é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 linstallation
```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 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 :
```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 dor
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 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 :
```text
/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 :
```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 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
```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 na pas tourné ;
- ou le LaunchAgent sync ne sexé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 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
```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 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 :
```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 nest 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`.
Cest létat de référence à préserver.