# ROADMAP — CI (Gitea Actions Synology) + Ancrages (aliases build-time) But : permettre à un successeur de reprendre sans rien deviner. Ce document décrit : - l’état stable actuel (baseline) - les invariants à ne pas casser - les prochaines étapes “mission principale” (ancrages primaires robustes + CI durable) - la méthode de debug rapide --- ## 0) État actuel (baseline VALIDÉE) ### CI (Gitea Actions) - ✅ Job dans un container Node 22 (conforme `engines`) - ✅ Checkout **sans actions GitHub**, depuis `workflow/event.json` - ✅ Zéro `apt-get` dans le workflow - ✅ `npm ci` + build + tests anchors + validation schema aliases - ✅ Injection d’aliases au postbuild confirmée en logs ### Runner (DS220+) - ✅ `container.network: host` dans `/data/config.yaml` du runner - ✅ `NODE_OPTIONS=--dns-result-order=ipv4first` passé aux containers de job - ✅ `--add-host=gitea.archicratie.trans-hands.synology.me:192.168.1.20` Raison : le DNS du bridge Docker (127.0.0.11) est instable sur cette infra → EAI_AGAIN / ESERVFAIL (npm, debian). Référence : `docs/CI-BASELINE.md` + `docs/CI-WORKFLOW.md` + `docs/HANDOFF-SESSION.md`. --- ## 1) Invariants (NE PAS “optimiser”) Ces points sont des garde-fous. Si on les retire, on revient aux mêmes pannes. 1) Runner : - garder `container.network: host` (tant que l’infra DNS bridge n’est pas corrigée) - garder `-e NODE_OPTIONS=--dns-result-order=ipv4first` 2) Workflow : - ne pas réintroduire `apt-get` - ne pas dépendre de `actions/checkout@...` - garder un container Node 22 tant que `package.json engines` impose `>=22 <23` 3) Ancrages : - le fichier canonique : `src/anchors/anchor-aliases.json` - injection build-time : `scripts/inject-anchor-aliases.mjs` - test anchors : `scripts/check-anchors.mjs` - validation schema aliases : `scripts/check-anchor-aliases.mjs` --- ## 2) Mission principale (raccrochage) Objectif “métier” : - préserver les liens profonds (ancrages) malgré l’édition (déplacements, insertions, corrections) - éviter les résolutions “par index” (fragiles) - rendre la migration d’ancrages **déterministe, versionnée, testée** Traduction technique : - quand un `newId` remplace un `oldId`, on versionne `oldId -> newId` **par page** - au build, on injecte un alias DOM invisible portant l’ancien `id` avant l’élément ciblé --- ## 3) Prochains jalons (ordre recommandé) ### Jalons A — Verrouillage qualité (court terme, “béton”) A1) CI : prouver l’injection (pas seulement “build ok”) - ajouter un test qui parcourt `src/anchors/anchor-aliases.json` et vérifie dans `dist//index.html` : - présence de `` - présence de l’élément `id="newId"` - et idéalement : alias placé “juste avant” la cible (proximité) A2) CI : interdire les IDs en double (risque SEO/DOM) - dans les pages `dist`, détecter les doublons d’attribut `id="..."` A3) CI : artefacts / logs actionnables - quand un test échoue : afficher `route`, `oldId`, `newId`, extrait HTML et ligne ### Jalons B — Ergonomie éditeur (moyen terme) B1) `apply-ticket.mjs` : renforcer le mode `--alias` - si un paragraphe est remplacé : écrire l’alias automatiquement - si conflit : message clair “oldId déjà mappé / newId introuvable” B2) `check-anchors.mjs` : suggestion d’aliases - lorsqu’il détecte “removed X / added Y” avec même préfixe `p-8-...` - générer une proposition, option `--write-aliases` (ou sortie patch) ### Jalons C — Robustesse long terme (ops) C1) Runner : réduire le risque “host network” - isoler le runner sur LAN (réseau dédié/pare-feu) - limiter les labels/queues aux repos nécessaires - documenter comment restaurer `/data/config.yaml` C2) Versionner les décisions - tout changement CI/runner : documenté dans `docs/` + commit (pas de “magic fix” non tracé) --- ## 4) Procédure standard (dev -> PR -> merge) ### Ajouter/modifier du contenu 1) modifier les sources (docx/import etc.) 2) si des IDs de paragraphes changent : - appliquer `scripts/apply-ticket.mjs --alias` si possible - sinon éditer `src/anchors/anchor-aliases.json` (par route) ### Vérifier en local - `npm test` - ou au minimum : - `npm run build` - vérifier injection : `grep -n "para-alias" dist//index.html` ### PR & merge - une PR = un ticket logique - CI doit passer - merge seulement quand anchors + aliases sont cohérents --- ## 5) Debug express (quand ça casse) ### CI échoue “DNS / npm” Symptômes typiques : - `EAI_AGAIN`, `ESERVFAIL`, `Temporary failure resolving` Actions : 1) vérifier runner config : `/data/config.yaml` contient bien `network: host` 2) vérifier job container : logs montrent `network="host"` 3) smoke test NAS : - `docker run --rm --network host mcr.microsoft.com/devcontainers/javascript-node:22-bookworm bash -lc "npm ping --registry=https://registry.npmjs.org"` ### CI échoue “EBADENGINE” - Node pas 22 → corriger l’image du job (Node 22) ### CI échoue “MODULE_NOT_FOUND scripts/...” - fichier non commité - `git status --porcelain` puis `git add/commit/push` ### Injection d’alias absente - vérifier que `postbuild` appelle bien `inject-anchor-aliases.mjs` - vérifier que `src/anchors/anchor-aliases.json` respecte le schéma (par route) --- ## 6) Définition de “DONE” (quand on peut dire “mission accomplie”) 1) CI stable sur 30+ runs consécutifs (push + PR + merge) 2) Toute modification de paragraphes qui casse des anchors produit : - soit un alias automatique via tooling - soit un échec CI explicite (avec patch proposé) 3) Aliases injectés testés (preuve dans dist) + pas de doublons d’IDs 4) Documentation à jour (baseline + décisions + procédures) --- Fin.