ADR-0010 — Corpus public
Status: Proposed (2026-04-29, après design review interne).
Note de numérotation. L'intitulé de travail initial était
0002-corpus-public.md. Le slot0002étant déjà occupé parbyte-deterministic-cli(conséquence d'une revue de design antérieure), l'ADR prend le prochain numéro libre (0010) — la numérotation du dépôt est monotone, jamais réécrite. L'identité conceptuelle ne change pas : c'est l'acte qui nomme comment le corpus public existe.
Context
morpion-play.pages.dev est une PWA produisant des traces NDJSON v1 (docs/schemas/game-record-v1.md) lorsqu'un joueur termine une partie. Ces traces, ensemble, forment un corpus humain de Morpion Solitaire 5T — l'objet scientifique à publier vers partnerships, Mallat, et la communauté chercheuse cognition / ML qui pourrait l'utiliser pour étudier la planification combinatoire chez l'enfant.
Le projet morpion adopte une doctrine simple sur l'orientation du flux entre privé et commun : privé \(\to\) commun, public \(\to\) commun, jamais l'inverse. Le test produit qui en découle est explicite : si quelqu'un peut désigner une trace privatisable, une stratégie verrouillée, un score lockable, on a échoué.
Sans cet ADR, le corpus existe juridiquement (les traces sont collectées sous opt-in après le pass RGPD default-off) mais pas narrativement : aucun chemin lisible « où est le commun, sous quelle licence, comment le citer ». La conséquence est qu'un concurrent peut en cinq jours déployer un dataset CC-BY + DOI Zenodo et nous dépasser silencieusement. La défense la moins coûteuse est non pas de produire le corpus plus tôt, mais de le nommer publiquement avant qu'il ne contienne quoi que ce soit — geste-licence + endpoint /dataset + ADR.
La revue interne a convergé sur trois arbitrages cardinaux que cet ADR formalise :
- Fenêtre stratégique — la défense critique n'est pas la PWA elle-même mais les artefacts publics : licence claire, endpoint
/dataset, dépôt Zenodo nommé. - Licence arbitrée CC0 — licence des traces : CC0 sur les données factuelles ; CC-BY-SA 4.0 sur la prose accompagnante ; MIT sur le code outillant.
- Cadence et seuil — GitHub Release mensuelle, promotion Zenodo conditionnée au seuil 200 joueurs distincts (pas 200 traces — un cousin qui joue 50 fois n'augmente pas la valeur publique du commun).
Decision
1. Cadence de publication
- Producteur : un workflow GitHub Actions
corpus-release.ymlempaquette mensuellement les traces opt-in du repo en un asset releasable. - Branche :
corpus/(orpheline ou commit-track — choix de l'opérateur lors de la première activation, sur le patron rehearsal orphan branch). - Tag :
corpus-YYYY-MM(ex.corpus-2026-05). -
Asset principal :
morpion-corpus-YYYY-MM.tar.zstcontenant :traces/*.jsonl— traces filtrées surshare-traces === '1'(gate uniqueshouldPostTrace()côté serveur, cf. moléculemorpion-rgpd-default-off).manifest.csv— colonnes :game_id, score, started_at_day, build_hash. Un seul niveau de lecture pour qui veut indexer sans désérialiser le NDJSON.README.md— citation suggérée + licences + statistiques de release (N traces, N joueurs distincts, distribution des scores, fenêtre temporelle).
Le cron du workflow n'est pas activé dans cette ADR. Le brouillon livré est workflow_dispatch only — la première release sera déclenchée manuellement par l'opérateur après que morpion-cer-pre-enregistrement aura outillé l'anonymisation côté serveur (SHA-256 du player_id avec sel non public, drop de started_at_iso, drop de screen_w/h/dpr).
2. Promotion Zenodo
- Cadence : semestrielle, opérateur en main (le DOI mérite vérification humaine —
cs evolvene le décerne pas). - Condition de qualification : \(\geq\) 200 joueurs distincts depuis le démarrage du corpus, identifiés par leur
player_idhaché côté serveur. Pas 200 traces — cinquante parties jouées par un seul cousin n'augmentent pas la diversité du signal scientifique. - Avant le premier dépôt qualifié : la citation pointe le tag GitHub Release (cf. §3 ci-dessous). La PWA n'attend pas Zenodo pour exister.
- Au premier dépôt qualifié : Zenodo émet un DOI. La citation se réécrit (cf. §3). Les releases ultérieures s'ajoutent au même concept DOI Zenodo via les nouvelles versions, conservant le DOI canonique tout en versionnant l'archive.
3. Licences
| Artefact | Licence | Justification |
|---|---|---|
Traces NDJSON (traces/*.jsonl) | CC0-1.0 | Données factuelles sans expression créative. Test produit : sous CC0, personne ne peut s'approprier plus qu'autrui. Zéro friction d'adoption en classe (partnerships) — le prof ne lit aucune licence avant de rejouer une partie. |
Prose accompagnante (README.md du release, docs/corpus/*, notes méthodologiques) | CC-BY-SA 4.0 | Toute redérivation reste partageable. La paire CC0+CC-BY-SA respecte la doctrine du commun adoptée pour ce projet. |
Code de la PWA, du workflow, des outils (dist-play/, tools/, .github/workflows/corpus-release.yml, dist-play/functions/dataset.js) | MIT | Adoption maximale aval — partnerships, un labo, un fork pédagogique peuvent réutiliser le code sans friction de copyleft. La traction inverse est explicitement souhaitée : si un fork apparaît, c'est un succès. |
ODbL est rejetée (sur-spécifiée, friction d'adoption en classe). AGPL sur le code est rejetée (la PWA n'a pas de boucle SaaS à protéger — la valeur n'est pas dans le code, elle est dans le commun de traces).
4. Anonymisation (préalable à la première release)
L'implémentation effective est portée par la molécule morpion-cer-pre-enregistrement (warm). Cet ADR fixe le contrat ; la molécule fixe l'exécution :
player_idhaché côté serveur : SHA-256 duplayer_idcôté client, avec un sel non public connu seulement de l'opérateur. Le sel n'est jamais commité.started_at_isoretiré des traces publiées ; remplacé parstarted_at_day(granularité jour, pas seconde).- Fingerprint allégé :
screen_w,screen_h,dprretirés ; seultouch(boolean) est conservé. build_hashconservé (corrélation engine \(\leftrightarrow\) trace, nécessaire au gate de parité ADR-0009).game_idconservé tel quel (UUIDv7 — non corrélant à un humain par construction).
Avant cette implémentation, aucune trace ne sort du repo en release publique. Le workflow corpus-release.yml livré ce soir échoue intentionnellement si l'anonymisation n'est pas en place (vérification de présence d'un salt-version.txt dans le secret du runner).
5. Citation
Pré-Zenodo (par défaut, jusqu'au premier dépôt qualifié) :
Sérié, E. & contributeurs anonymes (2026). Morpion Solitaire 5T human trace corpus, release 2026-MM. https://github.com/eserie/morpion/releases/tag/corpus-2026-MM
Post-Zenodo (à partir du premier DOI émis) :
Sérié, E. & contributeurs anonymes (2026). Morpion Solitaire 5T human trace corpus, release 2026-MM. Zenodo. https://doi.org/10.5281/zenodo.XXXXXXX
La citation est régénérée automatiquement dans le README.md du release par corpus-release.yml. Le XXXXXXX est remplacé par le DOI réel après le premier dépôt Zenodo (variable de workflow ZENODO_CONCEPT_DOI).
6. Endpoint /dataset
Une Cloudflare Pages Function (dist-play/functions/dataset.js) répond :
GET /dataset\(\to\) JSON{ latest_release_url, corpus_homepage, license_traces: "CC0-1.0", license_readme: "CC-BY-SA-4.0", license_code: "MIT", citation }. Permet à un client partnerships, un notebook Colab ou un script Pythonrequests.get(...)de récupérer le pointeur du dernier dump sansghCLI ni token GitHub.GET /dataset/manifest\(\to\) CSV brut dumanifest.csvdu dernier release, si disponible. Permet d'indexer sans télécharger l'archive complète.- Aucun autre chemin ne sert de trace individuelle. La flèche privé \(\to\) commun ne s'inverse pas par chemin court : le commun ne se télécharge qu'en bloc, archivé, signé par un tag git.
L'endpoint se contente de proxifier l'API GitHub Releases publique ; il n'a ni base de données, ni cache, ni état. Sa seule valeur est la lisibilité : un point d'entrée stable et nommé. Latence acceptable \((\leq\) 500 ms p95) — l'usage est documentaire, pas chaud.
Architecture
┌─────────────────────────────────┐
│ PWA dist-play/ │
│ share-traces opt-in (gate ✔) │
└────────────────┬────────────────┘
│ POST /save (opt-in only)
▼
┌─────────────────────────────────┐
│ Cloudflare Worker save.js │
│ + R2 storage (privé) │
│ + sync mensuel → repo gallery/ │
└────────────────┬────────────────┘
│ git push corpus/
▼
┌──────────────────────────────────────────────┐
│ GitHub Actions corpus-release.yml │
│ - filter share-traces === '1' │
│ - count distinct hashed player_id │
│ - tar.zst + manifest.csv + README │
│ - create release corpus-YYYY-MM │
└────────────┬─────────────────────────────────┘
│
┌──────────────┼──────────────────────────────┐
▼ ▼
┌─────────────────────┐ ┌──────────────────────────┐
│ GitHub Release │ ←─── /dataset ──┤ Cloudflare Function │
│ (mensuel, CC0+CC-BY │ pointe vers │ dist-play/functions/ │
│ -SA + MIT) │ le dernier │ dataset.js │
└──────────┬──────────┘ └──────────────────────────┘
│
│ semestriel, ≥ 200 joueurs distincts
▼
┌─────────────────────┐
│ Zenodo concept DOI │
│ (citable, archivé) │
└─────────────────────┘
Consequences
-
Engagements pris :
- Cadence mensuelle de release une fois
morpion-cer-pre-enregistrementoutillé. - L'opérateur tient la main pour les dépôts Zenodo (DOI, métadonnées, vérification).
- Le repo prend une branche
corpus/(ou un commit-track) qui ne suit pas le rythmemain. - Le
dist-play/index.htmlportera un footer « Voir le commun — corpus public, CC0 » (livrable demorpion-charte-copy-v1).
- Cadence mensuelle de release une fois
-
Engagements explicitement non pris :
- Pas de gating par auth sur
/datasetni sur le téléchargement du release. Le commun est lisible sans compte. - Pas de limitation d'usage (pas de non-commercial, pas de research-only) — sous CC0, l'usage commercial est explicitement autorisé. Test produit : si un fournisseur SaaS construit un produit fermé sur les traces, il ne s'est pas approprié le commun ; il l'a utilisé. C'est précisément la différence que la doctrine du commun cherche à honorer.
- Pas de Software Heritage comme cible de dépôt. SWH archive le code ; nous publions des données sur cadence. Zenodo est l'archive sémantiquement correcte.
- Pas de gating par auth sur
- Ce qu'un fork peut faire sans friction : copier le corpus, le re-publier sous CC0 (legal sous CC0), entraîner un modèle dessus, en publier un dérivé. C'est ce qu'on souhaite.
- Ce qu'un fork ne peut pas faire : prétendre être le corpus officiel. Le tag GitHub Release + le DOI Zenodo + l'endpoint
/datasetsur le domainemorpion-play.pages.devconstituent l'identité narrative du corpus, indépendante de la propriété juridique des données. - Risque résiduel : un concurrent peut, sous CC0, redistribuer le corpus avec un re-naming agressif (« le dataset Morpion Pro »). C'est acceptable — sous CC0 c'est légitime, et la doctrine du commun dit « on échoue si quelqu'un peut désigner une part de capital ou un modèle fermé appartenant au commun » ; redistribuer un commun en clair n'est pas le fermer.
Invariant
Toute trace publiée dans un release
corpus-YYYY-MMest sous CC0-1.0, sonplayer_idest haché avec un sel non public, ne contient aucun horodatage plus fin que le jour, et n'a jamais transité par un chemin de POST qui ignore la gateshouldPostTrace(). Aucune autre voie ne porte la mention « corpus public ».
Derivation — Issue d'une revue interne du projet morpion ayant produit cinq décisions verrouillées par cet ADR : cadence mensuelle, promotion Zenodo semestrielle, seuil 200 joueurs distincts, paire de licences CC0 + CC-BY-SA, et footer public obligatoire. La revue a aussi identifié le risque d'un concurrent préemptant un dataset équivalent en cinq jours — d'où la décision de nommer publiquement le commun avant qu'il ne contienne quoi que ce soit (geste-licence + endpoint /dataset + ADR). L'arbitrage de licence CC0 sur les traces (vs CC-BY-4.0) repose sur la doctrine du commun adoptée pour ce projet : test produit explicite (rien que sous CC0 ne peut redevenir privatisé) et flèche orientée privé \(\to\) commun, jamais l'inverse.