From cb4cd0140941a1f7a2f2ade07a59a381d020b4e1 Mon Sep 17 00:00:00 2001 From: Archicratia Date: Tue, 20 Jan 2026 17:04:28 +0100 Subject: [PATCH] =?UTF-8?q?docs:=20add=20topo=20logique=20m=C3=A9tier?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- docs/TOPO_LOGIQUE_METIER.md | 250 ++++++++++++++++++++++++++++++++++++ 1 file changed, 250 insertions(+) create mode 100644 docs/TOPO_LOGIQUE_METIER.md diff --git a/docs/TOPO_LOGIQUE_METIER.md b/docs/TOPO_LOGIQUE_METIER.md new file mode 100644 index 0000000..2318bf6 --- /dev/null +++ b/docs/TOPO_LOGIQUE_METIER.md @@ -0,0 +1,250 @@ +# 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 cet `id`. +- **Paragraphe citable** : un `

...

` 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 de `dist/`). +- **BUILD / PROD-like** : `npm run build` puis servir `dist/` (ce qui ressemble à la prod). + +--- + +## 2) Vue d’ensemble : le pipeline (la “machine éditoriale”) + +### 2.1 Le flux humain (ce que fait l’éditeur) +1) Lire une page sur “Archicratie – Web Edition”. +2) Sur un paragraphe : cliquer **Proposer**. +3) Choisir **Type** (Correction / Fact-check) + **Category** (lexique, style, etc.). +4) Gitea s’ouvre en **nouvel onglet** avec un ticket pré-rempli. +5) L’éditeur écrit la proposition, justifie, et valide le ticket. + +### 2.2 Le flux technique (ce que fait la machine) +6) `apply-ticket` récupère le ticket via l’API Gitea. +7) Il retrouve le bon fichier source (MDX) + le bon paragraphe (matching sûr). +8) Il applique la modification (ou refuse si trop incertain). +9) On lance `npm test` → build + test ancres + check JS inline. +10) On commit / push. +11) 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--` + 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 : + +1) **Fetch** : récupère le ticket via API (FORGE_TOKEN requis). +2) **Parse** : extrait Chemin/Ancre/Proposition/(Texte actuel si présent). +3) **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é) +4) **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 \ No newline at end of file