Files
archicratie-edition/docs/EDITORIAL-ANNOTATIONS-SPEC.md
Archicratia 7444eeb532
All checks were successful
CI / build-and-anchors (push) Successful in 1m45s
SMOKE / smoke (push) Successful in 11s
docs: add pro runbooks (deploy/edge/public_site) + annotations spec + start-here v2
2026-02-21 15:34:47 +01:00

8.2 KiB
Raw Permalink Blame History

SPEC — Annotations éditoriales (YAML v1) + merge + anti-doublon

Objectif : permettre aux tickets (Gitea) de déposer “Références / Médias / Commentaires” dans src/annotations/**, de façon univoque, stable, et sans régression.

0) Contexte et intention

Le site est statique. Lédition collaborative se fait via :

  • un mode “proposition” (UI / modal)
  • un ticket Gitea (issue) standardisé
  • un script dapplication côté éditeur (apply-ticket.mjs ou équivalent)
  • génération dun YAML dannotations versionné dans Git

La donnée dannotation doit être :

  • audit-able (Git)
  • merge-able (sans tout casser)
  • stable (IDs paragraphes / liens / médias)
  • scalable (éviter YAML monstrueux à long terme)

1) Arborescence canonique

1.1 Un workKey par “ouvrage / section du site”

On veut une univocité entre :

  • SiteNav (Méthode, Essai-thèse, Traité, Cas IA, Glossaire, Atlas) et
  • larborescence annotations

Proposition canonique (workKey = route racine) :

  • methode
  • archicrat-ia (Essai-thèse ArchiCraT-IA)
  • traite
  • ia
  • glossaire
  • atlas

1.2 Règle de stockage “v1”

Par page, un YAML unique :

src/annotations//.yml

Exemples :

  • Page : /archicrat-ia/prologue/

    • slug content = archicrat-ia/prologue
    • fichier : src/annotations/archicrat-ia/prologue.yml
  • Page : /traite/00-demarrage/

    • fichier : src/annotations/traite/00-demarrage.yml

Note : “slugSansWorkKey” = la partie après <workKey>/. Sil y a des sous-dossiers (chapitres), le chemin reflète la structure : chapitre-1/section-a.yml si on choisit du sharding.

2) Question “gros YAML” : page unique vs sharding par paragraphe

2.1 Option A (v1 recommandée) : 1 YAML par page

Avantages :

  • simple
  • peu de fichiers
  • diff lisible si volume modéré
  • cohérent avec un modèle “annotations par page”

Inconvénients :

  • YAML peut grossir si milliers dannotations

2.2 Option B (v2 future) : sharding par paragraphe

src/annotations///.yml

Avantages :

  • fichiers petits
  • merges moins conflictuels Inconvénients :
  • plus de fichiers
  • tooling plus complexe (indexation + merge multi-fichiers)

2.3 Recommandation de mission (sans casser lexistant)

  • On démarre en Option A.
  • On se garde une migration future (v2) quand le volume réel le justifie.
  • On impose dès v1 : clé unique + merge déterministe + anti-doublon, ce qui rend la migration future possible.

3) Format YAML v1 (schéma complet)

3.1 Top-level

en yaml :

schema: 1

Optionnel mais recommandé (doit matcher la page)

page: "/"

meta: title: "Titre de la page (optionnel)" updatedAt: "2026-02-21T12:34:56Z" # ISO8601 updatedBy: "username" # compte editor source: kind: "ticket" id: 123 url: "https://gitea.../issues/123"

paras: "": references: [] media: [] comments: []

3.2 paras : clé = paraId (ex: p-0-d7974f88)

Chaque paragraphe peut porter 3 types déléments :

references

media

comments

Règle : si une section est vide, elle peut être [] ou absente. Mais pour simplifier les merges, on recommande de garder la forme canonique avec [].

4) Formats des items + clés uniques

4.1 References

4.1.1 Format

references:

  • id: "ref:doi:10.1234/abcd.efgh" # clé stable (voir 4.1.2) kind: "doi" # doi | url | isbn | arxiv | hal | other label: "Titre court" target: "https://doi.org/10.1234/abcd.efgh" note: "Pourquoi cest pertinent (optionnel)" addedAt: "2026-02-21T12:34:56Z" addedBy: "username"

4.1.2 Règle de clé unique (anti-doublon)

id doit être stable et déterministe :

doi → ref:doi:

isbn → ref:isbn:

url → ref:url:

Normalisation URL (v1) : au minimum

trim

lowercase scheme/host

retirer trailing slash si non significatif

conserver query si importante

4.1.3 Merge / précédence

Quand on merge deux listes references :

union par id (clé unique)

si même id existe des deux côtés :

conserver kind/target de litem le plus “riche” (target non vide gagne)

concat/merge note :

si notes différentes : garder les deux en les séparant (ex: noteA + "\n---\n" + noteB)

addedAt : conserver le plus ancien

addedBy : conserver le premier (ou liste si on veut, mais v1 simple : first)

4.2 Media

4.2.1 Format

media:

  • id: "media:image:sha256:abcd..." # clé stable (voir 4.2.2) type: "image" # image | video | audio | file src: "/public/media////" caption: "Légende (optionnel)" credit: "Auteur/source (optionnel)" license: "CC-BY (optionnel)" addedAt: "2026-02-21T12:34:56Z" addedBy: "username"

4.2.2 Règle de clé unique

id déterministe :

idéal : hash du fichier (sha256)

sinon : hash de type + src

v1 (si on ne calcule pas de hash fichier) :

media::

4.2.3 Merge / précédence

union par id

si collision :

garder src identique (sinon cest un bug)

fusionner caption/credit/license selon “non vide gagne”

addedAt : plus ancien

4.3 Comments

4.3.1 Format

comments:

  • id: "cmt:20260221T123456Z:username:0001" kind: "comment" # comment | question | objection | todo | validation text: "Texte du commentaire" status: "open" # open | resolved addedAt: "2026-02-21T12:34:56Z" addedBy: "username" source: kind: "ticket" id: 123

4.3.2 Clé unique

Les commentaires sont “append-only” → id peut être générée (timestamp + user + compteur)

Anti-doublon : si on ré-applique un ticket, on refuse de dupliquer un id existant.

4.3.3 Merge / précédence

union par id

collisions rares, mais si elles arrivent :

si textes différents → garder les deux (on renomme lid du second)

5) Règles globales de merge (résumé)

Quand on applique un ticket sur un YAML existant :

vérifier schema == 1

vérifier page si présent :

doit matcher /

paras :

créer paras[paraId] si absent

pour chaque liste (references/media/comments) :

merge par id (anti-doublon)

appliquer règles de précédence (non vide gagne / concat note / append-only comments)

6) Table de correspondance “UI ticket → YAML”

Cette table permet à un successeur IA dimplémenter apply-ticket.mjs sans ambiguïté.

6.1 Champs UI minimaux

workKey (sélection implicite via page)

pagePath (ex: /archicrat-ia/prologue/)

pageSlug (ex: archicrat-ia/prologue)

paraId (ex: p-0-d7974f88)

kind :

reference

media

comment

6.2 Mapping exact

UI kind UI champs YAML cible
reference kind(doi/url/isbn), target, label, note paras[paraId].references[]
media type(image/video/audio/file), src, caption, credit, license paras[paraId].media[]
comment kind(comment/question/objection/todo/validation), text paras[paraId].comments[]

6.3 Règles de génération dID (implémentation)

reference.id :

doi : ref:doi:${doi}

isbn : ref:isbn:${isbn}

url : ref:url:${normalize(url)}

media.id :

media:${type}:${src}

comment.id :

cmt:${timestamp}:${user}:${counter}

7) Validation YAML (sanity)

Avant commit (et en CI) :

YAML parse OK

schema OK

page si présent cohérent

paras est un mapping

paraId match pattern : ^p-\d+-[a-f0-9]{8}$ (existant)

src media pointe dans /public/media/... (ou /media/... si on choisit un alias, mais v1 canon : /public/media/...)

8) Notes de compatibilité

Les routes “Essai-thèse” ont été migrées vers /archicrat-ia/*.

Les anciennes routes /archicratie/archicrat-ia/* peuvent exister en legacy, mais la donnée canonique dannotation doit suivre le workKey final (archicrat-ia).

9) Ce que létape 9 devra implémenter

pipeline : ticket → YAML (apply-ticket)

index : build-annotations-index + check-annotations

tooling : détection médias orphelins / liens cassés

éventuellement : migration vers sharding par paragraphe (v2) si volume réel le justifie