{
  "language": "fr",
  "alternates": {
    "fr": "https://test.each.app/surface/publications/v0.json",
    "en": "https://test.each.app/en/surface/publications/v0.json",
    "markdown_fr": "https://test.each.app/surface/publications/v0.md",
    "markdown_en": "https://test.each.app/en/surface/publications/v0.md"
  },
  "module": "publications",
  "version": "v0",
  "status": "draft",
  "updated": "2026-10-30",
  "name": "module Publications",
  "summary": "Le module Publications permet de publier un texte sur Each. Chaque publication est versionnée: une modification crée une nouvelle version immuable, les anciennes restent lisibles. Chaque version porte une preuve signée de son contenu (empreinte SHA-256).",
  "object": [
    {
      "id": "id",
      "text": "Identifiant stable de la publication (pub_...)."
    },
    {
      "id": "path",
      "text": "Adresse de lecture: /p/{auteur}/{slug}."
    },
    {
      "id": "author",
      "text": "Nom de l'auteur ou de l'autrice, tel qu'il ou elle le donne."
    },
    {
      "id": "title",
      "text": "Titre."
    },
    {
      "id": "version",
      "text": "Numéro de version (1, 2, 3...). Jamais réécrit."
    },
    {
      "id": "format",
      "text": "\"markdown\" ou \"html\" (HTML nettoyé: p, br, em, strong, h2, h3, blockquote, ul, ol, li, a)."
    },
    {
      "id": "content",
      "text": "Contenu exact, tel que publié. Each ne le corrige jamais."
    },
    {
      "id": "themes",
      "text": "Thèmes (liste de mots)."
    },
    {
      "id": "license",
      "text": "Licence donnée par l'auteur. Sans licence: \"non précisée — tous droits réservés à l'auteure\"."
    },
    {
      "id": "content_sha256",
      "text": "Empreinte SHA-256 (hexadécimal) des octets UTF-8 du contenu."
    },
    {
      "id": "proof",
      "text": "Preuve signée each.publication de cette version."
    }
  ],
  "core": "Le noyau Each n'est pas modifiable par un module. Toute écriture (créer une publication, ajouter une version) exige soit une confirmation par clé d'accès, soit un jeton de capacité portant la portée publications:write. Le noyau vérifie l'un ou l'autre avant d'écrire, et signe la preuve. Les versions sont en ajout seulement: aucune modification ni suppression.",
  "scopes": [
    {
      "id": "publications:read",
      "text": "Lire les publications et leurs versions (public, sans jeton)."
    },
    {
      "id": "publications:write",
      "text": "Créer une publication ou ajouter une version, au nom de la personne qui a créé le jeton."
    }
  ],
  "capability_tokens": "Un jeton de capacité se crée avec ta clé d'accès (POST /v1/capabilities). Il est montré une seule fois, Each n'en garde que l'empreinte. Il expire après 30 jours. Il s'envoie dans l'en-tête Authorization: Bearer each_cap_...",
  "proof": {
    "type": "each.publication",
    "fr": "Chaque version produit une preuve signée (ES256, clé publique: /.well-known/each-keys), vérifiable sur /verifier/{id}. La preuve dit qui l'a signée: la clé d'accès de l'auteur, un jeton de capacité, ou l'équipe Each pour une publication test.",
    "en": "Every version produces a signed proof (ES256, public key: /.well-known/each-keys), verifiable at /verifier/{id}. The proof says who signed it: the author's passkey, a capability token, or the Each team for a test publication.",
    "fields": [
      "v",
      "type",
      "id",
      "issuer",
      "environment",
      "issued_at",
      "publication.id",
      "publication.path",
      "publication.version",
      "publication.title",
      "publication.author",
      "publication.format",
      "publication.license",
      "publication.content_sha256",
      "publication.previous_sha256",
      "signed_by",
      "signed_by_author",
      "note",
      "statement"
    ]
  },
  "api": [
    "GET /v1/publications",
    "GET /v1/publications/{id}",
    "GET /v1/publications/{id}/versions",
    "GET /v1/publications/{id}/versions/{n}",
    "POST /v1/publications/options",
    "POST /v1/publications",
    "POST /v1/publications/{id}/versions",
    "POST /v1/capabilities/options",
    "POST /v1/capabilities"
  ],
  "cors": "Les GET de /v1/publications sont ouverts à toutes les origines (Access-Control-Allow-Origin: *), pour qu'un lecteur externe puisse afficher les textes.",
  "reader": "Un lecteur d'exemple à copier: examples/publication-reader/ (un fichier, une configuration, un README).",
  "versioning": "Version du contrat: v0 = brouillon. Un changement incompatible crée v1 à une nouvelle adresse; v0 reste lisible. Pour proposer un changement: copie src/modules/publications/, modifie contract.json, ouvre une revue.",
  "open_questions": [
    {
      "text": "Qui peut publier au nom d'un auteur (proche, éditeur), et comment l'auteur reprend-il la main sur une publication test?"
    },
    {
      "text": "Licences proposées par défaut (tous droits réservés, licences libres) et comment les afficher."
    },
    {
      "text": "Retrait: une version reste lisible pour toujours; faut-il un retrait public (masquer sans effacer la preuve)?"
    },
    {
      "text": "Traductions: une traduction est-elle une version ou une publication liée?"
    }
  ]
}