8.0 KiB
Topo – Logique métier de l’outil éditorial (Web Edition ↔ Gitea ↔ apply-ticket ↔ CI)
Ce document explique ce que fait réellement l’outil, pourquoi il existe, et comment le maintenir sans casser la promesse centrale : citabilité durable + édition traçable + intégration sûre.
Public visé : “commun des mortels” (nouveau contributeur, mainteneur occasionnel, moi dans 6 mois).
0) La promesse (le “pourquoi”)
On veut un site (Astro) où chaque paragraphe est :
- citable (URL + ancre stable),
- corrigeable (ouvrir un ticket pré-rempli depuis le paragraphe),
- réparable de manière sûre (appliquer la proposition dans les sources sans magie),
- vérifié automatiquement (tests + build + garde-fous en CI).
En bref :
Lecture → proposition → ticket → application → tests → build → publication
…sans perdre la traçabilité, ni casser les citations historiques.
1) Glossaire (pas de jargon sans définition)
- Ancre : partie
#...d’une URL (ex :#p-8-0e65838d). Le navigateur saute à l’élément HTML portant cetid. - Paragraphe citable : un
<p id="p-...">...</p>dans l’article. - Ticket / Issue : demande de correction sur Gitea (ex : #14).
- PR (Pull Request) : “demande d’ajout / fusion” : une proposition de merge d’une branche vers
master. - CI : tests automatiques exécutés sur le serveur à chaque push/PR.
- Runner : machine/conteneur qui exécute la CI (chez nous : DS220+ / ds220-runner).
- DEV :
npm run dev(serveur Astro à la volée, pas dedist/). - BUILD / PROD-like :
npm run buildpuis servirdist/(ce qui ressemble à la prod).
2) Vue d’ensemble : le pipeline (la “machine éditoriale”)
2.1 Le flux humain (ce que fait l’éditeur)
- Lire une page sur “Archicratie – Web Edition”.
- Sur un paragraphe : cliquer Proposer.
- Choisir Type (Correction / Fact-check) + Category (lexique, style, etc.).
- Gitea s’ouvre en nouvel onglet avec un ticket pré-rempli.
- L’éditeur écrit la proposition, justifie, et valide le ticket.
2.2 Le flux technique (ce que fait la machine)
apply-ticketrécupère le ticket via l’API Gitea.- Il retrouve le bon fichier source (MDX) + le bon paragraphe (matching sûr).
- Il applique la modification (ou refuse si trop incertain).
- On lance
npm test→ build + test ancres + check JS inline. - On commit / push.
- La CI revalide automatiquement sur le serveur.
3) Composant A — Le site (Astro) et les outils de paragraphe
Dans le rendu final, chaque paragraphe important reçoit un id de forme :
p-<index>-<hash8>
ex :p-8-0e65838d
Ensuite, un script ajoute des outils de paragraphe (“para-tools”) :
- ¶ : lien direct sur le paragraphe (ancre)
- Citer : copie une citation (titre + version + URL sans query-string)
- Proposer : ouvre la modale (2 étapes), puis ouvre le ticket Gitea
Point crucial : progressive enhancement
- Si JS marche : UX optimale.
- Si JS casse : le site reste lisible, et le lien de proposition reste utilisable au minimum via
href.
4) Composant B — Contrat des tickets (machine-readable)
Pour que apply-ticket puisse travailler, le ticket doit rester structuré.
Le ticket contient des lignes “clé: valeur” (une par ligne), par ex :
Chemin: /archicratie/prologue/URL locale: http://localhost:4321/archicratie/prologue/#p-...Ancre: #p-8-...Version: ...Type: type/correction(ou type/fact-check)State: state/recevable(ou state/a-sourcer)Category: cat/lexique(optionnel)
Règle d’or : ces clés doivent rester simples, stables, sur une ligne chacune.
Sinon, scripts + CI + auto-labeling deviennent fragiles.
5) Composant C — apply-ticket (appliquer sans magie)
apply-ticket fait 4 choses :
- Fetch : récupère le ticket via API (FORGE_TOKEN requis).
- Parse : extrait Chemin/Ancre/Proposition/(Texte actuel si présent).
- Match : retrouve le paragraphe dans le fichier source (MDX) :
- idéal : “Texte actuel (copie exacte…)” → match fort
- sinon : match par score → si score trop faible, refus (sécurité)
- Apply : modifie le fichier source, sans casser le reste.
Mode sûr
--dry-run: montre BEFORE/AFTER, n’écrit rien- mode normal : écrit + propose ensuite
git diff,git add,git commit
6) Composant D — Citabilité P0 : ancres, churn test, aliases
6.1 Le problème
Si l’ID dépend du contenu, modifier un paragraphe peut changer l’ID.
Donc une citation historique ...#ancien casse.
6.2 La solution robuste (“web native”)
On ne “résout” pas l’ancre : on la fait exister.
On maintient un fichier :
src/anchors/anchor-aliases.json
Exemple (par page/chemin) : en json { "/archicratie/prologue/": { "p-8-e7075fe3": "p-8-0e65838d" } }
Au build, un script injecte dans dist/.../index.html :
...
Résultat :
le navigateur résout #p-8-e7075fe3 sans JS.
6.3 Pourquoi un fallback JS existe encore ?
En mode npm run dev, on ne passe pas par dist/, donc pas d’injection build-time. Le fallback JS est un filet :
utile en DEV,
utile si un alias manque,
mais pas la solution principale.
7) Tests & garde-fous (qualité automatique)
7.1 npm test doit rester “simple et vrai”
Il exécute :
npm run build (génère dist)
npm run test:anchors (stabilité des ancres)
node scripts/check-inline-js.mjs (évite les scripts inline invalides)
7.2 test:anchors (baseline + churn)
tests/anchors-baseline.json = snapshot de référence.
check-anchors compare dist à la baseline.
Si trop de churn → échec (donc on voit la casse).
On met à jour la baseline uniquement quand on accepte consciemment la nouvelle réalité : npm run test:anchors:update
8) DEV vs BUILD : comprendre sans se tromper
npm run dev → serveur Astro “live”, pas de dist/ ⇒ les alias build-time n’existent pas ⇒ fallback JS peut s’activer.
npm run build && npx serve dist → rendu final “prod-like” ⇒ alias injectés ⇒ citations historiques fonctionnent sans JS.
Repère immédiat :
port 4321 = DEV
port 3000 (serve dist) = PROD-like
9) Rituels opérationnels (les 3 recettes)
Recette 1 — Créer un ticket propre
Cliquer “Proposer”
Choisir Type + Category
Dans Gitea : compléter “Proposition (remplacer par)” + “Justification”
Ne pas détruire les lignes Chemin / Ancre / Type / State / Category
Recette 2 — Appliquer un ticket
en bash : node scripts/apply-ticket.mjs --dry-run node scripts/apply-ticket.mjs git diff npm test git add ... git commit -m "edit: apply ticket # (#)" git push
Recette 3 — Quand un ID change (citabilité)
trouver ancien id + nouveau id
ajouter alias dans src/anchors/anchor-aliases.json
npm run build
vérifier ...#ancien → scroll sur le bon paragraphe
npm test
10) Règles d’or (invariants non négociables)
Ne jamais éditer dist/ à la main (artefact).
Ne jamais sacrifier l’ancre : Chemin + Ancre doivent exister.
Tickets toujours “parsables” (clés stables ligne-par-ligne).
apply-ticket doit pouvoir refuser quand c’est ambigu.
npm test doit rester “le bouton rouge” fiable.
11) Dépannage rapide
401 invalid token : FORGE_TOKEN absent ou mal exporté.
Header invalid value : token collé avec des caractères parasites (espaces, retours, texte autour).
Proposer ouvre 2 onglets / remplace la page : bug d’interception click → vérifier preventDefault + stopPropagation et l’“openInNewTab”.
Ancien #id ne marche plus :
en PROD-like : vérifier alias injecté + JSON
en DEV : normal que fallback JS soit requis
12) Où lire quoi (docs)
docs/QUICKSTART.md : démarrer vite
docs/MANUEL_REFERENCE.md : usage complet + procédures
docs/CONTRAT_TICKETS.md : format strict des issues
(ce doc) docs/TOPO_LOGIQUE_METIER.md : la logique qui relie tout