feat(session-0): cadre juridique, porte de validation et dataset vérifié

Session 0 du plan — aucun code applicatif.

Cadre
- 5 ADR : licences, Phaser 4 hors budget initial, frontière Svelte/Phaser,
  filières A/B des assets, kréyòl langue principale (norme gwadloupéyenne).
- LICENSE (AGPL-3.0-or-later, texte canonique gnu.org), LICENSE-CONTENT
  (CC BY-SA 4.0). Le jeu est une œuvre collective : aucun compositing sur un
  média SA ou NC, contrainte vérifiée par script.
- Audit des 7 sources avec endpoints réellement appelés. TRAMIL vérifié en
  direct : « all rights reserved » et page de mentions légales en 404.
  iNaturalist mesuré à 93 % de CC BY-NC sur un échantillon de 305 photos.

Outillage (tools/data/, hors bundle, zéro appel réseau au runtime)
- verify:taxa, ingest:commons, build:dataset, validate:data, test:porte,
  build:credits, check:audio.
- validate.mjs est la porte exigée par le brief §2 : le build échoue si une
  épreuve s'appuie sur un média non validé, non photographique ou de filière B,
  sur une attribution sans auteur, sur un compositing SA/NC, ou sur une entrée
  publiée sans relecture kréyòl. test:porte prouve les 9 refus + 1 témoin.

Données
- 13 entrées (8 fruits + 5 plantes du module Pa touché) vérifiées contre
  Wikidata ET GBIF : 13/13 ACCEPTED, 0 divergence avec la graine.
- 130 candidats Commons sous licence libre, 39 pré-inscrits, 0 validé —
  aucun agent ne peut valider un média.

Écarts signalés, non corrigés en silence
- Le champ danger de la graine a deux formes (note vs resume) : normalisé.
- 3 identifiants divergent du nom kréyòl au-delà des accents : non tranchés.
- comestible:false sur akée et pomme-cajou : sous-estimation prudente assumée.
- Le mancenillier n'a aucune photographie moderne dans ses 3 premiers
  candidats — l'entrée la plus critique est la moins bien servie.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
OKI
2026-07-26 23:47:27 -04:00
co-authored by Claude Opus 5
parent f0b3ce8484
commit 945a524b44
45 changed files with 8599 additions and 0 deletions
+176
View File
@@ -0,0 +1,176 @@
# Crédits — KI FWI SA YÉ ?
> **Fichier généré.** Ne pas éditer à la main : `npm run build:credits`.
> Dernière génération : 2026-07-27.
## Ce que couvre ce fichier
Chaque média embarqué dans le jeu ou dans lencyclopédie est listé ci-dessous avec son
auteur, sa licence et le lien vers sa page de description dorigine. Rien nest
« libre de droit » : chaque ligne est une obligation contractuelle.
Le code du projet est sous **AGPL-3.0-or-later** (`LICENSE`). Les textes rédigés par
ORGANISATION KA INTERNATIONALE sont sous **CC BY-SA 4.0** (`LICENSE-CONTENT`). Les médias
tiers restent sous leur licence propre : le jeu est une **œuvre collective**, pas une
œuvre dérivée — voir `docs/adr/0001-licences.md`.
## Chiffres
- 13 entrées · 39 médias
- 0 médias validés par un humain
- 12 médias en partage à lidentique (CC BY-SA) — **aucun compositing autorisé**
- 0 médias sous clause non commerciale (CC BY-NC)
## Médias par entrée
### aki — *Blighia sapida* (`ake`)
Taxonomie vérifiée le 2026-07-27 contre [Wikidata Q417145](https://www.wikidata.org/wiki/Q417145)
et [GBIF 3189955](https://www.gbif.org/species/3189955).
| média | vue | auteur | licence | validé | page dorigine |
|---|---|---|---|---|---|
| ackee-001 | — | Jerome Walker | CC BY-SA 3.0 | non | [voir](https://commons.wikimedia.org/wiki/File:Ackee_001.jpg) |
| walter-hood-fitch03 | — | Walter Hood Fitch | domaine public | non | [voir](https://commons.wikimedia.org/wiki/File:Walter_Hood_Fitch03.JPG) |
| owoce-aka | — | Agnieszka Kwiecień ( Nova ) | CC BY-SA 3.0 | non | [voir](https://commons.wikimedia.org/wiki/File:Owoce_Aka.jpg) |
### fwiyapen — *Artocarpus altilis* (`fwiyapen`)
Taxonomie vérifiée le 2026-07-27 contre [Wikidata Q14677](https://www.wikidata.org/wiki/Q14677)
et [GBIF 2984573](https://www.gbif.org/species/2984573).
| média | vue | auteur | licence | validé | page dorigine |
|---|---|---|---|---|---|
| artocarpus-incisus-blanco2-267 | — | Francisco Manuel Blanco (O.S.A.) | domaine public | non | [voir](https://commons.wikimedia.org/wiki/File:Artocarpus_incisus_Blanco2.267.png) |
| starr-031209-0031-artocarpus-altilis | — | Forest &amp; Kim Starr | CC BY 3.0 | non | [voir](https://commons.wikimedia.org/wiki/File:Starr_031209-0031_Artocarpus_altilis.jpg) |
| artocarpus-altilis-fruit | — | Hans Hillewaert | CC BY-SA 3.0 | non | [voir](https://commons.wikimedia.org/wiki/File:Artocarpus_altilis_(fruit).jpg) |
### gouyav — *Psidium guajava* (`gouyav`)
Taxonomie vérifiée le 2026-07-27 contre [Wikidata Q166843](https://www.wikidata.org/wiki/Q166843)
et [GBIF 5420380](https://www.gbif.org/species/5420380).
| média | vue | auteur | licence | validé | page dorigine |
|---|---|---|---|---|---|
| psidium-guajava-fruit-2 | — | Own work | CC BY-SA 3.0 | non | [voir](https://commons.wikimedia.org/wiki/File:Psidium_guajava_fruit_(2).jpg) |
| apple-guava | — | Fuadsyazwan ( talk ) | domaine public | non | [voir](https://commons.wikimedia.org/wiki/File:Apple_Guava.jpg) |
| starr-111012-8771-psidium-guajava-burnt-fruit-kahana-maui-24 | — | Forest and Kim Starr | CC BY 3.0 | non | [voir](https://commons.wikimedia.org/wiki/File:Starr-111012-8771-Psidium_guajava-burnt_fruit-Kahana-Maui_(24488703784).jpg) |
### kénèt — *Melicoccus bijugatus* (`kenet`)
Taxonomie vérifiée le 2026-07-27 contre [Wikidata Q279728](https://www.wikidata.org/wiki/Q279728)
et [GBIF 3189990](https://www.gbif.org/species/3189990).
| média | vue | auteur | licence | validé | page dorigine |
|---|---|---|---|---|---|
| melicoccus-bijugatus | — | No machine-readable author provided. Hans B.~commonswiki assumed (based on copyright claims). | domaine public | non | [voir](https://commons.wikimedia.org/wiki/File:Melicoccus_bijugatus.jpg) |
| cebus-capucinus-puntarenas-costa-rica | — | kansasphoto | CC BY 2.0 | non | [voir](https://commons.wikimedia.org/wiki/File:Cebus_capucinus_Puntarenas_Costa_Rica.jpg) |
| una-rama-de-mamon | — | EEIM | CC BY-SA 3.0 | non | [voir](https://commons.wikimedia.org/wiki/File:Una_rama_de_mamon.jpeg) |
### kowosòl — *Annona muricata* (`kowosol`)
Taxonomie vérifiée le 2026-07-27 contre [Wikidata Q1709343](https://www.wikidata.org/wiki/Q1709343)
et [GBIF 5407273](https://www.gbif.org/species/5407273).
| média | vue | auteur | licence | validé | page dorigine |
|---|---|---|---|---|---|
| soursop-fruit | — | USGov | domaine public | non | [voir](https://commons.wikimedia.org/wiki/File:Soursop_fruit.jpg) |
| annona-muricata-1 | — | Damien Boilley from suburbs of Paris, France | CC BY 2.0 | non | [voir](https://commons.wikimedia.org/wiki/File:Annona_muricata_1.jpg) |
| annona-muricata2 | — | User:Hans_B. | domaine public | non | [voir](https://commons.wikimedia.org/wiki/File:Annona_muricata2.jpg) |
### lorié-jòn — *Cascabela thevetia* (`lorye-jonn`)
Taxonomie vérifiée le 2026-07-27 contre [Wikidata Q10694475](https://www.wikidata.org/wiki/Q10694475)
et [GBIF 3169652](https://www.gbif.org/species/3169652).
| média | vue | auteur | licence | validé | page dorigine |
|---|---|---|---|---|---|
| thevetia-peruviana1 | — | No machine-readable author provided. Hans B.~commonswiki assumed (based on copyright claims). | domaine public | non | [voir](https://commons.wikimedia.org/wiki/File:Thevetia_peruviana1.jpg) |
| yellow-oleander-thevetia-peruviana-leaves-flowers-in-kolkata | — | J.M.Garg | CC BY-SA 3.0 | non | [voir](https://commons.wikimedia.org/wiki/File:Yellow_Oleander_(Thevetia_peruviana)_leaves_%26_flowers_in_Kolkata_W_IMG_8008.jpg) |
| starr-060916-8881-thevetia-peruviana | — | Forest &amp; Kim Starr | CC BY 3.0 | non | [voir](https://commons.wikimedia.org/wiki/File:Starr_060916-8881_Thevetia_peruviana.jpg) |
### mansiniyé — *Hippomane mancinella* (`mansiniye`)
Taxonomie vérifiée le 2026-07-27 contre [Wikidata Q636480](https://www.wikidata.org/wiki/Q636480)
et [GBIF 3063705](https://www.gbif.org/species/3063705).
| média | vue | auteur | licence | validé | page dorigine |
|---|---|---|---|---|---|
| hippomane-mancinella-hocquart-1821 | — | M. Hocquart | domaine public | non | [voir](https://commons.wikimedia.org/wiki/File:Hippomane_mancinella-Hocquart_1821.jpeg) |
| hyacinthus-orientalis-and-hippomane-mancinella | — | "The Universal Herbal" by Thomas Green (published 181620) | domaine public | non | [voir](https://commons.wikimedia.org/wiki/File:Hyacinthus_orientalis_and_Hippomane_mancinella.gif) |
| hippomane-mancinella-jacquin | — | Nicolás Joseph Jacquin | domaine public | non | [voir](https://commons.wikimedia.org/wiki/File:Hippomane_mancinella-Jacquin.jpeg) |
### medsinyé — *Jatropha curcas* (`medisinye`)
Taxonomie vérifiée le 2026-07-27 contre [Wikidata Q74644](https://www.wikidata.org/wiki/Q74644)
et [GBIF 3072953](https://www.gbif.org/species/3072953).
| média | vue | auteur | licence | validé | page dorigine |
|---|---|---|---|---|---|
| jatropha-curcas-blanco2-384 | — | Francisco Manuel Blanco (O.S.A.) | domaine public | non | [voir](https://commons.wikimedia.org/wiki/File:Jatropha_curcas_Blanco2.384.jpg) |
| jatropha-curcas-blanco2-384-cropped | — | Francisco Manuel Blanco (O.S.A.) | domaine public | non | [voir](https://commons.wikimedia.org/wiki/File:Jatropha_curcas_Blanco2.384-cropped.jpg) |
| georg-forster-purgiernuss | — | Georg Forster | domaine public | non | [voir](https://commons.wikimedia.org/wiki/File:Georg_Forster_-_Purgiernuss.jpeg) |
### pòm-dlo — *Syzygium samarangense* (`pom-dlo`)
Taxonomie vérifiée le 2026-07-27 contre [Wikidata Q11643111](https://www.wikidata.org/wiki/Q11643111)
et [GBIF 3183180](https://www.gbif.org/species/3183180).
| média | vue | auteur | licence | validé | page dorigine |
|---|---|---|---|---|---|
| champanga-flower-buds | — | Vinayaraj | CC BY-SA 3.0 | non | [voir](https://commons.wikimedia.org/wiki/File:Champanga_flower_buds.jpg) |
| lainwu-wax-apple-diamond-p00063 | — | Taiwan7007 | CC BY 3.0 | non | [voir](https://commons.wikimedia.org/wiki/File:Lainwu_(Wax_apple)_diamond_P00063.JPG) |
| 9956kfsyzygium-samarangense-pampangafvf-05 | — | Judgefloro | CC BY-SA 4.0 | non | [voir](https://commons.wikimedia.org/wiki/File:9956kfSyzygium_samarangense_Pampangafvf_05.JPG) |
### pòm-kajou — *Anacardium occidentale* (`pom-kajou`)
Taxonomie vérifiée le 2026-07-27 contre [Wikidata Q34007](https://www.wikidata.org/wiki/Q34007)
et [GBIF 5421368](https://www.gbif.org/species/5421368).
| média | vue | auteur | licence | validé | page dorigine |
|---|---|---|---|---|---|
| anacardium-occidentale-kohler-s-medizinal-pflanzen-010 | — | Franz Eugen Köhler, Köhler's Medizinal-Pflanzen | domaine public | non | [voir](https://commons.wikimedia.org/wiki/File:Anacardium_occidentale_-_K%C3%B6hler%E2%80%93s_Medizinal-Pflanzen-010.jpg) |
| cashew2-flower | — | Aruna at Malayalam Wikipedia | CC BY-SA 3.0 | non | [voir](https://commons.wikimedia.org/wiki/File:Cashew2-flower.JPG) |
| cashew-apples | — | Abhishek Jacob | CC BY-SA 3.0 | non | [voir](https://commons.wikimedia.org/wiki/File:Cashew_apples.jpg) |
### pòm-kannèl — *Annona squamosa* (`pom-kannel`)
Taxonomie vérifiée le 2026-07-27 contre [Wikidata Q275620](https://www.wikidata.org/wiki/Q275620)
et [GBIF 5407099](https://www.gbif.org/species/5407099).
| média | vue | auteur | licence | validé | page dorigine |
|---|---|---|---|---|---|
| annona-squamosa-custurd-apple-plant-in-hyderabad-ap-w-img-93 | — | J.M.Garg | CC BY-SA 4.0 | non | [voir](https://commons.wikimedia.org/wiki/File:Annona_squamosa_(Custurd_Apple)_plant_in_Hyderabad,_AP_W_IMG_9354.jpg) |
| annona-squamosa-fruits-leaves | — | Jim Conrad | domaine public | non | [voir](https://commons.wikimedia.org/wiki/File:Annona_squamosa-fruits-leaves.jpg) |
| sharifa | — | Miansari66 | CC0 1.0 (domaine public volontaire) | non | [voir](https://commons.wikimedia.org/wiki/File:Sharifa.JPG) |
### pòm-sitè — *Spondias dulcis* (`pom-site`)
Taxonomie vérifiée le 2026-07-27 contre [Wikidata Q500383](https://www.wikidata.org/wiki/Q500383)
et [GBIF 3190595](https://www.gbif.org/species/3190595).
| média | vue | auteur | licence | validé | page dorigine |
|---|---|---|---|---|---|
| spondia-dulcis-blanco1-132 | — | Francisco Manuel Blanco (O.S.A.) | domaine public | non | [voir](https://commons.wikimedia.org/wiki/File:Spondia_dulcis_Blanco1.132.png) |
| spondia-dulcis-blanco1-132-cropped | — | Francisco Manuel Blanco (O.S.A.) | domaine public | non | [voir](https://commons.wikimedia.org/wiki/File:Spondia_dulcis_Blanco1.132-cropped.jpg) |
| spondia-dulcis-blanco1-132-2 | — | Francisco Manuel Blanco (O.S.A.) | domaine public | non | [voir](https://commons.wikimedia.org/wiki/File:Spondia_dulcis_Blanco1.132.jpg) |
### zikak — *Chrysobalanus icaco* (`zikak`)
Taxonomie vérifiée le 2026-07-27 contre [Wikidata Q577669](https://www.wikidata.org/wiki/Q577669)
et [GBIF 2985082](https://www.gbif.org/species/2985082).
| média | vue | auteur | licence | validé | page dorigine |
|---|---|---|---|---|---|
| starr-031108-2161-chrysobalanus-icaco | — | Forest &amp; Kim Starr | CC BY 3.0 | non | [voir](https://commons.wikimedia.org/wiki/File:Starr_031108-2161_Chrysobalanus_icaco.jpg) |
| chrysobalanus-icaco-inflorescense | — | Hans Hillewaert | CC BY-SA 3.0 | non | [voir](https://commons.wikimedia.org/wiki/File:Chrysobalanus_icaco_(inflorescense).jpg) |
| flore-medicale-des-antilles-ou-traite-des-plantes-usuelles-p | — | Descourtilz, J. Theodore.; Descourtilz, M. E.; Pichard. | domaine public | non | [voir](https://commons.wikimedia.org/wiki/File:Flore_m%C3%A9dicale_des_Antilles,_ou,_Trait%C3%A9_des_plantes_usuelles_(Pl._84)_(8201963925).jpg) |
## Sources factuelles
- **Wikidata** — identifiants et taxonomie (CC0). https://www.wikidata.org
- **GBIF** — noms scientifiques acceptés et clés dusage. https://www.gbif.org
- **Wikimedia Commons** — photographies. https://commons.wikimedia.org
Voir `SOURCES.md` pour le détail des régimes de licence et `docs/audit-sources.md`
pour laudit complet, TRAMIL et CIRAD compris.
+661
View File
@@ -0,0 +1,661 @@
GNU AFFERO GENERAL PUBLIC LICENSE
Version 3, 19 November 2007
Copyright (C) 2007 Free Software Foundation, Inc. <https://fsf.org/>
Everyone is permitted to copy and distribute verbatim copies
of this license document, but changing it is not allowed.
Preamble
The GNU Affero General Public License is a free, copyleft license for
software and other kinds of works, specifically designed to ensure
cooperation with the community in the case of network server software.
The licenses for most software and other practical works are designed
to take away your freedom to share and change the works. By contrast,
our General Public Licenses are intended to guarantee your freedom to
share and change all versions of a program--to make sure it remains free
software for all its users.
When we speak of free software, we are referring to freedom, not
price. Our General Public Licenses are designed to make sure that you
have the freedom to distribute copies of free software (and charge for
them if you wish), that you receive source code or can get it if you
want it, that you can change the software or use pieces of it in new
free programs, and that you know you can do these things.
Developers that use our General Public Licenses protect your rights
with two steps: (1) assert copyright on the software, and (2) offer
you this License which gives you legal permission to copy, distribute
and/or modify the software.
A secondary benefit of defending all users' freedom is that
improvements made in alternate versions of the program, if they
receive widespread use, become available for other developers to
incorporate. Many developers of free software are heartened and
encouraged by the resulting cooperation. However, in the case of
software used on network servers, this result may fail to come about.
The GNU General Public License permits making a modified version and
letting the public access it on a server without ever releasing its
source code to the public.
The GNU Affero General Public License is designed specifically to
ensure that, in such cases, the modified source code becomes available
to the community. It requires the operator of a network server to
provide the source code of the modified version running there to the
users of that server. Therefore, public use of a modified version, on
a publicly accessible server, gives the public access to the source
code of the modified version.
An older license, called the Affero General Public License and
published by Affero, was designed to accomplish similar goals. This is
a different license, not a version of the Affero GPL, but Affero has
released a new version of the Affero GPL which permits relicensing under
this license.
The precise terms and conditions for copying, distribution and
modification follow.
TERMS AND CONDITIONS
0. Definitions.
"This License" refers to version 3 of the GNU Affero General Public License.
"Copyright" also means copyright-like laws that apply to other kinds of
works, such as semiconductor masks.
"The Program" refers to any copyrightable work licensed under this
License. Each licensee is addressed as "you". "Licensees" and
"recipients" may be individuals or organizations.
To "modify" a work means to copy from or adapt all or part of the work
in a fashion requiring copyright permission, other than the making of an
exact copy. The resulting work is called a "modified version" of the
earlier work or a work "based on" the earlier work.
A "covered work" means either the unmodified Program or a work based
on the Program.
To "propagate" a work means to do anything with it that, without
permission, would make you directly or secondarily liable for
infringement under applicable copyright law, except executing it on a
computer or modifying a private copy. Propagation includes copying,
distribution (with or without modification), making available to the
public, and in some countries other activities as well.
To "convey" a work means any kind of propagation that enables other
parties to make or receive copies. Mere interaction with a user through
a computer network, with no transfer of a copy, is not conveying.
An interactive user interface displays "Appropriate Legal Notices"
to the extent that it includes a convenient and prominently visible
feature that (1) displays an appropriate copyright notice, and (2)
tells the user that there is no warranty for the work (except to the
extent that warranties are provided), that licensees may convey the
work under this License, and how to view a copy of this License. If
the interface presents a list of user commands or options, such as a
menu, a prominent item in the list meets this criterion.
1. Source Code.
The "source code" for a work means the preferred form of the work
for making modifications to it. "Object code" means any non-source
form of a work.
A "Standard Interface" means an interface that either is an official
standard defined by a recognized standards body, or, in the case of
interfaces specified for a particular programming language, one that
is widely used among developers working in that language.
The "System Libraries" of an executable work include anything, other
than the work as a whole, that (a) is included in the normal form of
packaging a Major Component, but which is not part of that Major
Component, and (b) serves only to enable use of the work with that
Major Component, or to implement a Standard Interface for which an
implementation is available to the public in source code form. A
"Major Component", in this context, means a major essential component
(kernel, window system, and so on) of the specific operating system
(if any) on which the executable work runs, or a compiler used to
produce the work, or an object code interpreter used to run it.
The "Corresponding Source" for a work in object code form means all
the source code needed to generate, install, and (for an executable
work) run the object code and to modify the work, including scripts to
control those activities. However, it does not include the work's
System Libraries, or general-purpose tools or generally available free
programs which are used unmodified in performing those activities but
which are not part of the work. For example, Corresponding Source
includes interface definition files associated with source files for
the work, and the source code for shared libraries and dynamically
linked subprograms that the work is specifically designed to require,
such as by intimate data communication or control flow between those
subprograms and other parts of the work.
The Corresponding Source need not include anything that users
can regenerate automatically from other parts of the Corresponding
Source.
The Corresponding Source for a work in source code form is that
same work.
2. Basic Permissions.
All rights granted under this License are granted for the term of
copyright on the Program, and are irrevocable provided the stated
conditions are met. This License explicitly affirms your unlimited
permission to run the unmodified Program. The output from running a
covered work is covered by this License only if the output, given its
content, constitutes a covered work. This License acknowledges your
rights of fair use or other equivalent, as provided by copyright law.
You may make, run and propagate covered works that you do not
convey, without conditions so long as your license otherwise remains
in force. You may convey covered works to others for the sole purpose
of having them make modifications exclusively for you, or provide you
with facilities for running those works, provided that you comply with
the terms of this License in conveying all material for which you do
not control copyright. Those thus making or running the covered works
for you must do so exclusively on your behalf, under your direction
and control, on terms that prohibit them from making any copies of
your copyrighted material outside their relationship with you.
Conveying under any other circumstances is permitted solely under
the conditions stated below. Sublicensing is not allowed; section 10
makes it unnecessary.
3. Protecting Users' Legal Rights From Anti-Circumvention Law.
No covered work shall be deemed part of an effective technological
measure under any applicable law fulfilling obligations under article
11 of the WIPO copyright treaty adopted on 20 December 1996, or
similar laws prohibiting or restricting circumvention of such
measures.
When you convey a covered work, you waive any legal power to forbid
circumvention of technological measures to the extent such circumvention
is effected by exercising rights under this License with respect to
the covered work, and you disclaim any intention to limit operation or
modification of the work as a means of enforcing, against the work's
users, your or third parties' legal rights to forbid circumvention of
technological measures.
4. Conveying Verbatim Copies.
You may convey verbatim copies of the Program's source code as you
receive it, in any medium, provided that you conspicuously and
appropriately publish on each copy an appropriate copyright notice;
keep intact all notices stating that this License and any
non-permissive terms added in accord with section 7 apply to the code;
keep intact all notices of the absence of any warranty; and give all
recipients a copy of this License along with the Program.
You may charge any price or no price for each copy that you convey,
and you may offer support or warranty protection for a fee.
5. Conveying Modified Source Versions.
You may convey a work based on the Program, or the modifications to
produce it from the Program, in the form of source code under the
terms of section 4, provided that you also meet all of these conditions:
a) The work must carry prominent notices stating that you modified
it, and giving a relevant date.
b) The work must carry prominent notices stating that it is
released under this License and any conditions added under section
7. This requirement modifies the requirement in section 4 to
"keep intact all notices".
c) You must license the entire work, as a whole, under this
License to anyone who comes into possession of a copy. This
License will therefore apply, along with any applicable section 7
additional terms, to the whole of the work, and all its parts,
regardless of how they are packaged. This License gives no
permission to license the work in any other way, but it does not
invalidate such permission if you have separately received it.
d) If the work has interactive user interfaces, each must display
Appropriate Legal Notices; however, if the Program has interactive
interfaces that do not display Appropriate Legal Notices, your
work need not make them do so.
A compilation of a covered work with other separate and independent
works, which are not by their nature extensions of the covered work,
and which are not combined with it such as to form a larger program,
in or on a volume of a storage or distribution medium, is called an
"aggregate" if the compilation and its resulting copyright are not
used to limit the access or legal rights of the compilation's users
beyond what the individual works permit. Inclusion of a covered work
in an aggregate does not cause this License to apply to the other
parts of the aggregate.
6. Conveying Non-Source Forms.
You may convey a covered work in object code form under the terms
of sections 4 and 5, provided that you also convey the
machine-readable Corresponding Source under the terms of this License,
in one of these ways:
a) Convey the object code in, or embodied in, a physical product
(including a physical distribution medium), accompanied by the
Corresponding Source fixed on a durable physical medium
customarily used for software interchange.
b) Convey the object code in, or embodied in, a physical product
(including a physical distribution medium), accompanied by a
written offer, valid for at least three years and valid for as
long as you offer spare parts or customer support for that product
model, to give anyone who possesses the object code either (1) a
copy of the Corresponding Source for all the software in the
product that is covered by this License, on a durable physical
medium customarily used for software interchange, for a price no
more than your reasonable cost of physically performing this
conveying of source, or (2) access to copy the
Corresponding Source from a network server at no charge.
c) Convey individual copies of the object code with a copy of the
written offer to provide the Corresponding Source. This
alternative is allowed only occasionally and noncommercially, and
only if you received the object code with such an offer, in accord
with subsection 6b.
d) Convey the object code by offering access from a designated
place (gratis or for a charge), and offer equivalent access to the
Corresponding Source in the same way through the same place at no
further charge. You need not require recipients to copy the
Corresponding Source along with the object code. If the place to
copy the object code is a network server, the Corresponding Source
may be on a different server (operated by you or a third party)
that supports equivalent copying facilities, provided you maintain
clear directions next to the object code saying where to find the
Corresponding Source. Regardless of what server hosts the
Corresponding Source, you remain obligated to ensure that it is
available for as long as needed to satisfy these requirements.
e) Convey the object code using peer-to-peer transmission, provided
you inform other peers where the object code and Corresponding
Source of the work are being offered to the general public at no
charge under subsection 6d.
A separable portion of the object code, whose source code is excluded
from the Corresponding Source as a System Library, need not be
included in conveying the object code work.
A "User Product" is either (1) a "consumer product", which means any
tangible personal property which is normally used for personal, family,
or household purposes, or (2) anything designed or sold for incorporation
into a dwelling. In determining whether a product is a consumer product,
doubtful cases shall be resolved in favor of coverage. For a particular
product received by a particular user, "normally used" refers to a
typical or common use of that class of product, regardless of the status
of the particular user or of the way in which the particular user
actually uses, or expects or is expected to use, the product. A product
is a consumer product regardless of whether the product has substantial
commercial, industrial or non-consumer uses, unless such uses represent
the only significant mode of use of the product.
"Installation Information" for a User Product means any methods,
procedures, authorization keys, or other information required to install
and execute modified versions of a covered work in that User Product from
a modified version of its Corresponding Source. The information must
suffice to ensure that the continued functioning of the modified object
code is in no case prevented or interfered with solely because
modification has been made.
If you convey an object code work under this section in, or with, or
specifically for use in, a User Product, and the conveying occurs as
part of a transaction in which the right of possession and use of the
User Product is transferred to the recipient in perpetuity or for a
fixed term (regardless of how the transaction is characterized), the
Corresponding Source conveyed under this section must be accompanied
by the Installation Information. But this requirement does not apply
if neither you nor any third party retains the ability to install
modified object code on the User Product (for example, the work has
been installed in ROM).
The requirement to provide Installation Information does not include a
requirement to continue to provide support service, warranty, or updates
for a work that has been modified or installed by the recipient, or for
the User Product in which it has been modified or installed. Access to a
network may be denied when the modification itself materially and
adversely affects the operation of the network or violates the rules and
protocols for communication across the network.
Corresponding Source conveyed, and Installation Information provided,
in accord with this section must be in a format that is publicly
documented (and with an implementation available to the public in
source code form), and must require no special password or key for
unpacking, reading or copying.
7. Additional Terms.
"Additional permissions" are terms that supplement the terms of this
License by making exceptions from one or more of its conditions.
Additional permissions that are applicable to the entire Program shall
be treated as though they were included in this License, to the extent
that they are valid under applicable law. If additional permissions
apply only to part of the Program, that part may be used separately
under those permissions, but the entire Program remains governed by
this License without regard to the additional permissions.
When you convey a copy of a covered work, you may at your option
remove any additional permissions from that copy, or from any part of
it. (Additional permissions may be written to require their own
removal in certain cases when you modify the work.) You may place
additional permissions on material, added by you to a covered work,
for which you have or can give appropriate copyright permission.
Notwithstanding any other provision of this License, for material you
add to a covered work, you may (if authorized by the copyright holders of
that material) supplement the terms of this License with terms:
a) Disclaiming warranty or limiting liability differently from the
terms of sections 15 and 16 of this License; or
b) Requiring preservation of specified reasonable legal notices or
author attributions in that material or in the Appropriate Legal
Notices displayed by works containing it; or
c) Prohibiting misrepresentation of the origin of that material, or
requiring that modified versions of such material be marked in
reasonable ways as different from the original version; or
d) Limiting the use for publicity purposes of names of licensors or
authors of the material; or
e) Declining to grant rights under trademark law for use of some
trade names, trademarks, or service marks; or
f) Requiring indemnification of licensors and authors of that
material by anyone who conveys the material (or modified versions of
it) with contractual assumptions of liability to the recipient, for
any liability that these contractual assumptions directly impose on
those licensors and authors.
All other non-permissive additional terms are considered "further
restrictions" within the meaning of section 10. If the Program as you
received it, or any part of it, contains a notice stating that it is
governed by this License along with a term that is a further
restriction, you may remove that term. If a license document contains
a further restriction but permits relicensing or conveying under this
License, you may add to a covered work material governed by the terms
of that license document, provided that the further restriction does
not survive such relicensing or conveying.
If you add terms to a covered work in accord with this section, you
must place, in the relevant source files, a statement of the
additional terms that apply to those files, or a notice indicating
where to find the applicable terms.
Additional terms, permissive or non-permissive, may be stated in the
form of a separately written license, or stated as exceptions;
the above requirements apply either way.
8. Termination.
You may not propagate or modify a covered work except as expressly
provided under this License. Any attempt otherwise to propagate or
modify it is void, and will automatically terminate your rights under
this License (including any patent licenses granted under the third
paragraph of section 11).
However, if you cease all violation of this License, then your
license from a particular copyright holder is reinstated (a)
provisionally, unless and until the copyright holder explicitly and
finally terminates your license, and (b) permanently, if the copyright
holder fails to notify you of the violation by some reasonable means
prior to 60 days after the cessation.
Moreover, your license from a particular copyright holder is
reinstated permanently if the copyright holder notifies you of the
violation by some reasonable means, this is the first time you have
received notice of violation of this License (for any work) from that
copyright holder, and you cure the violation prior to 30 days after
your receipt of the notice.
Termination of your rights under this section does not terminate the
licenses of parties who have received copies or rights from you under
this License. If your rights have been terminated and not permanently
reinstated, you do not qualify to receive new licenses for the same
material under section 10.
9. Acceptance Not Required for Having Copies.
You are not required to accept this License in order to receive or
run a copy of the Program. Ancillary propagation of a covered work
occurring solely as a consequence of using peer-to-peer transmission
to receive a copy likewise does not require acceptance. However,
nothing other than this License grants you permission to propagate or
modify any covered work. These actions infringe copyright if you do
not accept this License. Therefore, by modifying or propagating a
covered work, you indicate your acceptance of this License to do so.
10. Automatic Licensing of Downstream Recipients.
Each time you convey a covered work, the recipient automatically
receives a license from the original licensors, to run, modify and
propagate that work, subject to this License. You are not responsible
for enforcing compliance by third parties with this License.
An "entity transaction" is a transaction transferring control of an
organization, or substantially all assets of one, or subdividing an
organization, or merging organizations. If propagation of a covered
work results from an entity transaction, each party to that
transaction who receives a copy of the work also receives whatever
licenses to the work the party's predecessor in interest had or could
give under the previous paragraph, plus a right to possession of the
Corresponding Source of the work from the predecessor in interest, if
the predecessor has it or can get it with reasonable efforts.
You may not impose any further restrictions on the exercise of the
rights granted or affirmed under this License. For example, you may
not impose a license fee, royalty, or other charge for exercise of
rights granted under this License, and you may not initiate litigation
(including a cross-claim or counterclaim in a lawsuit) alleging that
any patent claim is infringed by making, using, selling, offering for
sale, or importing the Program or any portion of it.
11. Patents.
A "contributor" is a copyright holder who authorizes use under this
License of the Program or a work on which the Program is based. The
work thus licensed is called the contributor's "contributor version".
A contributor's "essential patent claims" are all patent claims
owned or controlled by the contributor, whether already acquired or
hereafter acquired, that would be infringed by some manner, permitted
by this License, of making, using, or selling its contributor version,
but do not include claims that would be infringed only as a
consequence of further modification of the contributor version. For
purposes of this definition, "control" includes the right to grant
patent sublicenses in a manner consistent with the requirements of
this License.
Each contributor grants you a non-exclusive, worldwide, royalty-free
patent license under the contributor's essential patent claims, to
make, use, sell, offer for sale, import and otherwise run, modify and
propagate the contents of its contributor version.
In the following three paragraphs, a "patent license" is any express
agreement or commitment, however denominated, not to enforce a patent
(such as an express permission to practice a patent or covenant not to
sue for patent infringement). To "grant" such a patent license to a
party means to make such an agreement or commitment not to enforce a
patent against the party.
If you convey a covered work, knowingly relying on a patent license,
and the Corresponding Source of the work is not available for anyone
to copy, free of charge and under the terms of this License, through a
publicly available network server or other readily accessible means,
then you must either (1) cause the Corresponding Source to be so
available, or (2) arrange to deprive yourself of the benefit of the
patent license for this particular work, or (3) arrange, in a manner
consistent with the requirements of this License, to extend the patent
license to downstream recipients. "Knowingly relying" means you have
actual knowledge that, but for the patent license, your conveying the
covered work in a country, or your recipient's use of the covered work
in a country, would infringe one or more identifiable patents in that
country that you have reason to believe are valid.
If, pursuant to or in connection with a single transaction or
arrangement, you convey, or propagate by procuring conveyance of, a
covered work, and grant a patent license to some of the parties
receiving the covered work authorizing them to use, propagate, modify
or convey a specific copy of the covered work, then the patent license
you grant is automatically extended to all recipients of the covered
work and works based on it.
A patent license is "discriminatory" if it does not include within
the scope of its coverage, prohibits the exercise of, or is
conditioned on the non-exercise of one or more of the rights that are
specifically granted under this License. You may not convey a covered
work if you are a party to an arrangement with a third party that is
in the business of distributing software, under which you make payment
to the third party based on the extent of your activity of conveying
the work, and under which the third party grants, to any of the
parties who would receive the covered work from you, a discriminatory
patent license (a) in connection with copies of the covered work
conveyed by you (or copies made from those copies), or (b) primarily
for and in connection with specific products or compilations that
contain the covered work, unless you entered into that arrangement,
or that patent license was granted, prior to 28 March 2007.
Nothing in this License shall be construed as excluding or limiting
any implied license or other defenses to infringement that may
otherwise be available to you under applicable patent law.
12. No Surrender of Others' Freedom.
If conditions are imposed on you (whether by court order, agreement or
otherwise) that contradict the conditions of this License, they do not
excuse you from the conditions of this License. If you cannot convey a
covered work so as to satisfy simultaneously your obligations under this
License and any other pertinent obligations, then as a consequence you may
not convey it at all. For example, if you agree to terms that obligate you
to collect a royalty for further conveying from those to whom you convey
the Program, the only way you could satisfy both those terms and this
License would be to refrain entirely from conveying the Program.
13. Remote Network Interaction; Use with the GNU General Public License.
Notwithstanding any other provision of this License, if you modify the
Program, your modified version must prominently offer all users
interacting with it remotely through a computer network (if your version
supports such interaction) an opportunity to receive the Corresponding
Source of your version by providing access to the Corresponding Source
from a network server at no charge, through some standard or customary
means of facilitating copying of software. This Corresponding Source
shall include the Corresponding Source for any work covered by version 3
of the GNU General Public License that is incorporated pursuant to the
following paragraph.
Notwithstanding any other provision of this License, you have
permission to link or combine any covered work with a work licensed
under version 3 of the GNU General Public License into a single
combined work, and to convey the resulting work. The terms of this
License will continue to apply to the part which is the covered work,
but the work with which it is combined will remain governed by version
3 of the GNU General Public License.
14. Revised Versions of this License.
The Free Software Foundation may publish revised and/or new versions of
the GNU Affero General Public License from time to time. Such new versions
will be similar in spirit to the present version, but may differ in detail to
address new problems or concerns.
Each version is given a distinguishing version number. If the
Program specifies that a certain numbered version of the GNU Affero General
Public License "or any later version" applies to it, you have the
option of following the terms and conditions either of that numbered
version or of any later version published by the Free Software
Foundation. If the Program does not specify a version number of the
GNU Affero General Public License, you may choose any version ever published
by the Free Software Foundation.
If the Program specifies that a proxy can decide which future
versions of the GNU Affero General Public License can be used, that proxy's
public statement of acceptance of a version permanently authorizes you
to choose that version for the Program.
Later license versions may give you additional or different
permissions. However, no additional obligations are imposed on any
author or copyright holder as a result of your choosing to follow a
later version.
15. Disclaimer of Warranty.
THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY
APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT
HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY
OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO,
THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM
IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF
ALL NECESSARY SERVICING, REPAIR OR CORRECTION.
16. Limitation of Liability.
IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS
THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY
GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE
USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF
DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD
PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS),
EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF
SUCH DAMAGES.
17. Interpretation of Sections 15 and 16.
If the disclaimer of warranty and limitation of liability provided
above cannot be given local legal effect according to their terms,
reviewing courts shall apply local law that most closely approximates
an absolute waiver of all civil liability in connection with the
Program, unless a warranty or assumption of liability accompanies a
copy of the Program in return for a fee.
END OF TERMS AND CONDITIONS
How to Apply These Terms to Your New Programs
If you develop a new program, and you want it to be of the greatest
possible use to the public, the best way to achieve this is to make it
free software which everyone can redistribute and change under these terms.
To do so, attach the following notices to the program. It is safest
to attach them to the start of each source file to most effectively
state the exclusion of warranty; and each file should have at least
the "copyright" line and a pointer to where the full notice is found.
<one line to give the program's name and a brief idea of what it does.>
Copyright (C) <year> <name of author>
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU Affero General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU Affero General Public License for more details.
You should have received a copy of the GNU Affero General Public License
along with this program. If not, see <https://www.gnu.org/licenses/>.
Also add information on how to contact you by electronic and paper mail.
If your software can interact with users remotely through a computer
network, you should also make sure that it provides a way for users to
get its source. For example, if your program is a web application, its
interface could display a "Source" link that leads users to an archive
of the code. There are many ways you could offer source, and different
solutions will be better for different programs; see section 13 for the
specific requirements.
You should also get your employer (if you work as a programmer) or school,
if any, to sign a "copyright disclaimer" for the program, if necessary.
For more information on this, and how to apply and follow the GNU AGPL, see
<https://www.gnu.org/licenses/>.
+70
View File
@@ -0,0 +1,70 @@
LICENCE DU CONTENU — KI FWI SA YÉ ?
====================================
Ce fichier concerne le CONTENU du projet. Le CODE est couvert par le fichier
`LICENSE` (GNU Affero General Public License, version 3 ou ultérieure).
1. Contenu produit par ORGANISATION KA INTERNATIONALE
------------------------------------------------------
Les textes rédigés pour ce projet — descriptions d'indices botaniques, fiches
encyclopédiques, textes du module « Pa touché », interface, documentation — ainsi
que les jeux de données structurées (`src/lib/data/`) sont mis à disposition sous :
Creative Commons Attribution - Partage dans les Mêmes Conditions 4.0
International (CC BY-SA 4.0)
Résumé : https://creativecommons.org/licenses/by-sa/4.0/deed.fr
Texte légal : https://creativecommons.org/licenses/by-sa/4.0/legalcode.fr
Attribution demandée :
« KI FWI SA YÉ ? » — ORGANISATION KA INTERNATIONALE (o-k-i.net), CC BY-SA 4.0
2. Médias tiers — leur licence propre s'applique, pas celle-ci
---------------------------------------------------------------
Les photographies, illustrations et enregistrements provenant de tiers (Wikimedia
Commons, iNaturalist, contributeurs individuels) NE SONT PAS relicenciés par ce
fichier. Chacun reste sous sa licence d'origine, listée média par média dans
`CREDITS.md` et dans les données (`src/lib/data/fruits/*.json`).
Le projet constitue à leur égard une ŒUVRE COLLECTIVE : les médias y sont
juxtaposés, jamais fondus dans une œuvre dérivée. Cette distinction est ce qui
permet de faire cohabiter des médias CC BY-SA et des médias CC BY-NC dans un même
produit. Elle impose une contrainte technique absolue :
AUCUN COMPOSITING. Un média tiers n'est jamais fusionné, incrusté, détouré
puis recombiné, ni intégré à un atlas de textures avec d'autres médias.
Cette contrainte est vérifiée par script : `npm run validate:data` refuse tout
média marqué `composite: true` dès lors qu'il porte une clause de partage à
l'identique ou une clause non commerciale.
3. Clause non commerciale — engagement irréversible
-----------------------------------------------------
Le projet accepte des médias sous licence Creative Commons Attribution - Pas
d'Utilisation Commerciale (CC BY-NC). En conséquence, et tant que ces médias sont
embarqués :
« KI FWI SA YÉ ? » NE PEUT PAS être distribué à titre commercial.
Ni vente, ni version payante, ni licence à un éditeur, ni intégration dans
une offre commerciale.
Le code, lui, reste librement réutilisable sous AGPL-3.0-or-later, y compris à
titre commercial, dès lors qu'il est séparé de ces médias.
Décision, motifs et condition de réexamen : `docs/adr/0001-licences.md`.
4. Enregistrements audio kréyòl
---------------------------------
Les enregistrements de prononciation sont réalisés par des locuteurs humains qui
en conservent les droits voisins. Chaque locuteur doit avoir donné une autorisation
écrite avant embarquement, et est crédité nominativement dans `CREDITS.md`.
Aucune synthèse vocale n'est utilisée.
+72
View File
@@ -0,0 +1,72 @@
# KI FWI SA YÉ ?
Jeu éducatif libre qui apprend aux enfants des Antilles à reconnaître les fruits, les arbres
et les plantes de leurs îles. Le kréyòl est la langue principale ; le français en est la
traduction.
Porté par **ORGANISATION KA INTERNATIONALE** — [o-k-i.net](https://o-k-i.net).
> **État : session 0 terminée.** Cadre juridique, outillage de données et dataset vérifié.
> Aucun code applicatif n'est encore écrit. Voir [`docs/plan.md`](docs/plan.md).
## Le principe
Le jeu enseigne la reconnaissance du **réel**. Deux filières d'assets, jamais mélangées :
- **Filière A — vérité.** Photographies réelles. Seule filière autorisée pour tout ce qui
sert à identifier : épreuves, indices, fiches.
- **Filière B — décor.** Images générées. Fonds, sprites, badges. Jamais une épreuve.
Les modèles de diffusion connaissent mal le corossol, à peine la quenette, presque pas le
zikak. Ils produisent des fruits *plausibles et faux*. Un jeu d'identification bâti sur des
assets générés apprend l'erreur.
Cette règle n'est pas une consigne : c'est un script. `npm run validate:data` fait échouer
le build si une épreuve s'appuie sur un média non validé, et `npm run test:porte` prouve que
ce refus se produit.
## Commandes
```bash
npm install
npm run verify:taxa # vérifie la taxonomie contre Wikidata et GBIF
npm run ingest:commons # remonte les photos candidates sous licence libre
npm run build:dataset # compose les entrées (--force pour écraser)
npm run validate:data # la porte : schéma + règles métier
npm run test:porte # prouve que la porte refuse ce qu'elle doit refuser
npm run build:credits # régénère CREDITS.md depuis les données
npm run check:audio # liste les enregistrements kréyòl manquants
```
Ces scripts vivent dans `tools/data/`, hors du bundle. **Aucun appel réseau ne subsistera au
runtime du jeu** : tout est cuit au build.
## Où regarder
| Fichier | Contenu |
|---|---|
| [`docs/plan.md`](docs/plan.md) | les 7 sessions et leurs portes de sortie mesurables |
| [`docs/adr/`](docs/adr/) | les cinq décisions d'architecture et leurs motifs |
| [`docs/audit-sources.md`](docs/audit-sources.md) | ce qu'on prend à chaque source, sous quelle licence |
| [`docs/a-arbitrer.md`](docs/a-arbitrer.md) | ce qu'un humain doit trancher avant publication |
| [`docs/kreyol-a-relire.md`](docs/kreyol-a-relire.md) | les incertitudes orthographiques, signalées non corrigées |
| [`docs/planche-relecture-medias.md`](docs/planche-relecture-medias.md) | les 130 photos candidates à valider |
| [`fruits.schema.json`](fruits.schema.json) | le contrat des données |
| [`CREDITS.md`](CREDITS.md) | attributions, généré — ne pas éditer |
## Licences
- **Code :** [AGPL-3.0-or-later](LICENSE)
- **Contenu OKI :** [CC BY-SA 4.0](LICENSE-CONTENT)
- **Médias tiers :** licence d'origine conservée, listée média par média dans
[`CREDITS.md`](CREDITS.md). Le jeu est une œuvre **collective**, pas dérivée — d'où
l'interdiction absolue de compositing, vérifiée par script.
Rien n'est « libre de droit ». Voir [`SOURCES.md`](SOURCES.md) et
[`docs/adr/0001-licences.md`](docs/adr/0001-licences.md).
## Ce que le code ne fera jamais
Aucun compte, aucune publicité, aucun traceur, aucune requête vers un domaine tiers au
runtime, aucune collecte de données sur les enfants. Le jeu est entièrement jouable hors
ligne après une première visite.
+46
View File
@@ -0,0 +1,46 @@
# Sources — KI FWI SA YÉ ?
Rien n'est « libre de droit ». Chaque source a un régime, chaque régime a une contrainte.
Ce fichier en donne l'état ; l'audit détaillé est dans [`docs/audit-sources.md`](docs/audit-sources.md),
les attributions média par média dans [`CREDITS.md`](CREDITS.md), et la décision de licence
dans [`docs/adr/0001-licences.md`](docs/adr/0001-licences.md).
## Sources utilisées
| Source | Usage | Régime | Contrainte principale |
|---|---|---|---|
| [Wikidata](https://www.wikidata.org) | identifiants Q, taxonomie | CC0 | croiser avec GBIF, toujours |
| [GBIF](https://www.gbif.org) | nom accepté, clé d'usage, famille | données ouvertes | détecte les synonymes |
| [Wikimedia Commons](https://commons.wikimedia.org) | photographies, planches | CC0 · PD · CC BY · CC BY-SA | attribution nominative · **aucun compositing** |
| [iNaturalist](https://www.inaturalist.org) | photographies de complément | ~93 % CC BY-NC | engage le non-commercial |
| Photographies du porteur | tout, en priorité | CC BY-SA 4.0 (OKI) | aucune |
## Sources citées, jamais copiées
| Source | Usage | Régime | Statut |
|---|---|---|---|
| [TRAMIL](https://www.tramil.net) | vérification factuelle | tous droits réservés | **demande écrite en attente** |
| [Agritrop / CIRAD](https://agritrop.cirad.fr) | vérification agronomique | mixte, majoritairement © | **demande écrite en attente** |
| [INRAE](https://www.inrae.fr) | vérification | mixte | **demande écrite en attente** |
Aucun fichier issu de ces trois sources n'entre dans le dépôt. Elles se citent dans le
champ `sources_factuelles` des entrées, avec titre, URL et date de consultation.
## Vérification
La taxonomie est vérifiée par script contre les deux référentiels, jamais de mémoire :
```bash
npm run verify:taxa
```
Rapport : [`docs/verification-taxons.md`](docs/verification-taxons.md).
Dernier passage — **13 taxons, 13 acceptés par GBIF, 0 divergence**.
## Ce qui bloque une publication
Un média ne peut porter une épreuve d'identification que s'il est une photographie réelle,
de filière A, validée par un humain nommé, avec sa vue renseignée. Un enregistrement audio
doit être une voix humaine. Une orthographe kréyòl doit être relue par un locuteur. Ces
règles sont vérifiées par `npm run validate:data` et prouvées par `npm run test:porte` :
ce ne sont pas des intentions.
+151
View File
@@ -0,0 +1,151 @@
# Points à arbitrer par un humain
> Le brief §9 est explicite : « Si une décision engage le juridique, la pédagogie ou la
> sécurité des enfants : arrête-toi et demande. Ce sont les trois domaines où une erreur ne
> se rattrape pas par un correctif. »
>
> Ce fichier liste ce que la session 0 a rencontré et **n'a pas tranché**. Chaque point
> indique la valeur provisoire retenue dans les données et pourquoi ce choix-là plutôt qu'un
> autre. Aucun n'est bloquant pour la session 1 ; tous le sont pour une publication.
---
## 1. `comestible: false` sur l'akée et la pomme-cajou — sous-estimation assumée
**Domaine : sécurité des enfants.**
Les cinq entrées du module « Pa touché » sortent de la composition avec `comestible: false`.
C'est **factuellement incomplet pour deux d'entre elles** :
- **Aki / akée** (*Blighia sapida*) — se mange, mais **uniquement** ouverte naturellement et
mûre, et seulement la partie charnue claire. Le fruit non mûr et les graines sont toxiques
(hypoglycine).
- **Pòm-kajou / pomme-cajou** (*Anacardium occidentale*) — la pomme se mange. C'est la coque
de la noix qui contient un liquide caustique.
**Pourquoi `false` malgré tout.** Entre deux erreurs possibles, l'une dit à un enfant « ce
fruit ne se mange pas » alors qu'il se mange sous conditions ; l'autre dit « ce fruit se
mange » à un enfant qui rencontrera un akée fermé. La seconde envoie aux urgences. Le
défaut prudent était le seul choix défendable sans arbitrage humain.
La nuance complète est présente dans `danger.resume` de chaque entrée, mot pour mot depuis
la graine. Rien n'est perdu ; c'est la valeur booléenne qui est grossière.
**À trancher :** comment l'interface exprime « comestible sous conditions strictes » sans
transformer une nuance en autorisation. Un booléen ne suffit probablement pas — un troisième
état (`conditionnel`) est possible, mais il faudra qu'il s'affiche de façon qu'un enfant de
sept ans ne le lise pas comme un oui.
---
## 2. Les fruits dangereux doivent-ils apparaître ailleurs que dans « Pa touché » ?
**Domaine : pédagogie et sécurité.**
État actuel : les cinq plantes sont en `categorie: "plante_dangereuse"`, et le validateur
**interdit** qu'un de leurs médias porte un usage `epreuve`. C'est l'application directe du
brief §6 — « jamais chronométré, jamais scoré, jamais transformé en épreuve d'adresse ».
Mais la pomme-cajou est aussi un fruit qu'on trouve au marché et que les enfants mangent.
L'exclure entièrement des modes d'apprentissage est peut-être une perte : un enfant qui sait
reconnaître une pomme-cajou et sait que la noix brûle est mieux armé qu'un enfant qui n'a
vu la plante que dans un module « danger ».
**À trancher :** une entrée peut-elle appartenir aux deux mondes ? Si oui, la règle
technique doit devenir plus fine que « catégorie dangereuse ⇒ pas d'épreuve », et cette
finesse est exactement le genre de chose qui se relâche silencieusement. La règle actuelle,
plus grossière, a le mérite d'être infranchissable.
---
## 3. Les mois de saisonnalité ne sont vérifiés contre rien
**Domaine : pédagogie.**
Les `saison_mois` des huit fruits proviennent de `fruits.seed.json` et **n'ont été vérifiés
contre aucune source** — contrairement à la taxonomie, contrôlée contre Wikidata et GBIF.
Deux problèmes distincts :
1. **Aucune source.** Rien ne les étaie aujourd'hui.
2. **Aucune distinction par île.** Le champ est unique alors que les entrées listent jusqu'à
quatre îles (`gp`, `mq`, `gf`, `re`). La Guyane et La Réunion n'ont pas le calendrier de
la Guadeloupe.
Or le mode « Sézon » repose entièrement sur ce champ, et le savoir qu'il prétend transmettre
est précisément celui qui se perd. Enseigner une saisonnalité fausse est pire que ne pas
l'enseigner.
**À trancher :** source de référence (CIRAD Antilles est le candidat naturel — lettre prête
dans `docs/courriers/cirad.md`), et passage éventuel à une structure par île. Tant que ce
n'est pas fait, **le mode Sézon ne doit pas être publié**, même s'il est techniquement prêt
en session 2.
---
## 4. Quelles photographies pour le mancenillier
**Domaine : sécurité des enfants.**
Le brief impose « aucun visuel anxiogène » sur le module « Pa touché ». Mais un enfant ne
peut éviter un mancenillier que s'il le reconnaît — et ce qu'il doit reconnaître, c'est
l'arbre entier au bord de la plage, la feuille à nervure médiane jaune, et le petit fruit
vert d'aspect appétissant.
Le danger est précisément que le fruit **paraisse bon**. La photographie utile est donc
celle d'un fruit qui a l'air appétissant, accompagnée du texte qui dit de ne pas y toucher.
**Difficulté matérielle constatée en session 0 :** les trois premiers candidats Commons pour
*Hippomane mancinella* sont **toutes des planches gravées** — Jacquin 1780, Green 1816-20,
Hocquart 1821. Aucune photographie moderne dans le haut de la pile. C'est l'entrée la plus
critique du module qui est la moins bien servie.
**À trancher :** la sélection des médias de `mansiniye`, image par image, par un humain. Ne
pas laisser ce choix à l'ordre de pertinence d'un moteur de recherche. Une photo de lésion
cutanée, par exemple, serait à la fois anxiogène et pédagogiquement inutile — l'enfant doit
reconnaître l'arbre, pas la brûlure.
**Voie la plus sûre :** photographier l'arbre soi-même sur le littoral. Il est signalé par
une bande de peinture rouge, ce qui rend la séance praticable et écarte tout risque de
confondre l'espèce.
À noter aussi : la bande de peinture rouge qui signale les mancenilliers sur le littoral
martiniquais et guadeloupéen est elle-même un indice à enseigner. Il est renseigné dans
`danger.signalement`.
---
## 5. `pòm-dlo` : trois noms, trois espèces
**Domaine : pédagogie.** Détaillé dans `docs/kreyol-a-relire.md` §3.
`pòm-dlo`, `pòm-malaka` et `pòm-rose` désignent des *Syzygium* différents selon les îles.
L'entrée actuelle associe `pòm-dlo` à *Syzygium samarangense* sur la seule foi de la graine.
La taxonomie de cette association est vérifiée ; **l'association nom ↔ espèce ne l'est pas.**
---
## 6. Le champ `iles` n'est vérifié pour aucune entrée
**Domaine : pédagogie.**
Les listes d'îles viennent de la graine. Elles déterminent quels fruits apparaissent dans un
pack d'île, donc ce qu'un enfant guadeloupéen verra. Une erreur ici ne casse rien
techniquement : elle enseigne juste qu'un fruit pousse là où il ne pousse pas.
**Piste de vérification :** les observations géolocalisées d'iNaturalist
(`place_id` Guadeloupe / Martinique / Guyane / La Réunion) donnent une première mesure
objective de présence, à croiser avec un regard local.
---
## Récapitulatif
| # | Point | Domaine | Bloque quoi |
|---|---|---|---|
| 1 | `comestible` grossier sur akée et pomme-cajou | sécurité | publication des fiches |
| 2 | Fruits dangereux hors du module Pa touché | pédagogie / sécurité | rien à ce stade |
| 3 | Saisonnalité non sourcée, non ventilée par île | pédagogie | **publication du mode Sézon** |
| 4 | Choix des photos du mancenillier | sécurité | publication du module Pa touché |
| 5 | `pòm-dlo` — association nom ↔ espèce | pédagogie | publication de l'entrée |
| 6 | Présence par île non vérifiée | pédagogie | packs d'île |
+90
View File
@@ -0,0 +1,90 @@
# ADR 0001 — Licences du code, du contenu et des médias
- **Statut :** accepté
- **Date :** 2026-07-27
- **Session :** 0 — cadre et données
- **Décideur :** le porteur (ORGANISATION KA INTERNATIONALE)
## Contexte
Le pack d'origine parlait de « ressources libres de droit ». L'expression n'a pas
d'existence juridique et masque quatre régimes très différents :
- **Wikimedia Commons** n'héberge que du libre, mais majoritairement du **CC BY-SA**,
qui impose l'attribution nominative **et** le partage à l'identique. Le partage à
l'identique contamine les œuvres dérivées.
- **iNaturalist** publie beaucoup de **CC BY-NC**, incompatible avec toute distribution
commerciale.
- **TRAMIL** (tramil.net) n'accorde aucune licence dans ses mentions légales. Par défaut :
tous droits réservés.
- **CIRAD / INRAE** appliquent des régimes mixtes, majoritairement propriétaires, avec des
usages pédagogiques négociables au cas par cas.
Le projet vise des enfants de 7 à 12 ans dans un cadre scolaire. Une erreur de licence sur
un support diffusé en classe n'est pas rattrapable par un correctif.
## Décision
### Code — AGPL-3.0-or-later
`LICENSE` contient le texte canonique récupéré depuis gnu.org. L'AGPL plutôt que la GPL
parce qu'une version future pourrait exposer une face serveur (export de progression pour
un enseignant, tableau de classe) : l'AGPL couvre l'usage en réseau, la GPL non.
### Contenu rédigé par OKI — CC BY-SA 4.0
Textes, fiches, indices botaniques, module « Pa touché », données structurées. Cohérent
avec Commons, donc réutilisable par le projet lui-même et par les enseignants.
### Médias tiers — licence d'origine conservée, œuvre collective
Chaque média garde sa licence. Le jeu est une **œuvre collective**, pas une œuvre dérivée.
C'est cette qualification qui permet à des médias CC BY-SA et CC BY-NC de coexister dans
un même produit.
### Clause non commerciale — acceptée, et irréversible
Le porteur a tranché en session 0 : le CC BY-NC est accepté pour élargir le fonds
photographique, en échange d'un **engagement non commercial définitif** sur le jeu.
Le code reste réutilisable commercialement sous AGPL une fois séparé des médias.
## Conséquences
### Ce que cette décision interdit, techniquement
1. **Aucun compositing.** Un média sous partage à l'identique ou sous clause non
commerciale ne peut être ni fusionné, ni détouré puis recombiné, ni fondu dans un atlas
de textures partagé avec d'autres médias. C'est ce qui préserve la qualification
d'œuvre collective.
2. **Aucune vente**, aucune version payante, aucune licence à un éditeur tant qu'un seul
média NC est embarqué.
3. **Aucun fichier TRAMIL.** TRAMIL se cite comme source de vérification factuelle, dans
`sources_factuelles`, jamais comme source d'images.
### Ce qui applique la décision
- `npm run validate:data` refuse tout média `composite: true` portant une clause SA ou NC,
et tout média à attribution dont l'auteur est absent.
- `npm run test:porte` prouve que ces refus se produisent réellement.
- `npm run build:credits` régénère `CREDITS.md` depuis les données, avec une section
distincte pour les médias NC. Un fichier de crédits tenu à la main se désynchronise, et
une attribution fausse est une violation.
- Le schéma impose `licence`, `auteur`, `url_fichier` et `url_description` sur chaque média.
### Condition de réexamen
Si le projet devait un jour être distribué commercialement, il faudrait retirer tous les
médias NC et régénérer les crédits. `CREDITS.md` liste ces médias dans une section dédiée
précisément pour rendre cette opération possible. À ce jour, aucun média NC n'est embarqué :
les 39 médias candidats proviennent tous de Commons, sous CC0, domaine public, CC BY ou
CC BY-SA. **L'engagement non commercial n'est donc pas encore consommé** — il ne le sera
qu'au premier média iNaturalist retenu.
## Alternatives écartées
- **Refuser le NC.** Aurait gardé une porte de sortie commerciale, au prix d'un fonds
photographique plus pauvre sur les espèces mal couvertes (zikak, pòm-sitè).
- **Isoler le NC dans un pack séparé retirable par flag.** Meilleur des deux mondes sur le
papier, mais complexifie le pipeline d'assets et le service worker pour une option dont
le porteur a jugé qu'il ne l'exercerait pas.
@@ -0,0 +1,63 @@
# ADR 0002 — Phaser 4 et l'écart au budget JS
- **Statut :** accepté, avec mesure à compléter en session 4
- **Date :** 2026-07-27
- **Session :** 0 — cadre et données
## Contexte
Le playbook OKI §2.7 fixe un budget non négociable de **170 Ko de JS initial compressé**.
Le mode arcade « Ranmasé » demande de la physique, des particules et du *game feel* : le
faire en DOM coûterait plus cher en travail et en performance qu'un moteur éprouvé.
Le pack d'origine prescrivait « Phaser 5 ». **Phaser 5 n'existe pas.** Vérification faite
au démarrage de la session :
```
$ npm view phaser version
4.2.1
```
La branche courante est Phaser 4 — 4.0 « Caladan » (avril 2026), 4.1 « Salusa »,
4.2 « Giedi » — avec un moteur WebGL réécrit en *render nodes*. Partir de Phaser 3 aurait
été partir d'une branche en fin de vie.
## Décision
Utiliser **`phaser@^4`** (4.2.1 au moment de la décision), et assumer un **écart documenté**
au budget JS, borné par quatre conditions :
1. Phaser n'est **jamais** dans le chemin critique. Import dynamique dans la route
`(jeu)/ranmase` uniquement, jamais au layout racine.
2. Le shell reste **≤ 170 Ko gzip**, Phaser exclu. Le budget n'est pas relâché : il est
mesuré à part.
3. L'entrée dans la scène passe derrière un **écran de chargement designé** (playbook P5,
en KA avec le tambour `ka`), pas derrière une page blanche.
4. Rendu `AUTO` (WebGL avec repli canvas), DPR plafonné à **1,5**,
`powerPreference: 'low-power'`, cible **30 fps stables sur Mali-G52**.
## Conséquences
- Le budget d'entrée du site (≤ 2 Mo) et les Core Web Vitals (LCP < 2,5 s, INP < 200 ms,
CLS < 0,05) restent mesurés **sur l'accueil et sur une fiche**, pages qui ne chargent
jamais Phaser.
- Un utilisateur qui ne joue jamais au mode arcade ne télécharge jamais Phaser. Les quatre
autres modes sont en Svelte pur (ADR 0003).
- La session 4 doit renseigner ici la **mesure réelle** du bundle Phaser en gzip et le
relevé de fps sur mobile d'entrée de gamme.
### Mesures — à compléter en session 4
| Mesure | Cible | Relevé |
|---|---|---|
| Shell JS initial (gzip) | ≤ 170 Ko | _à mesurer_ |
| Bundle Phaser seul (gzip) | information | _à mesurer_ |
| fps scène Ranmasé sur Mali-G52 | ≥ 30 stables | _à mesurer_ |
| Poids total de l'accueil | ≤ 2 Mo | _à mesurer_ |
## Condition de réexamen
Si la mesure de session 4 montre que Phaser dépasse ~450 Ko gzip, ou que les 30 fps ne
sont pas tenus sur mobile d'entrée de gamme, la scène « Ranmasé » est réécrite en DOM/CSS
avec une boucle rAF maison — le playbook P3 (« DOM d'abord, WebGL seulement où ça paie »)
reprend alors la main. Les quatre autres modes n'en dépendent pas : le jeu reste entier.
+59
View File
@@ -0,0 +1,59 @@
# ADR 0003 — Frontière stricte entre Svelte et Phaser
- **Statut :** accepté
- **Date :** 2026-07-27
- **Session :** 0 — cadre et données
## Contexte
Le pack d'origine supposait que le jeu entier serait porté par le moteur de jeu. Or trois
des cinq modes — Rekonèt, Kaché, Sézon — sont des interfaces de cartes et de boutons. Un
canvas les rendrait moins accessibles, plus lourds et plus difficiles à rendre lisibles
sans JavaScript, pour aucun gain.
Le public visé lit parfois mal, navigue sur Android d'entrée de gamme, et une partie de
l'usage se fera en classe, potentiellement au clavier ou avec un lecteur d'écran.
## Décision
Architecture **hybride à frontière stricte** : Svelte porte la coquille, Phaser porte un
seul îlot.
```
Svelte 5 (coquille) Phaser 4 (îlot)
├─ routes, i18n, SEO └─ scène « Ranmasé » uniquement
├─ menus, HUD, album · import dynamique dans (jeu)/ranmase
├─ fiches encyclopédiques · jamais au layout racine
├─ données, progression · game.destroy(true) au démontage
├─ audio, réglages · communication par événements
└─ Rekonèt · Kaché · Sézon · aucun état Svelte partagé par frame
```
Règles de frontière, non négociables :
1. **Import dynamique uniquement**, dans la route de la scène. Un `import` statique de
Phaser au layout racine ferait entrer 300 à 400 Ko dans le chemin critique de toutes
les pages, y compris de l'encyclopédie.
2. **Destruction symétrique** : `game.destroy(true)` au démontage du composant. Un moteur
de jeu qui survit à sa route fuit de la mémoire et continue de consommer du rAF.
3. **Communication par événements**, jamais par état Svelte lu ou écrit à chaque frame.
Le playbook §3 l'interdit explicitement : les états réactifs par frame passent par des
variables plain et un flush rAF.
4. **Miroir DOM sémantique obligatoire** pour la scène (playbook §2.8, point 4) : le canvas
est `aria-hidden`, et l'état du jeu est doublé en DOM lisible au clavier et au lecteur
d'écran.
## Conséquences
- Les quatre modes non-arcade sont **jouables au clavier** et dégradent proprement.
- La session 2 doit produire un jeu **déjà amusant sans Phaser**. C'est la porte de sortie
de cette session : si le jeu n'est pas plaisant en Svelte pur, ajouter un moteur de jeu
ne le sauvera pas — cela ajoutera du poids à un problème de game design.
- L'encyclopédie `/zerbaj/` ne dépend d'aucune brique de jeu et reste prérendue, lisible
sans JavaScript.
## Alternative écartée
**Tout en Phaser.** Aurait unifié le rendu au prix de l'accessibilité clavier, du
référencement de l'encyclopédie, de la lisibilité sans JS et du budget. Le playbook P3 est
explicite : DOM d'abord, WebGL seulement où ça paie. Ici, il ne paie que sur une scène.
+83
View File
@@ -0,0 +1,83 @@
# ADR 0004 — Deux filières d'assets : vérité et décor
- **Statut :** accepté
- **Date :** 2026-07-27
- **Session :** 0 — cadre et données
## Contexte
Le pack d'origine prévoyait de générer l'intégralité des visuels du jeu — 76 images — par
diffusion (SDXL / FLUX via ComfyUI), puis de passer directement à la production.
C'est une contradiction avec le but du jeu. Un enfant qui apprend à reconnaître un
corossol sur une image générée n'apprend pas à reconnaître un corossol : il apprend à
reconnaître ce qu'un modèle de diffusion produit quand on lui demande un corossol. Sur les
espèces peu représentées dans les jeux d'entraînement — le zikak, la quenette, le cachiman
cœur-de-bœuf, la pomme-liane — le modèle ne refuse pas : il produit un fruit **plausible
et faux**. C'est le pire des deux mondes, parce que l'erreur est invisible à qui ne connaît
pas déjà l'espèce.
Cette session a produit une illustration involontaire du même problème côté sources
réelles : parmi les photographies que Wikimedia Commons remonte pour *Melicoccus bijugatus*
(la quenette), l'un des premiers résultats est une photographie de **singe capucin**
mangeant le fruit. Aucune machine — moteur de recherche ou modèle génératif — ne peut
tenir lieu de validation botanique.
## Décision
Deux filières, deux régimes, jamais mélangés.
| Filière | Contenu | Source autorisée | Rôle |
|---|---|---|---|
| **A — Vérité** | fruit, coupe, feuille, écorce, port de l'arbre | photographie réelle : Commons, iNaturalist, herbier, appareil du porteur | tout ce qui sert à **identifier** — épreuves, indices, fiches |
| **B — Décor** | fonds, personnages, UI, sprites arcade, badges, écrans de titre | génération IA (ComfyUI / FLUX) | tout ce qui **ne sert pas** à identifier |
### Une troisième catégorie découverte en session 0
Les fonds Commons contiennent beaucoup de **planches botaniques anciennes** — Blanco,
Merian, Köhler, domaine public, exactes et magnifiques. Elles ne sont ni des photographies
ni des images générées. Le schéma les distingue donc explicitement :
```
type_media : "photo" | "planche_botanique" | "image_generee"
```
Une planche botanique **documente** une fiche encyclopédique. Elle ne peut **pas** porter
une épreuve d'identification : une gravure au trait rehaussée n'entraîne pas l'œil à
reconnaître un fruit posé sur une table de marché.
### Le champ `usages` et la porte
Chaque média déclare où il est employé : `epreuve`, `indice`, `fiche`, `decor`. Les deux
premiers sont les usages **identifiants**. Un média identifiant doit satisfaire les quatre
conditions, vérifiées par script :
1. `filiere: "A"` ;
2. `type_media: "photo"` ;
3. `valide: true`, avec un `valide_par` nommé — une validation anonyme n'engage personne ;
4. `vue` renseignée.
## Conséquences
- `npm run validate:data` fait échouer le build sur toute violation. `npm run test:porte`
rejoue les neuf cas interdits et vérifie que le refus se produit — une règle qu'on n'a
jamais vue refuser quelque chose est une intention, pas une règle.
- **Tout média sort de l'ingestion avec `valide: false`.** Aucun agent, aucun script, aucun
modèle ne peut passer ce champ à `true`. La validation se fait par comparaison à au moins
deux photographies de référence, idéalement contresignée par quelqu'un qui connaît :
TRAMIL, un enseignant de SVT, un agriculteur, une grand-mère.
- Le pipeline de génération (filière B) vit dans `tools/assets/`, hors du bundle, avec son
propre `requirements.txt`. Il est piloté **hors ligne, au build** (playbook P2). Aucun
appel réseau ne subsiste au runtime du jeu.
- Les défauts du script du pack d'origine sont corrigés en session 3 :
`hash()` de Python est randomisé par exécution (`PYTHONHASHSEED`), donc les seeds annoncés
comme reproductibles ne le sont pas — utiliser `zlib.crc32(clé.encode()) & 0xFFFFFFFF` ;
`copy.deepcopy` au lieu de `json.loads(json.dumps(...))` ; et vérifier la licence des
**poids** du modèle `rembg`, qui ne suit pas nécessairement la licence MIT du paquet.
## Alternative écartée
**Générer les visuels d'identification et les faire valider a posteriori.** Le pack le
proposait implicitement. Le problème n'est pas la validation, c'est le coût de l'erreur non
détectée : un validateur non spécialiste confirmera un corossol plausible. La photographie
supprime la question.
+78
View File
@@ -0,0 +1,78 @@
# ADR 0005 — Le kréyòl est la langue principale, norme gwadloupéyenne
- **Statut :** accepté ; orthographe en attente de relecture humaine
- **Date :** 2026-07-27
- **Session :** 0 — cadre et données
## Contexte
Le jeu vise à restituer une connaissance qui se transmettait en kréyòl. Traiter le kréyòl
comme une traduction du français inverserait le rapport que le projet cherche précisément
à rétablir.
Par ailleurs, les orthographes gwadloupéyenne et matinitjée diffèrent sur plusieurs entrées
du jeu de données. Les mélanger produirait un contenu que personne ne reconnaît tout à
fait comme le sien.
## Décision
### Le nom kréyòl est le nom de l'entrée
Dans les données, `noms.gcf` est le **nom principal**. `noms.fr`, `noms.en` et `noms.es` en
sont les traductions. Le schéma rend `gcf` obligatoire et les autres facultatives — pas
l'inverse. C'est un choix politique, pas cosmétique, et il ne s'inverse pas au motif que le
français serait « plus pratique » pour l'interface.
### Routes
`/` sert le kréyòl, `/fr/` le français, `/en/` l'anglais. Routeur par dossiers avec
catalogues JSON, pas de middleware (playbook §5b.7) : les URLs et le prérendu restent sous
contrôle total, ce qui est la condition du statique et du hors-ligne.
Attribut `lang="gcf"` correct partout, y compris sur les fragments kréyòl insérés dans une
page française — un nom de fruit prononcé par un lecteur d'écran avec la phonétique
française n'est pas le nom du fruit.
### Norme orthographique : gwadloupéyenne
Une seule norme pour tout le projet, décidée par le porteur en session 0. Le champ
`orthographe.norme` vaut `"gwadloupeyen"` sur chaque entrée, et le schéma n'accepte pas
d'autre valeur : il est impossible de mélanger les deux normes sans modifier le schéma,
donc sans que la décision soit revue.
### L'orthographe elle-même n'est pas du ressort de l'agent
Aucune graphie n'est tranchée par un agent de code. Chaque entrée porte :
```json
"orthographe": { "norme": "gwadloupeyen", "statut": "a_relire", "relu_par": null }
```
`statut` ne passe à `"relu"` que par décision d'un locuteur humain nommé. Le validateur
refuse toute entrée déclarée publiable dont l'orthographe n'est pas relue, et toute entrée
`relu` sans nom de relecteur.
Les incertitudes constatées sont consignées dans `docs/kreyol-a-relire.md` — signalées, pas
corrigées.
## Conséquences
- Les 13 graphies issues de `fruits.seed.json` sont **toutes non vérifiées** à ce stade. La
graine elle-même le déclare. Trois incohérences internes ont été relevées entre
l'identifiant technique et le nom kréyòl (voir `docs/kreyol-a-relire.md`) : elles ne sont
pas corrigées ici.
- Les identifiants techniques (`id`) restent en ASCII sans diacritique — ils servent de nom
de fichier et de segment d'URL. Ils ne sont **pas** une graphie et ne doivent jamais être
affichés à l'utilisateur. `kowosol` est un identifiant ; `kowosòl` est un nom.
- Un identifiant ne se renomme jamais après publication : il est dans les URLs, dans la
progression stockée en local et dans les liens partagés. Une correction d'orthographe
change `noms.gcf`, jamais `id`.
- Chaque entrée doit recevoir un enregistrement audio du nom prononcé par une voix humaine
locale. Pas de synthèse vocale : les enfants visés lisent mal le kréyòl écrit, dont
l'orthographe leur est peu familière — un jeu qui enseigne les noms kréyòl sans les faire
entendre rate sa cible. `npm run check:audio` tient la liste de ce qui manque.
## Point ouvert
Le relecteur n'est pas encore désigné. Tant qu'il ne l'est pas, aucune entrée ne peut être
publiée : c'est le validateur qui l'impose, pas une note de bas de page.
+22
View File
@@ -0,0 +1,22 @@
# Enregistrements kréyòl à réaliser
> Généré par `npm run check:audio`. Aucune synthèse vocale : ces noms doivent être
> prononcés par une voix humaine locale (brief §6).
Format attendu : `.opus` — un fichier par entrée, déposé dans `static/audio/<id>.opus`.
## À enregistrer (13)
- [ ] **aki**`static/audio/ake.opus` _(akée)_
- [ ] **fwiyapen**`static/audio/fwiyapen.opus` _(fruit à pain)_
- [ ] **gouyav**`static/audio/gouyav.opus` _(goyave)_
- [ ] **kénèt**`static/audio/kenet.opus` _(quenette)_
- [ ] **kowosòl**`static/audio/kowosol.opus` _(corossol)_
- [ ] **lorié-jòn**`static/audio/lorye-jonn.opus` _(laurier jaune)_
- [ ] **mansiniyé**`static/audio/mansiniye.opus` _(mancenillier)_
- [ ] **medsinyé**`static/audio/medisinye.opus` _(médicinier)_
- [ ] **pòm-dlo**`static/audio/pom-dlo.opus` _(pomme d'eau)_
- [ ] **pòm-kajou**`static/audio/pom-kajou.opus` _(pomme-cajou)_
- [ ] **pòm-kannèl**`static/audio/pom-kannel.opus` _(pomme-cannelle)_
- [ ] **pòm-sitè**`static/audio/pom-site.opus` _(prune de Cythère)_
- [ ] **zikak**`static/audio/zikak.opus` _(icaque)_
+235
View File
@@ -0,0 +1,235 @@
# Audit des sources — KI FWI SA YÉ ?
> Session 0. Chaque fiche répond à quatre questions : **ce qu'on y prend**, **sous quelle
> licence**, **avec quelle contrainte**, **comment on l'interroge**. Les endpoints listés
> ont été **appelés réellement** pendant l'audit, pas recopiés d'une documentation.
>
> Date de l'audit : 2026-07-27.
---
## Tableau de synthèse
| Source | Ce qu'on y prend | Régime | Verdict |
|---|---|---|---|
| **Wikidata** | Q-id, taxonomie | CC0 | ✅ Utilisée, sans réserve |
| **GBIF** | nom accepté, clé d'usage, famille | données ouvertes | ✅ Utilisée, sans réserve |
| **Wikimedia Commons** | photographies, planches | CC0 / PD / CC BY / CC BY-SA | ✅ Utilisée, attribution obligatoire, **pas de compositing** |
| **iNaturalist** | photographies de complément | ~93 % CC BY-NC (mesuré) | ⚠️ Autorisée mais engage le non-commercial (ADR 0001) |
| **TRAMIL** | vérification factuelle citée | **tous droits réservés** | ⛔ **Aucun fichier.** Demande écrite requise |
| **CIRAD / Agritrop** | vérification, publications | mixte, majoritairement © | ⛔ Demande écrite avant tout usage |
| **INRAE** | vérification | mixte | ⛔ Demande écrite avant tout usage |
| **Photos du porteur** | tout | choisi par le porteur | ✅ La meilleure source disponible |
---
## 1. Wikidata — la colonne vertébrale des identifiants
**Ce qu'on y prend.** L'identifiant Q de chaque taxon, et la famille botanique remontée par
la chaîne de taxons parents.
**Licence.** CC0 pour les données. Aucune contrainte d'attribution, mais le projet cite la
source par honnêteté et pour la traçabilité.
**Contrainte.** Wikidata est un wiki : une valeur peut être fausse ou obsolète. C'est
pourquoi le projet croise **systématiquement** avec GBIF et exige les deux dans le schéma
(`verifie_contre` doit contenir `wikidata` **et** `gbif` — un seul ne suffit pas).
**Comment on l'interroge.** Une seule requête SPARQL pour les 13 taxons :
```sparql
SELECT ?taxon ?name ?fam WHERE {
VALUES ?name { "Annona muricata" }
?taxon wdt:P225 ?name .
OPTIONAL { ?taxon wdt:P171+ ?f . ?f wdt:P105 wd:Q35409 ; wdt:P225 ?fam . }
}
```
`P225` = nom du taxon · `P171` = taxon supérieur · `P105` = rang · `Q35409` = famille.
Endpoint `https://query.wikidata.org/sparql`, en-tête `User-Agent` identifiant le projet
(exigé par l'infrastructure Wikimedia). Implémenté dans `tools/data/verify-taxa.mjs`.
**Résultat de l'audit.** 13/13 taxons trouvés par correspondance exacte sur `P225`.
---
## 2. GBIF — le nom scientifique accepté
**Ce qu'on y prend.** La clé d'usage (`usageKey`), le nom scientifique **accepté**, le
statut (`ACCEPTED` / `SYNONYM`) et la famille.
**Licence.** Données ouvertes. GBIF demande la citation du jeu de données ; le projet cite
GBIF globalement dans `CREDITS.md` et lie chaque entrée à sa fiche.
**Contrainte.** C'est ici que se détectent les **synonymes**, piège central d'un dataset
botanique. Le laurier-jaune est le cas d'école : il circule largement sous
*Thevetia peruviana*, alors que le nom accepté est *Cascabela thevetia*. Un dataset qui
fige un synonyme se désynchronise silencieusement des référentiels.
**Comment on l'interroge.**
```
GET https://api.gbif.org/v1/species/match?name=<nom>&strict=false
GET https://api.gbif.org/v1/species/<usageKey> # si status ≠ ACCEPTED
```
**Résultat de l'audit.** 13/13 en `matchType: EXACT` et `status: ACCEPTED`. **Aucune
divergence** avec les familles annoncées dans `fruits.seed.json`. La graine était bonne sur
ce point — c'est vérifié, plus supposé. Rapport : `docs/verification-taxons.md`.
---
## 3. Wikimedia Commons — le fonds photographique principal
**Ce qu'on y prend.** Des photographies pour la filière A (vérité), et des planches
botaniques anciennes pour les fiches encyclopédiques.
**Licence.** Commons n'héberge que du libre, mais « libre » recouvre plusieurs régimes très
différents. Sur les 130 candidats remontés pendant l'audit : domaine public, CC0, CC BY 2.0
à 4.0, CC BY-SA 2.0 à 4.0.
**Contraintes, dans l'ordre de gravité.**
1. **Le partage à l'identique contamine les dérivés.** Une photo CC BY-SA compositée dans
un sprite rend le sprite CC BY-SA. D'où l'interdiction absolue de compositing posée par
l'ADR 0001 et vérifiée par `npm run validate:data`.
2. **L'attribution est nominative.** Il faut l'auteur, la licence, l'URL du fichier et
l'URL de la page de description. Le script les récupère et refuse tout fichier à
attribution dont l'auteur est absent des métadonnées.
3. **Le titre ne garantit rien.** Une recherche sur *Melicoccus bijugatus* remonte en
deuxième position une photographie de **singe capucin** mangeant le fruit. Le moteur de
recherche n'est pas un botaniste. Rien ne sort de l'ingestion autrement qu'en
`valide: false`.
4. **Toutes les licences ne sont pas acceptables.** L'audit a écarté automatiquement
4 fichiers : deux sous GFDL 1.2 ou « Attribution » simple (régimes non retenus), deux
sous licence à attribution dont l'auteur était introuvable dans les métadonnées.
**Comment on l'interroge.**
```
GET https://commons.wikimedia.org/w/api.php
?action=query&generator=search&gsrnamespace=6
&gsrsearch="<nom scientifique>" filetype:bitmap
&prop=imageinfo&iiprop=url|size|mime|extmetadata
&iiextmetadatafilter=LicenseShortName|LicenseUrl|Artist|Credit|ImageDescription|DateTimeOriginal
```
Implémenté dans `tools/data/ingest-commons.mjs`. **Aucun fichier n'est téléchargé** en
session 0 : on ne collecte que des métadonnées et des URLs.
**Résultat de l'audit.** 130 candidats sous licence libre sur 13 taxons, soit au moins 10
par taxon. Aucun taxon sous le seuil de deux candidats.
---
## 4. iNaturalist — complément, au prix d'un engagement
**Ce qu'on y prend.** Des photographies pour les espèces mal couvertes par Commons, et des
observations géolocalisées aux Antilles (utile pour la saisonnalité par île, mode Sézon).
**Licence — mesurée, pas supposée.** Échantillon relevé pendant l'audit sur
*Chrysobalanus icaco* (zikak), 305 photographies de qualité recherche :
| licence | photos | part |
|---|---|---|
| CC BY-NC | 280 | 92 % |
| CC0 | 12 | 4 % |
| CC BY | 8 | 3 % |
| CC BY-NC-SA | 5 | 2 % |
**94 % du fonds est donc sous clause non commerciale.** Se limiter au non-NC réduirait
iNaturalist à un appoint marginal.
**Contrainte.** Retenir une seule photo NC engage le projet à ne jamais être distribué
commercialement (ADR 0001, décision du porteur). Le champ `usage_non_commercial` marque ces
médias dans les données, et `CREDITS.md` les isole dans une section dédiée pour rendre un
retrait ultérieur possible.
**Comment on l'interroge.**
```
GET https://api.inaturalist.org/v1/observations
?taxon_name=<nom>&quality_grade=research
&photo_license=cc0,cc-by,cc-by-sa,cc-by-nc,cc-by-nc-sa
&place_id=<Guadeloupe|Martinique> # pour la saisonnalité locale
```
**État à ce jour.** Aucune photo iNaturalist n'est encore embarquée. L'engagement non
commercial n'est donc **pas encore consommé**.
---
## 5. TRAMIL — ressource majeure, inutilisable sans autorisation
**Ce qu'on y prend.** Rien, en fichiers. TRAMIL sert de **source de vérification factuelle
citée en référence** — usages traditionnels, toxicité, parties de plante concernées — dans
le champ `sources_factuelles` de chaque entrée.
**Licence — vérifiée directement pendant l'audit.**
- Le pied de page de `tramil.net` affiche : **« © Copyright 2017 TRAMIL all rights
reserved. »**
- Le lien « Legal notice » du site renvoie une **erreur 404** (`/content/mentions-legales`,
vérifié le 2026-07-27).
Autrement dit : non seulement aucune licence n'est accordée, mais **les conditions ne sont
pas même consultables**. Par défaut : tous droits réservés.
**Contrainte.** La TRAMILothèque (photographies, planches d'herbier, coupes microscopiques,
scans) est exactement ce dont ce projet aurait besoin, et est **inutilisable sans
autorisation écrite**. Aucun fichier TRAMIL ne peut entrer dans le dépôt tant que cette
autorisation n'existe pas.
**Ce qu'il faut faire — et qui ne se délègue pas.** TRAMIL est hébergé par le SCD de
l'Université des Antilles à Schœlcher. Le porteur est à quinze minutes. Un partenariat
TRAMIL × OKI sur un jeu scolaire martiniquais a toutes les chances d'aboutir, et
transformerait le projet : accès à des images d'herbier vouchées, et une caution
scientifique sur le module « Pa touché ».
Lettre-type prête : `docs/courriers/tramil.md`.
---
## 6. CIRAD / Agritrop et INRAE
**Ce qu'on y prend.** De la vérification factuelle : saisonnalité réelle sous climat
antillais, variétés cultivées localement, données agronomiques. Agritrop, le dépôt ouvert
du CIRAD, contient de l'open access exploitable en citation.
**Licence.** Régimes mixtes, majoritairement propriétaires, avec des cas d'usage pédagogique
négociables. **À demander, jamais à présumer** — y compris sur un dépôt « ouvert », où
l'ouverture porte souvent sur la lecture, pas sur la réutilisation.
**Comment on l'interroge.** Consultation manuelle d'Agritrop (`agritrop.cirad.fr`), avec
enregistrement de la référence dans `sources_factuelles`. Aucune ingestion automatisée : le
volume ne le justifie pas et le régime de licence l'interdirait.
Lettre-type prête : `docs/courriers/cirad.md`.
---
## 7. Photographies du porteur — la meilleure source
Une photographie prise au marché de Fort-de-France vaut mieux que n'importe quelle
génération, et mieux que la plupart des photos de Commons : elle montre la variété locale,
au bon stade de maturité, dans le contexte où l'enfant la rencontrera.
**Licence.** Choisie par le porteur. `OKI-CC-BY-SA-4.0` dans le schéma, alignée sur
`LICENSE-CONTENT`. Aucune contrainte externe, aucun risque, et aucun compositing interdit
puisque le projet en détient les droits.
**Ce qui manquera nécessairement.** Les vues d'indice — écorce, feuille isolée, coupe nette
— sont rares sur Commons pour les espèces antillaises. Ce sont précisément celles dont le
mode Kaché a besoin. Une après-midi de terrain avec un appareil comblera plus de trous que
n'importe quelle recherche automatisée.
---
## Ce que cet audit ne couvre pas
- La **validité botanique** de chaque photographie : aucune machine ne peut la trancher.
- Les **droits voisins des locuteurs** pour les enregistrements audio : autorisation écrite
à obtenir avant embarquement, crédit nominatif dans `CREDITS.md`.
- La **licence des poids** du modèle utilisé par `rembg` dans le pipeline de filière B
(session 3) : les poids ne suivent pas toujours la licence du paquet, à vérifier avant
toute utilisation.
+69
View File
@@ -0,0 +1,69 @@
# Lettre-type — demande d'autorisation CIRAD / INRAE
> **À adapter et envoyer par le porteur.** Champs à compléter entre crochets.
> Le CIRAD dispose d'une implantation en Martinique et en Guadeloupe : privilégier
> l'antenne locale plutôt que le siège de Montpellier.
>
> Régime : mixte, majoritairement propriétaire, avec des usages pédagogiques négociables.
> Agritrop (`agritrop.cirad.fr`) est un dépôt ouvert — mais l'ouverture y porte sur la
> lecture, pas nécessairement sur la réutilisation. Vérifier la licence pièce par pièce
> avant d'en présumer quoi que ce soit. Voir `docs/audit-sources.md` §6.
---
**Objet : demande d'usage pédagogique — jeu éducatif libre sur les fruits des Antilles**
[Lieu], le [date]
À l'attention de [nom / service communication ou direction régionale Antilles-Guyane],
Madame, Monsieur,
ORGANISATION KA INTERNATIONALE, structure établie en [Martinique / Guadeloupe], développe
**« KI FWI SA YÉ ? »**, un jeu éducatif gratuit et libre destiné aux enfants de 7 à 12 ans
des Antilles, de la Guyane et de La Réunion. Son objet : leur réapprendre à reconnaître et
à nommer les fruits et les arbres de leurs îles, en kréyòl d'abord.
Le projet est non commercial et sans publicité : code sous AGPL-3.0, contenu sous
CC BY-SA 4.0, aucun compte, aucun traceur, aucune collecte de données sur les enfants.
**Notre demande porte sur trois points, par ordre d'importance décroissante.**
**1. Les données de saisonnalité.** Le jeu comporte un mode « Sézon » où l'enfant place les
fruits sur le calendrier de l'année. C'est une connaissance en voie de disparition, et nos
données actuelles reposent sur des sources générales, non spécifiques aux Antilles
françaises. Vos travaux agronomiques régionaux permettraient de les fonder correctement.
Nous sollicitons l'autorisation de citer et d'exploiter ces données pour [liste des espèces],
avec citation de la référence complète dans le jeu.
**2. L'iconographie.** Si votre fonds comporte des photographies exploitables pour ces
espèces — en particulier les vues d'écorce, de feuille isolée et de coupe, rares dans les
fonds libres — nous serions intéressés par une autorisation d'usage limitée à ce jeu, avec
crédit nominatif, sans modification et sans redistribution hors du jeu.
**3. Une relecture.** Si un de vos chercheurs de l'antenne Antilles acceptait de relire les
fiches botaniques (indices de reconnaissance : feuille, écorce, port, coupe), cette
relecture serait créditée.
Nous restons naturellement ouverts à une forme de partenariat qui vous conviendrait mieux,
y compris une mention institutionnelle sur la page de crédits du projet.
Je vous prie d'agréer, Madame, Monsieur, l'expression de ma considération distinguée.
[Nom]
[Fonction] — ORGANISATION KA INTERNATIONALE
[courriel] · [téléphone]
o-k-i.net
---
## Suivi de la demande
| Date | Action | Interlocuteur | Résultat |
|---|---|---|---|
| | envoi | | |
| | relance | | |
| | réponse | | |
**Tant que la colonne « résultat » est vide, aucun fichier CIRAD ou INRAE n'entre dans le
dépôt, et aucune donnée n'est reprise sans citation explicite de sa source.**
+78
View File
@@ -0,0 +1,78 @@
# Lettre-type — demande d'autorisation TRAMIL
> **À adapter et envoyer par le porteur.** Champs à compléter entre crochets.
> TRAMIL est hébergé par le SCD de l'Université des Antilles, campus de Schœlcher.
> Une visite sur place vaut mieux qu'un courriel : le projet est local, l'interlocuteur
> aussi, et une demande présentée de vive voix obtient une réponse.
>
> Contexte juridique de la démarche : `docs/audit-sources.md` §5. Le pied de page de
> tramil.net indique « © Copyright 2017 TRAMIL all rights reserved » et la page de mentions
> légales du site est inaccessible (404, vérifié le 2026-07-27) — aucune licence n'est donc
> accordée, même implicitement.
---
**Objet : demande d'autorisation d'usage pédagogique — jeu éducatif libre sur les fruits et plantes des Antilles**
[Lieu], le [date]
À l'attention de [nom du responsable / de la coordination TRAMIL],
Madame, Monsieur,
Je suis [nom], [fonction] au sein d'ORGANISATION KA INTERNATIONALE, structure établie en
[Martinique / Guadeloupe] et spécialisée dans le développement de logiciels libres à
vocation culturelle et éducative.
Nous développons **« KI FWI SA YÉ ? »**, un jeu éducatif gratuit destiné aux enfants de 7 à
12 ans des Antilles et de la Guyane. Son objet est de leur réapprendre à reconnaître et à
nommer les fruits, les arbres et les plantes de leurs îles — en kréyòl d'abord, le français
venant en traduction. Le jeu comprend un module de sécurité consacré aux plantes dangereuses
du quotidien : mancenillier, akée non mûr, coque de pomme-cajou, médicinier, laurier-jaune.
Le projet est **entièrement libre et non commercial** : code sous licence AGPL-3.0, contenu
sous CC BY-SA 4.0, aucune publicité, aucun compte utilisateur, aucun traceur, aucune
collecte de données sur les enfants. Il est destiné à un usage en classe et en famille, et
fonctionne hors ligne pour tenir compte des connexions scolaires.
**Notre demande porte sur deux points.**
**1. La TRAMILothèque comme source iconographique.** Vos photographies, planches d'herbier
et coupes constituent une ressource sans équivalent pour la région, et surtout une ressource
*vouchée* — ce qui est décisif pour un jeu dont l'objet même est l'identification correcte.
Nous sollicitons l'autorisation d'utiliser [nombre] images relatives aux espèces suivantes :
[liste des espèces], dans le seul cadre de ce jeu et de son encyclopédie associée.
Nous nous engageons à : créditer nominativement TRAMIL et l'auteur de chaque image à
l'endroit où elle apparaît et dans un écran de crédits dédié ; ne procéder à aucune
modification ni recomposition des images ; ne pas les redistribuer hors du jeu ; et retirer
toute image sur simple demande de votre part.
**2. Une relecture scientifique du module de sécurité.** Ce module traite de plantes qui
provoquent chaque année des accidents chez des enfants aux Antilles. Nous ne souhaitons pas
le publier sans qu'un regard compétent l'ait relu. Si l'un de vos collaborateurs acceptait
d'en relire le contenu — cinq fiches, une page chacune — cette relecture serait créditée
comme telle.
Nous serions heureux de vous présenter le projet de vive voix, à Schœlcher ou en visio, à
votre convenance. Une démonstration de l'état d'avancement prend une vingtaine de minutes.
Je reste à votre disposition pour toute précision et vous prie d'agréer, Madame, Monsieur,
l'expression de ma considération distinguée.
[Nom]
[Fonction] — ORGANISATION KA INTERNATIONALE
[courriel] · [téléphone]
o-k-i.net
---
## Suivi de la demande
| Date | Action | Interlocuteur | Résultat |
|---|---|---|---|
| | envoi / visite | | |
| | relance | | |
| | réponse | | |
**Tant que la colonne « résultat » est vide, aucun fichier TRAMIL n'entre dans le dépôt.**
+110
View File
@@ -0,0 +1,110 @@
# Kréyòl à relire
> **Rien dans ce fichier n'a été tranché par un agent de code.** L'ADR 0005 le pose comme
> règle : l'orthographe kréyòl n'est pas du ressort de l'outillage. Ce document **signale**,
> il ne corrige pas.
>
> Norme retenue pour le projet : **gwadloupéyenne** (ADR 0005). Une seule norme, jamais de
> mélange. Le schéma n'accepte pas d'autre valeur que `"gwadloupeyen"` dans
> `orthographe.norme` — changer d'avis suppose de modifier le schéma, donc de revoir la
> décision explicitement.
## Statut
**13 entrées sur 13 sont en `statut: "a_relire"`.** Aucune n'est publiable tant qu'un
locuteur nommé n'a pas tranché : `npm run validate:data` refuse toute entrée déclarée
valide dont l'orthographe n'est pas relue, et toute entrée relue sans nom de relecteur.
Relecteur désigné : **aucun à ce jour.**
## 1. Incohérences internes relevées dans la graine
Les identifiants techniques sont en ASCII sans diacritique — c'est voulu, ils servent de
nom de fichier et de segment d'URL, et ne sont jamais affichés. Mais trois d'entre eux
diffèrent du nom kréyòl **au-delà des seuls accents**, ce qui suggère une hésitation de
graphie, pas une simple translittération :
| id | `noms.gcf` | Écart constaté |
|---|---|---|
| `ake` | `aki` | voyelle finale différente : *e* contre *i* |
| `medisinye` | `medsinyé` | syllabe supplémentaire : *me-di-* contre *med-* |
| `lorye-jonn` | `lorié-jòn` | *lorye* contre *lorié* ; *jonn* contre *jòn* |
**Question au relecteur :** quelle graphie retenir pour chacun ? Le nom kréyòl
(`noms.gcf`) sera corrigé en conséquence. **L'identifiant, lui, ne bougera pas** — il est
déjà dans les URLs et dans la progression stockée localement.
## 2. Graphies à confirmer
Toutes issues de `fruits.seed.json`, qui déclare lui-même l'ensemble comme non vérifié.
Aucune n'est ici présentée comme correcte.
### Fruits
| id | graphie de la graine | français |
|---|---|---|
| `kowosol` | kowosòl | corossol |
| `kenet` | kénèt | quenette |
| `gouyav` | gouyav | goyave |
| `pom-site` | pòm-sitè | prune de Cythère |
| `zikak` | zikak | icaque |
| `pom-kannel` | pòm-kannèl | pomme-cannelle |
| `fwiyapen` | fwiyapen | fruit à pain |
| `pom-dlo` | pòm-dlo | pomme d'eau |
### Plantes du module « Pa touché »
| id | graphie de la graine | français |
|---|---|---|
| `mansiniye` | mansiniyé | mancenillier |
| `ake` | aki | akée |
| `pom-kajou` | pòm-kajou | pomme-cajou |
| `medisinye` | medsinyé | médicinier |
| `lorye-jonn` | lorié-jòn | laurier jaune |
**Point d'attention particulier :** la graine a été rédigée sans norme arrêtée, et signale
elle-même que les orthographes gwadloupéyenne et matinitjée diffèrent sur plusieurs de ces
entrées. Le projet ayant retenu la norme gwadloupéyenne, chaque graphie doit être confirmée
dans cette norme — y compris celles qui « paraissent » correctes.
## 3. Un point qui n'est pas orthographique mais lexical
`fruits.seed.json` porte cet avertissement sur `pom-dlo`, repris tel quel dans les données :
> « pòm-dlo », « pòm-malaka » et « pòm-rose » désignent des *Syzygium* **différents** selon
> les îles (*S. samarangense*, *S. malaccense*, *S. jambos*).
C'est un point de confusion classique, et il ne se règle pas par l'orthographe : il faut
décider **quel fruit porte quel nom en Guadeloupe**, puis s'y tenir. Un jeu qui enseigne
un nom que l'enfant entend appliqué à un autre fruit chez lui produit exactement la
confusion qu'il prétend dissiper.
L'entrée actuelle associe `pòm-dlo` à *Syzygium samarangense*, sur la seule foi de la
graine. **Non vérifié.** Trois voies possibles, à trancher par le relecteur : garder,
corriger, ou scinder en plusieurs entrées distinctes.
## 4. Ce qui reste à faire hors relecture
- **Les enregistrements.** Chaque nom doit être prononcé par une voix humaine locale ; pas
de synthèse vocale. La liste de ce qui manque est tenue à jour par
`npm run check:audio``docs/audio-a-enregistrer.md` (13 noms à enregistrer aujourd'hui).
- **La cohérence entre graphie et prononciation.** Le relecteur qui tranche l'orthographe
est idéalement celui qui enregistre, ou au moins celui qui écoute les enregistrements.
## Comment consigner une relecture
Dans `src/lib/data/fruits/<id>.json` :
```json
"orthographe": {
"norme": "gwadloupeyen",
"statut": "relu",
"relu_par": "Nom du relecteur"
}
```
Corriger `noms.gcf` si nécessaire. Ne jamais toucher à `id`. Puis :
```bash
npm run validate:data
```
+197
View File
@@ -0,0 +1,197 @@
# Plan des sessions — KI FWI SA YÉ ?
> Chaque session se termine par un build vert, un commit et une note de session dans
> `docs/sessions/`. **Ne pas enchaîner deux sessions sans relire ce qui a été produit.**
>
> Une porte de sortie n'est franchie que si elle est **mesurée**, pas estimée. Une porte non
> franchie n'autorise pas la session suivante : elle autorise à recommencer celle-ci.
---
## Session 0 — Cadre et données ✅ terminée
**Livré.** Dépôt initialisé, cinq ADR, audit des sept sources, `fruits.schema.json`,
validateur exécutable et son test, 13 entrées vérifiées contre Wikidata et GBIF, 39 médias
candidats sourcés sur Commons, `CREDITS.md` généré, licences, lettres-types, points à
arbitrer.
**Porte de sortie — franchie.**
| Critère | Cible | Mesuré |
|---|---|---|
| Taxons vérifiés contre **deux** référentiels | 13 | 13 ✅ |
| Divergences avec la graine | signalées | 0 divergence ✅ |
| Médias candidats sous licence libre | ≥ 2 par entrée | 10 par entrée ✅ |
| Médias validés | 0 attendu | 0 ✅ |
| `npm run validate:data` | vert | vert ✅ |
| `npm run test:porte` | 10/10 | 10/10 ✅ |
| Code applicatif écrit | aucun | aucun ✅ |
---
## Session 1 — Socle
SvelteKit 2 + Svelte 5 (runes) + TypeScript strict, `adapter-static`, prérendu intégral,
`trailingSlash: 'always'`. Tokens OKI (`oki-tokens.css` + `base.css`), thème sombre par
défaut et clair en opt-in AA. Polices Archivo et Inter self-hébergées en woff2. PWA légère.
i18n par dossiers — `/` en kréyòl, `/fr/`, `/en/`. `/zerbaj/` : une page prérendue par
entrée, avec JSON-LD, hreflang et le traitement `PRD_AI_Overview`.
**Porte de sortie.**
| Critère | Cible |
|---|---|
| Fiches en ligne | 13, une page prérendue chacune |
| Lighthouse mobile (accueil **et** une fiche) | ≥ 90 / 95 / 95 / 95 |
| Contenu lisible avec JavaScript désactivé | intégralement |
| JS initial | ≤ 170 Ko gzip |
| Requêtes vers un domaine tiers | **0**, vérifié par grep du build |
| `npm run check` | 0 erreur, 0 warning |
| `svelte-autofixer` sur chaque composant modifié | silencieux |
**Dépendance humaine :** aucune. La session 1 fonctionne avec 0 média validé — les fiches
affichent le texte, la taxonomie et les crédits, pas encore les photos.
---
## Session 2 — Moteur pédagogique, en Svelte pur
Modes **Rekonèt** (photo → 4 propositions, répétition espacée Leitner à 5 boîtes persistée
en local), **Kaché** (indices dévoilés un à un : feuille → écorce → coupe → fruit entier,
score dégressif) et **Sézon** (calendrier). Album `Lakou`, badges, audio, export de la
progression en JSON. Moment de révélation : retournement de la photo, nom kréyòl prononcé,
score en count-up (rAF → écriture DOM directe, span `aria-hidden` + valeur finale en
`.sr-only` dans une région `aria-live`), fiche ajoutée à l'album.
**Porte de sortie — la plus importante du projet.**
| Critère | Cible |
|---|---|
| **Le jeu est amusant sans Phaser** | jugement humain, sur une partie réelle |
| Navigation clavier complète sur les trois modes | vérifiée à la main |
| `prefers-reduced-motion` | gate unique au provider, vérifiée à la main |
| Progression conservée après rechargement | vérifiée |
| Cibles tactiles | ≥ 44 px, testées par `elementFromPoint` en 390 px |
| JS initial | toujours ≤ 170 Ko gzip |
**Si le jeu n'est pas plaisant ici, ne pas passer à la session 3.** Ajouter un moteur de jeu
à un problème de game design ajoute du poids au problème. Le mode Sézon reste non publiable
tant que le point 3 de `docs/a-arbitrer.md` n'est pas tranché.
**Dépendance humaine :** au moins deux photos validées par entrée pour que Rekonèt
fonctionne sur de vraies données. C'est le premier point de blocage réel du projet.
---
## Session 3 — Pipeline d'assets, filière B
Client ComfyUI dans `tools/assets/`, hors bundle, avec son `requirements.txt`. Seeds
déterministes par `zlib.crc32(clé.encode()) & 0xFFFFFFFF` — le `hash()` de Python est
randomisé par exécution, les seeds du pack d'origine ne sont donc pas reproductibles malgré
ce qu'il annonce. `copy.deepcopy` au lieu de `json.loads(json.dumps(...))`. Sortie AVIF/WebP,
atlas de textures par écran, packs par île téléchargeables et mis en cache par le service
worker. Licence des **poids** de `rembg` vérifiée, pas seulement celle du paquet.
**Porte de sortie.**
| Critère | Cible |
|---|---|
| Assets non validés dans le build | **0**, refusé par `validate:data` |
| Assets de filière B dans une épreuve | **0**, refusé par `validate:data` |
| Poids d'entrée du site | ≤ 2 Mo |
| Reproductibilité des seeds | deux exécutions → sorties identiques, vérifié par hash |
| Appels réseau au runtime | **0** |
| Compositing sur un média SA ou NC | **0**, refusé par `validate:data` |
---
## Session 4 — Ranmasé (Phaser 4) et Pa touché
Scène arcade en `phaser@^4`, import dynamique dans `(jeu)/ranmase`, `game.destroy(true)` au
démontage, communication par événements. Rendu `AUTO`, DPR ≤ 1,5,
`powerPreference: 'low-power'`. Miroir DOM sémantique. Module **Pa touché** : jamais
chronométré, jamais scoré, ton sobre et factuel.
**Porte de sortie.**
| Critère | Cible |
|---|---|
| Phaser dans le bundle initial | **absent**, vérifié sur le build |
| Shell JS initial, Phaser exclu | ≤ 170 Ko gzip |
| Bundle Phaser mesuré et consigné dans l'ADR 0002 | fait |
| fps sur Mali-G52 ou équivalent | ≥ 30 stables |
| Miroir DOM de la scène | navigable au clavier et au lecteur d'écran |
| Écran de chargement designé | présent, en KA |
| Module Pa touché | aucun chrono, aucun score, aucune épreuve |
**Réexamen :** si Phaser dépasse ~450 Ko gzip ou que les 30 fps ne tiennent pas, la scène
est réécrite en DOM/CSS (ADR 0002). Les quatre autres modes n'en dépendent pas.
---
## Session 5 — Contenu
Passage de 8 à 24 fruits, 5 plantes dangereuses consolidées. Enregistrement des voix
kréyòl. Relecture orthographique. Arbitrage des six points de `docs/a-arbitrer.md`.
**Porte de sortie.**
| Critère | Cible |
|---|---|
| Entrées avec taxonomie vérifiée contre deux référentiels | 29 / 29 |
| Entrées en `orthographe.statut: "relu"` avec relecteur nommé | 29 / 29 |
| `npm run check:audio` — enregistrements manquants | **0** |
| Voix de synthèse | **0** |
| Photos validées par entrée, avec validateur nommé | ≥ 2 |
| Points de `docs/a-arbitrer.md` tranchés | 6 / 6 |
| Module Pa touché relu par un humain compétent | fait, tracé |
**Cette session est majoritairement du terrain, pas du code.**
---
## 🔬 Test en classe — entre la 5 et la 6
Six enfants, trente minutes, le porteur regarde **sans intervenir**.
C'est la seule mesure qui compte, et elle invalidera une partie de ce plan. Tant mieux :
c'est plus tôt qu'après la livraison. Note d'observation à écrire dans
`docs/sessions/test-classe.md` avant la session 6.
---
## Session 6 — Finition
Performance, accessibilité, DoD §8 du playbook, `.htaccess` et `_headers`, déploiement,
écran de crédits, tag, push Gitea.
**Porte de sortie — la DoD intégralement vraie, plus :**
| Critère | Cible |
|---|---|
| Requêtes tierces au runtime, sur build de production | **0**, onglet réseau |
| Médias sans source, auteur, licence et URL | **0**, vérifié par script |
| Épreuves s'appuyant sur un asset généré | **0** |
| Jeu entièrement jouable hors ligne après une visite | vérifié en mode avion |
| `/zerbaj/` lisible et complet sans JavaScript | vérifié |
| Bundle initial | ≤ 170 Ko gzip, Phaser mesuré à part |
| Lighthouse mobile, accueil et fiche | ≥ 90 / 95 / 95 / 95 |
| Navigation clavier sur les cinq modes | complète |
| Écran de crédits dans le jeu | présent, généré depuis les données |
---
## Ce qui ne se délègue à aucun agent
Ces cinq points conditionnent la livraison et ne figurent dans aucune session parce
qu'aucune session ne peut les produire :
1. **Aller voir TRAMIL à Schœlcher.** Lettre prête : `docs/courriers/tramil.md`.
2. **Enregistrer les voix kréyòl.** Liste prête : `docs/audio-a-enregistrer.md`.
3. **Photographier ce qui manque sur Commons** — il manquera, surtout les vues d'écorce, de
feuille isolée et de coupe, celles dont le mode Kaché a besoin.
4. **Faire relire l'orthographe kréyòl** par un humain. Points relevés :
`docs/kreyol-a-relire.md`.
5. **Le test en classe.**
Le code est la partie facile.
+234
View File
@@ -0,0 +1,234 @@
# Planche de relecture des médias — filière A
> Généré par `npm run ingest:commons` le 2026-07-27.
> Sortie de script : ne pas éditer à la main, rejouer `npm run ingest:commons`.
## Ce qui est demandé au porteur
Pour chaque taxon, ouvrir les pages de description et retenir au moins deux photographies
qui montrent réellement l'espèce. Reporter le choix dans `src/lib/data/fruits/<id>.json`,
assigner à chaque média sa vue (`fruit_entier`, `coupe`, `feuille`, `ecorce`, `port`),
puis passer `valide` à `true` **et seulement alors**.
Aucune vérification botanique n'a été faite par la machine : l'ordre ci-dessous est celui du
moteur de recherche de Commons, rien de plus.
## `kowosol` — *Annona muricata* (fruit)
| # | fichier | auteur | licence | dimensions | page de description |
|---|---|---|---|---|---|
| 1 | Soursop fruit.jpg | USGov | PD | 365×274 | [voir](https://commons.wikimedia.org/wiki/File:Soursop_fruit.jpg) |
| 2 | Annona muricata 1.jpg | Damien Boilley from suburbs of Paris, France | CC-BY-2.0 | 960×1280 | [voir](https://commons.wikimedia.org/wiki/File:Annona_muricata_1.jpg) |
| 3 | Annona muricata2.jpg | User:Hans_B. | PD | 2592×1944 | [voir](https://commons.wikimedia.org/wiki/File:Annona_muricata2.jpg) |
| 4 | Annona muricata Blanco1.196-cropped.jpg | Francisco Manuel Blanco (O.S.A.) | PD | 1300×1620 | [voir](https://commons.wikimedia.org/wiki/File:Annona_muricata_Blanco1.196-cropped.jpg) |
| 5 | Kleine zuurzak Maria Sibylla Merian 1705 plate III.png | Maria Sibylla Merian ; engraved by I. Mulder | PD | 1252×1852 | [voir](https://commons.wikimedia.org/wiki/File:Kleine_zuurzak_Maria_Sibylla_Merian_1705_plate_III.png) |
| 6 | Guanábana-2.jpg | ViajeroExtraviado | CC0-1.0 | 2446×2444 | [voir](https://commons.wikimedia.org/wiki/File:Guan%C3%A1bana-2.jpg) |
| 7 | Aksara Karo Pohon sirsak.jpg | Agus Damanik | CC-BY-SA-4.0 | 3906×5859 | [voir](https://commons.wikimedia.org/wiki/File:Aksara_Karo_Pohon_sirsak.jpg) |
| 8 | Un Corossolier 02.jpg | Bérenger504 | CC-BY-SA-4.0 | 6000×4000 | [voir](https://commons.wikimedia.org/wiki/File:Un_Corossolier_02.jpg) |
| 9 | Un Corossolier 01.jpg | Bérenger504 | CC-BY-SA-4.0 | 6000×4000 | [voir](https://commons.wikimedia.org/wiki/File:Un_Corossolier_01.jpg) |
| 10 | Un Corossolier 03.jpg | Bérenger504 | CC-BY-SA-4.0 | 6000×4000 | [voir](https://commons.wikimedia.org/wiki/File:Un_Corossolier_03.jpg) |
## `kenet` — *Melicoccus bijugatus* (fruit)
| # | fichier | auteur | licence | dimensions | page de description |
|---|---|---|---|---|---|
| 1 | Melicoccus bijugatus.jpg | No machine-readable author provided. Hans B.~commonswiki ass | PD | 2126×1757 | [voir](https://commons.wikimedia.org/wiki/File:Melicoccus_bijugatus.jpg) |
| 2 | Cebus capucinus Puntarenas Costa Rica.jpg | kansasphoto | CC-BY-2.0 | 3924×2616 | [voir](https://commons.wikimedia.org/wiki/File:Cebus_capucinus_Puntarenas_Costa_Rica.jpg) |
| 3 | Una rama de mamon.jpeg | EEIM | CC-BY-SA-3.0 | 3264×2448 | [voir](https://commons.wikimedia.org/wiki/File:Una_rama_de_mamon.jpeg) |
| 4 | Arbol de Huaya (Melicoccus bijugatus).jpg | Acarcano | CC-BY-SA-4.0 | 2336×4160 | [voir](https://commons.wikimedia.org/wiki/File:Arbol_de_Huaya_(Melicoccus_bijugatus).jpg) |
| 5 | Melicoccus bijugatus tree.jpg | daveynin | CC-BY-2.0 | 2304×3456 | [voir](https://commons.wikimedia.org/wiki/File:Melicoccus_bijugatus_tree.jpg) |
| 6 | Panelera Corozal El Triangulo 07.jpg | Akire gatuna | CC-BY-SA-4.0 | 2160×3840 | [voir](https://commons.wikimedia.org/wiki/File:Panelera_Corozal_El_Triangulo_07.jpg) |
| 7 | Starr-091104-9193-Melicoccus bijugatus-plant tag-Kahanu Gardens NTBG K | Forest and Kim Starr | CC-BY-3.0 | 3648×2736 | [voir](https://commons.wikimedia.org/wiki/File:Starr-091104-9193-Melicoccus_bijugatus-plant_tag-Kahanu_Gardens_NTBG_Kaeleku_Hana-Maui_(24361925823).jpg) |
| 8 | Starr-091104-9194-Melicoccus bijugatus-trunk and canopy-Kahanu Gardens | Forest and Kim Starr | CC-BY-3.0 | 2736×3648 | [voir](https://commons.wikimedia.org/wiki/File:Starr-091104-9194-Melicoccus_bijugatus-trunk_and_canopy-Kahanu_Gardens_NTBG_Kaeleku_Hana-Maui_(24870791022).jpg) |
| 9 | Starr-091104-9196-Melicoccus bijugatus-leaves-Kahanu Gardens NTBG Kael | Forest and Kim Starr | CC-BY-3.0 | 3648×2736 | [voir](https://commons.wikimedia.org/wiki/File:Starr-091104-9196-Melicoccus_bijugatus-leaves-Kahanu_Gardens_NTBG_Kaeleku_Hana-Maui_(24361932503).jpg) |
| 10 | Starr-091104-9197-Melicoccus bijugatus-leaves-Kahanu Gardens NTBG Kael | Forest and Kim Starr | CC-BY-3.0 | 2736×3648 | [voir](https://commons.wikimedia.org/wiki/File:Starr-091104-9197-Melicoccus_bijugatus-leaves-Kahanu_Gardens_NTBG_Kaeleku_Hana-Maui_(24870797672).jpg) |
## `gouyav` — *Psidium guajava* (fruit)
| # | fichier | auteur | licence | dimensions | page de description |
|---|---|---|---|---|---|
| 1 | Psidium guajava fruit (2).jpg | Own work | CC-BY-SA-3.0 | 744×768 | [voir](https://commons.wikimedia.org/wiki/File:Psidium_guajava_fruit_(2).jpg) |
| 2 | Apple Guava.jpg | Fuadsyazwan ( talk ) | PD | 1632×1224 | [voir](https://commons.wikimedia.org/wiki/File:Apple_Guava.jpg) |
| 3 | Starr-111012-8771-Psidium guajava-burnt fruit-Kahana-Maui (24488703784 | Forest and Kim Starr | CC-BY-3.0 | 2592×3456 | [voir](https://commons.wikimedia.org/wiki/File:Starr-111012-8771-Psidium_guajava-burnt_fruit-Kahana-Maui_(24488703784).jpg) |
| 4 | Fruta de Goiaba.jpg | Zezinho68 | CC-BY-SA-4.0 | 6016×4000 | [voir](https://commons.wikimedia.org/wiki/File:Fruta_de_Goiaba.jpg) |
| 5 | Guava Tree below the sky 01.jpg | Sabina Bajracharya | CC-BY-SA-4.0 | 3456×4608 | [voir](https://commons.wikimedia.org/wiki/File:Guava_Tree_below_the_sky_01.jpg) |
| 6 | Guava Tree below the sky 02.jpg | Sabina Bajracharya | CC-BY-SA-4.0 | 3456×4608 | [voir](https://commons.wikimedia.org/wiki/File:Guava_Tree_below_the_sky_02.jpg) |
| 7 | Guava Tree 161120.jpg | Sabina Bajracharya | CC-BY-SA-4.0 | 3024×4032 | [voir](https://commons.wikimedia.org/wiki/File:Guava_Tree_161120.jpg) |
| 8 | Guava Tree 161116.jpg | Sabina Bajracharya | CC-BY-SA-4.0 | 3024×4032 | [voir](https://commons.wikimedia.org/wiki/File:Guava_Tree_161116.jpg) |
| 9 | Guava Leaves.jpg | Arjot | CC-BY-SA-4.0 | 3000×4000 | [voir](https://commons.wikimedia.org/wiki/File:Guava_Leaves.jpg) |
| 10 | Common Guava.jpg | Gaurav Dhwaj Khadka | CC-BY-SA-4.0 | 3024×4032 | [voir](https://commons.wikimedia.org/wiki/File:Common_Guava.jpg) |
## `pom-site` — *Spondias dulcis* (fruit)
| # | fichier | auteur | licence | dimensions | page de description |
|---|---|---|---|---|---|
| 1 | Spondia dulcis Blanco1.132.png | Francisco Manuel Blanco (O.S.A.) | PD | 1417×2107 | [voir](https://commons.wikimedia.org/wiki/File:Spondia_dulcis_Blanco1.132.png) |
| 2 | Spondia dulcis Blanco1.132-cropped.jpg | Francisco Manuel Blanco (O.S.A.) | PD | 1270×1770 | [voir](https://commons.wikimedia.org/wiki/File:Spondia_dulcis_Blanco1.132-cropped.jpg) |
| 3 | Spondia dulcis Blanco1.132.jpg | Francisco Manuel Blanco (O.S.A.) | PD | 1417×2107 | [voir](https://commons.wikimedia.org/wiki/File:Spondia_dulcis_Blanco1.132.jpg) |
| 4 | Starr 980529-4218 Spondias dulcis.jpg | Forest &amp; Kim Starr | CC-BY-3.0 | 1800×1200 | [voir](https://commons.wikimedia.org/wiki/File:Starr_980529-4218_Spondias_dulcis.jpg) |
| 5 | Owoce Śliwiec słodki.jpg | Agnieszka Kwiecień, Nova | CC-BY-3.0 | 1024×1024 | [voir](https://commons.wikimedia.org/wiki/File:Owoce_%C5%9Aliwiec_s%C5%82odki.jpg) |
| 6 | Spondias dulcis seeds.jpg | Tracey Slotta @ USDA-NRCS PLANTS Database | PD | 900×600 | [voir](https://commons.wikimedia.org/wiki/File:Spondias_dulcis_seeds.jpg) |
| 7 | 2014-10-11 Spondias dulcis Goldpflaume anagoria.JPG | Anagoria | CC-BY-3.0 | 3750×3168 | [voir](https://commons.wikimedia.org/wiki/File:2014-10-11_Spondias_dulcis_Goldpflaume_anagoria.JPG) |
| 8 | Buah kedondong by JJ.jpg | Rombituon | CC-BY-4.0 | 3000×4000 | [voir](https://commons.wikimedia.org/wiki/File:Buah_kedondong_by_JJ.jpg) |
| 9 | Spondias dulcis in Tropical Dream Center, Okinawa.jpg | M108t | CC-BY-4.0 | 3000×4000 | [voir](https://commons.wikimedia.org/wiki/File:Spondias_dulcis_in_Tropical_Dream_Center,_Okinawa.jpg) |
| 10 | Spondias dulcis leaves in Tropical Dream Center, Okinawa.jpg | M108t | CC-BY-4.0 | 4000×3000 | [voir](https://commons.wikimedia.org/wiki/File:Spondias_dulcis_leaves_in_Tropical_Dream_Center,_Okinawa.jpg) |
## `zikak` — *Chrysobalanus icaco* (fruit)
| # | fichier | auteur | licence | dimensions | page de description |
|---|---|---|---|---|---|
| 1 | Starr 031108-2161 Chrysobalanus icaco.jpg | Forest &amp; Kim Starr | CC-BY-3.0 | 1632×1224 | [voir](https://commons.wikimedia.org/wiki/File:Starr_031108-2161_Chrysobalanus_icaco.jpg) |
| 2 | Chrysobalanus icaco (inflorescense).jpg | Hans Hillewaert | CC-BY-SA-3.0 | 2473×3297 | [voir](https://commons.wikimedia.org/wiki/File:Chrysobalanus_icaco_(inflorescense).jpg) |
| 3 | Flore médicale des Antilles, ou, Traité des plantes usuelles (Pl. 84) | Descourtilz, J. Theodore.; Descourtilz, M. E.; Pichard. | PD | 1567×2592 | [voir](https://commons.wikimedia.org/wiki/File:Flore_m%C3%A9dicale_des_Antilles,_ou,_Trait%C3%A9_des_plantes_usuelles_(Pl._84)_(8201963925).jpg) |
| 4 | Chrysobalanus icaco (Chrysobalanaceae) 01.jpg | Filo gèn' | CC-BY-SA-4.0 | 2112×2304 | [voir](https://commons.wikimedia.org/wiki/File:Chrysobalanus_icaco_(Chrysobalanaceae)_01.jpg) |
| 5 | Fruit et feuilles de Chrysobalanus icaco (Chrysobalanaceae).jpg | Filo gèn' | CC-BY-SA-4.0 | 2321×3095 | [voir](https://commons.wikimedia.org/wiki/File:Fruit_et_feuilles_de_Chrysobalanus_icaco_(Chrysobalanaceae).jpg) |
| 6 | Icaques.jpg | Filo gèn' | CC-BY-SA-4.0 | 3008×2753 | [voir](https://commons.wikimedia.org/wiki/File:Icaques.jpg) |
| 7 | Icaques - fruits.jpg | Filo gèn' | CC-BY-SA-4.0 | 2950×3500 | [voir](https://commons.wikimedia.org/wiki/File:Icaques_-_fruits.jpg) |
| 8 | Foliorum compositio - Alterna.jpg | Filo gèn' | CC-BY-SA-4.0 | 620×720 | [voir](https://commons.wikimedia.org/wiki/File:Foliorum_compositio_-_Alterna.jpg) |
| 9 | Chrysobalanus icaco - Fruits 01.jpg | Filo gèn' | CC-BY-SA-4.0 | 1534×2048 | [voir](https://commons.wikimedia.org/wiki/File:Chrysobalanus_icaco_-_Fruits_01.jpg) |
| 10 | Chrysobalanus icaco - Fruits 02.jpg | Filo gèn' | CC-BY-SA-4.0 | 2261×2528 | [voir](https://commons.wikimedia.org/wiki/File:Chrysobalanus_icaco_-_Fruits_02.jpg) |
## `pom-kannel` — *Annona squamosa* (fruit)
| # | fichier | auteur | licence | dimensions | page de description |
|---|---|---|---|---|---|
| 1 | Annona squamosa (Custurd Apple) plant in Hyderabad, AP W IMG 9354.jpg | J.M.Garg | CC-BY-SA-4.0 | 800×533 | [voir](https://commons.wikimedia.org/wiki/File:Annona_squamosa_(Custurd_Apple)_plant_in_Hyderabad,_AP_W_IMG_9354.jpg) |
| 2 | Annona squamosa-fruits-leaves.jpg | Jim Conrad | PD | 650×419 | [voir](https://commons.wikimedia.org/wiki/File:Annona_squamosa-fruits-leaves.jpg) |
| 3 | Sharifa.JPG | Miansari66 | CC0-1.0 | 2816×2112 | [voir](https://commons.wikimedia.org/wiki/File:Sharifa.JPG) |
| 4 | Annona squamosa leaves at Madhurawada.JPG | Adityamadhav83 | CC-BY-SA-3.0 | 3839×2310 | [voir](https://commons.wikimedia.org/wiki/File:Annona_squamosa_leaves_at_Madhurawada.JPG) |
| 5 | Custard apple tree in Hainan - 04.JPG | Anna Frodesiak | CC0-1.0 | 4000×3000 | [voir](https://commons.wikimedia.org/wiki/File:Custard_apple_tree_in_Hainan_-_04.JPG) |
| 6 | 1901jfAnnona squamosa Tarlacfvf 01.JPG | Judgefloro | CC-BY-SA-4.0 | 4608×3456 | [voir](https://commons.wikimedia.org/wiki/File:1901jfAnnona_squamosa_Tarlacfvf_01.JPG) |
| 7 | Annona squamosa L. (9327977712).jpg | Dinesh Valke from Thane, India | CC-BY-SA-2.0 | 4284×5868 | [voir](https://commons.wikimedia.org/wiki/File:Annona_squamosa_L._(9327977712).jpg) |
| 8 | Annona squamosa in Jardin des Plantes de Toulouse 02.jpg | Krzysztof Golik | CC-BY-SA-4.0 | 4000×4722 | [voir](https://commons.wikimedia.org/wiki/File:Annona_squamosa_in_Jardin_des_Plantes_de_Toulouse_02.jpg) |
| 9 | 0158jfMalolos Historic Town Center Heritage Bulacanfvf 23.jpg | Judgefloro | CC0-1.0 | 4608×3456 | [voir](https://commons.wikimedia.org/wiki/File:0158jfMalolos_Historic_Town_Center_Heritage_Bulacanfvf_23.jpg) |
| 10 | Custard Apple - സീത പഴം 01.jpg | Shijan Kaakkara | CC-BY-SA-4.0 | 3648×2736 | [voir](https://commons.wikimedia.org/wiki/File:Custard_Apple_-_%E0%B4%B8%E0%B5%80%E0%B4%A4_%E0%B4%AA%E0%B4%B4%E0%B4%82_01.jpg) |
<details><summary>2 fichier(s) écarté(s) automatiquement</summary>
- File:Mygarden.JPG — licence non reconnue comme libre : Attribution
- File:Sugar apple on tree.jpg — licence non reconnue comme libre : GFDL 1.2
</details>
## `fwiyapen` — *Artocarpus altilis* (fruit)
| # | fichier | auteur | licence | dimensions | page de description |
|---|---|---|---|---|---|
| 1 | Artocarpus incisus Blanco2.267.png | Francisco Manuel Blanco (O.S.A.) | PD | 1379×2020 | [voir](https://commons.wikimedia.org/wiki/File:Artocarpus_incisus_Blanco2.267.png) |
| 2 | Starr 031209-0031 Artocarpus altilis.jpg | Forest &amp; Kim Starr | CC-BY-3.0 | 1632×1224 | [voir](https://commons.wikimedia.org/wiki/File:Starr_031209-0031_Artocarpus_altilis.jpg) |
| 3 | Artocarpus altilis (fruit).jpg | Hans Hillewaert | CC-BY-SA-3.0 | 2848×3799 | [voir](https://commons.wikimedia.org/wiki/File:Artocarpus_altilis_(fruit).jpg) |
| 4 | Artocarpus altilis 439799696.jpg | Bonnie Isaac | CC0-1.0 | 2048×1362 | [voir](https://commons.wikimedia.org/wiki/File:Artocarpus_altilis_439799696.jpg) |
| 5 | Artocarpus altilis 399504710.jpg | Marilyne Busque-Dubois | CC-BY-4.0 | 1440×1080 | [voir](https://commons.wikimedia.org/wiki/File:Artocarpus_altilis_399504710.jpg) |
| 6 | Artocarpus altilis 376055544.jpg | renjus box | CC-BY-4.0 | 2048×1401 | [voir](https://commons.wikimedia.org/wiki/File:Artocarpus_altilis_376055544.jpg) |
| 7 | Artocarpus altilis 366760782.jpg | Akshay | CC0-1.0 | 2048×1536 | [voir](https://commons.wikimedia.org/wiki/File:Artocarpus_altilis_366760782.jpg) |
| 8 | Artocarpus altilis 360470185.jpg | Mike Bowie | CC-BY-4.0 | 1536×2048 | [voir](https://commons.wikimedia.org/wiki/File:Artocarpus_altilis_360470185.jpg) |
| 9 | Artocarpus altilis 355237308.jpg | monkeyjodey | CC0-1.0 | 1536×2048 | [voir](https://commons.wikimedia.org/wiki/File:Artocarpus_altilis_355237308.jpg) |
| 10 | Artocarpus altilis 348826407.jpg | Kiwi Shen | CC-BY-4.0 | 1536×2048 | [voir](https://commons.wikimedia.org/wiki/File:Artocarpus_altilis_348826407.jpg) |
## `pom-dlo` — *Syzygium samarangense* (fruit)
| # | fichier | auteur | licence | dimensions | page de description |
|---|---|---|---|---|---|
| 1 | Champanga flower buds.jpg | Vinayaraj | CC-BY-SA-3.0 | 2073×1590 | [voir](https://commons.wikimedia.org/wiki/File:Champanga_flower_buds.jpg) |
| 2 | Lainwu (Wax apple) diamond P00063.JPG | Taiwan7007 | CC-BY-3.0 | 308×330 | [voir](https://commons.wikimedia.org/wiki/File:Lainwu_(Wax_apple)_diamond_P00063.JPG) |
| 3 | 9956kfSyzygium samarangense Pampangafvf 05.JPG | Judgefloro | CC-BY-SA-4.0 | 4608×3456 | [voir](https://commons.wikimedia.org/wiki/File:9956kfSyzygium_samarangense_Pampangafvf_05.JPG) |
| 4 | Atlas der baumarten von Java (Figur 452) BHL47163274.jpg | Koorders, S. H.; Valeton, Theodoric | PD | 2145×3322 | [voir](https://commons.wikimedia.org/wiki/File:Atlas_der_baumarten_von_Java_(Figur_452)_BHL47163274.jpg) |
| 5 | 09564jfSan Rafael Bulacan Maasim River Diliman Paddy Vegetable Fields | Judgefloro | PD | 4608×3456 | [voir](https://commons.wikimedia.org/wiki/File:09564jfSan_Rafael_Bulacan_Maasim_River_Diliman_Paddy_Vegetable_Fields_Roadsfvf_12.JPG) |
| 6 | 09592jfSan Rafael Bulacan Syzygium samarangense Diliman Paddy Vegetabl | Judgefloro | PD | 4608×3456 | [voir](https://commons.wikimedia.org/wiki/File:09592jfSan_Rafael_Bulacan_Syzygium_samarangense_Diliman_Paddy_Vegetable_Fields_Roadsfvf_07.JPG) |
| 7 | Syzygium samarangense (Rose apple) tree in RDA, Bogra 02.jpg | Afifa Afrin | CC-BY-SA-3.0 | 3456×4608 | [voir](https://commons.wikimedia.org/wiki/File:Syzygium_samarangense_(Rose_apple)_tree_in_RDA,_Bogra_02.jpg) |
| 8 | Syzygium samarangense (jamalac ou jambose).jpg | Filo gèn' | CC-BY-SA-4.0 | 4608×3456 | [voir](https://commons.wikimedia.org/wiki/File:Syzygium_samarangense_(jamalac_ou_jambose).jpg) |
| 9 | Syzygium samarangense 16zz.jpg | Photo by David J. Stang | CC-BY-SA-4.0 | 2544×1696 | [voir](https://commons.wikimedia.org/wiki/File:Syzygium_samarangense_16zz.jpg) |
| 10 | Syzygium samarangense 19zz.jpg | Photo by David J. Stang | CC-BY-SA-4.0 | 2544×1696 | [voir](https://commons.wikimedia.org/wiki/File:Syzygium_samarangense_19zz.jpg) |
<details><summary>1 fichier(s) écarté(s) automatiquement</summary>
- File:Wax apple1.jpg — licence à attribution mais auteur introuvable dans les métadonnées
</details>
## `mansiniye` — *Hippomane mancinella* (plante_dangereuse)
| # | fichier | auteur | licence | dimensions | page de description |
|---|---|---|---|---|---|
| 1 | Hippomane mancinella-Hocquart 1821.jpeg | M. Hocquart | PD | 363×500 | [voir](https://commons.wikimedia.org/wiki/File:Hippomane_mancinella-Hocquart_1821.jpeg) |
| 2 | Hyacinthus orientalis and Hippomane mancinella.gif | "The Universal Herbal" by Thomas Green (published 181620) | PD | 317×252 | [voir](https://commons.wikimedia.org/wiki/File:Hyacinthus_orientalis_and_Hippomane_mancinella.gif) |
| 3 | Hippomane mancinella-Jacquin.jpeg | Nicolás Joseph Jacquin | PD | 500×753 | [voir](https://commons.wikimedia.org/wiki/File:Hippomane_mancinella-Jacquin.jpeg) |
| 4 | Galapagos plants II 29.jpg | Klaus Schönitzer | CC-BY-SA-3.0 | 1500×2200 | [voir](https://commons.wikimedia.org/wiki/File:Galapagos_plants_II_29.jpg) |
| 5 | Mancenillier1.JPG | Mica | CC-BY-3.0 | 1536×2048 | [voir](https://commons.wikimedia.org/wiki/File:Mancenillier1.JPG) |
| 6 | Mancenillier2.JPG | Mica | CC-BY-3.0 | 1536×2048 | [voir](https://commons.wikimedia.org/wiki/File:Mancenillier2.JPG) |
| 7 | Hippomane mancinella (fruit).jpg | Hans Hillewaert | CC-BY-SA-3.0 | 3458×2592 | [voir](https://commons.wikimedia.org/wiki/File:Hippomane_mancinella_(fruit).jpg) |
| 8 | Hippomane mancenilla port.JPG | Pancrat | CC-BY-SA-3.0 | 1600×1200 | [voir](https://commons.wikimedia.org/wiki/File:Hippomane_mancenilla_port.JPG) |
| 9 | T. Green, The universal herbal Wellcome L0025496.jpg | https://wellcomeimages.org/indexplus/obf_images/a5/e8/28f318 | CC-BY-4.0 | 1568×1242 | [voir](https://commons.wikimedia.org/wiki/File:T._Green,_The_universal_herbal_Wellcome_L0025496.jpg) |
| 10 | Hippomane mancinella Costa Rica.jpg | Gabriele Kothe-Heinrich | CC-BY-SA-3.0 | 1200×900 | [voir](https://commons.wikimedia.org/wiki/File:Hippomane_mancinella_Costa_Rica.jpg) |
<details><summary>1 fichier(s) écarté(s) automatiquement</summary>
- File:The North American sylva, or, A description of the forest trees of the United States, Canada, and Nova Scotia, not described in the work of F. Andrew Michaux (microform) - and containing all the (20632692415).jpg — licence non reconnue comme libre : No restrictions
</details>
## `ake` — *Blighia sapida* (plante_dangereuse)
| # | fichier | auteur | licence | dimensions | page de description |
|---|---|---|---|---|---|
| 1 | Ackee 001.jpg | Jerome Walker | CC-BY-SA-3.0 | 2848×2136 | [voir](https://commons.wikimedia.org/wiki/File:Ackee_001.jpg) |
| 2 | Walter Hood Fitch03.JPG | Walter Hood Fitch | PD | 1194×1732 | [voir](https://commons.wikimedia.org/wiki/File:Walter_Hood_Fitch03.JPG) |
| 3 | Owoce Aka.jpg | Agnieszka Kwiecień ( Nova ) | CC-BY-SA-3.0 | 1860×1860 | [voir](https://commons.wikimedia.org/wiki/File:Owoce_Aka.jpg) |
| 4 | Flore médicale des Antilles, ou, Traité des plantes usuelles (10559212 | Descourtilz, J. Theodore.; Descourtilz, M. E.; Pichard. | PD | 1557×2889 | [voir](https://commons.wikimedia.org/wiki/File:Flore_m%C3%A9dicale_des_Antilles,_ou,_Trait%C3%A9_des_plantes_usuelles_(10559212793).jpg) |
| 5 | Pomological Watercolor POM00007429.jpg | Newton, Amanda Almira, ca. 1860-1943 | PD | 2715×4000 | [voir](https://commons.wikimedia.org/wiki/File:Pomological_Watercolor_POM00007429.jpg) |
| 6 | Pommier daki à Taneka, Commune de Copargo, département de la Donga au | Saliousoft | CC-BY-SA-4.0 | 9216×6912 | [voir](https://commons.wikimedia.org/wiki/File:Pommier_d%E2%80%99aki_%C3%A0_Taneka,_Commune_de_Copargo,_d%C3%A9partement_de_la_Donga_au_B%C3%A9nin_01.jpg) |
| 7 | Blighia sapida3.jpg | DouglasGoldman | CC-BY-SA-4.0 | 1814×2710 | [voir](https://commons.wikimedia.org/wiki/File:Blighia_sapida3.jpg) |
| 8 | Blighia sapida5.jpg | DouglasGoldman | CC-BY-SA-4.0 | 1814×2710 | [voir](https://commons.wikimedia.org/wiki/File:Blighia_sapida5.jpg) |
| 9 | Blighia sapida8.jpg | DouglasGoldman | CC-BY-SA-4.0 | 2710×1814 | [voir](https://commons.wikimedia.org/wiki/File:Blighia_sapida8.jpg) |
| 10 | Blighia sapida10.jpg | DouglasGoldman | CC-BY-SA-4.0 | 2710×1814 | [voir](https://commons.wikimedia.org/wiki/File:Blighia_sapida10.jpg) |
## `pom-kajou` — *Anacardium occidentale* (plante_dangereuse)
| # | fichier | auteur | licence | dimensions | page de description |
|---|---|---|---|---|---|
| 1 | Anacardium occidentale - Köhlers Medizinal-Pflanzen-010.jpg | Franz Eugen Köhler, Köhler's Medizinal-Pflanzen | PD | 425×589 | [voir](https://commons.wikimedia.org/wiki/File:Anacardium_occidentale_-_K%C3%B6hler%E2%80%93s_Medizinal-Pflanzen-010.jpg) |
| 2 | Cashew2-flower.JPG | Aruna at Malayalam Wikipedia | CC-BY-SA-3.0 | 1024×768 | [voir](https://commons.wikimedia.org/wiki/File:Cashew2-flower.JPG) |
| 3 | Cashew apples.jpg | Abhishek Jacob | CC-BY-SA-3.0 | 2534×1982 | [voir](https://commons.wikimedia.org/wiki/File:Cashew_apples.jpg) |
| 4 | Cashew flower fruit seed.JPG | ସୁରଥ କୁମାର ପାଢ଼ୀ | CC-BY-SA-3.0 | 4000×3000 | [voir](https://commons.wikimedia.org/wiki/File:Cashew_flower_fruit_seed.JPG) |
| 5 | Anacardium occidentale Thailand 2013-05-03wb.JPG | Strobilomyces | CC-BY-SA-3.0 | 2816×2112 | [voir](https://commons.wikimedia.org/wiki/File:Anacardium_occidentale_Thailand_2013-05-03wb.JPG) |
| 6 | Cashew 4334.JPG | Primejyothi | CC-BY-SA-3.0 | 3888×2592 | [voir](https://commons.wikimedia.org/wiki/File:Cashew_4334.JPG) |
| 7 | Cashew 4335.JPG | Primejyothi | CC-BY-SA-3.0 | 2592×3888 | [voir](https://commons.wikimedia.org/wiki/File:Cashew_4335.JPG) |
| 8 | Anacardium occidentale 01.JPG | Vinayaraj | CC-BY-SA-3.0 | 2580×3588 | [voir](https://commons.wikimedia.org/wiki/File:Anacardium_occidentale_01.JPG) |
| 9 | Anacardium occidentale 08.JPG | Vinayaraj | CC-BY-SA-3.0 | 2532×3648 | [voir](https://commons.wikimedia.org/wiki/File:Anacardium_occidentale_08.JPG) |
| 10 | Fleurs et noix de cajou.jpg | Xof | CC-BY-SA-4.0 | 4608×3456 | [voir](https://commons.wikimedia.org/wiki/File:Fleurs_et_noix_de_cajou.jpg) |
## `medisinye` — *Jatropha curcas* (plante_dangereuse)
| # | fichier | auteur | licence | dimensions | page de description |
|---|---|---|---|---|---|
| 1 | Jatropha curcas Blanco2.384.jpg | Francisco Manuel Blanco (O.S.A.) | PD | 1411×2061 | [voir](https://commons.wikimedia.org/wiki/File:Jatropha_curcas_Blanco2.384.jpg) |
| 2 | Jatropha curcas Blanco2.384-cropped.jpg | Francisco Manuel Blanco (O.S.A.) | PD | 1300×1870 | [voir](https://commons.wikimedia.org/wiki/File:Jatropha_curcas_Blanco2.384-cropped.jpg) |
| 3 | Georg Forster - Purgiernuss.jpeg | Georg Forster | PD | 1836×2658 | [voir](https://commons.wikimedia.org/wiki/File:Georg_Forster_-_Purgiernuss.jpeg) |
| 4 | Jatropha curcas 11 (4350031767).jpg | Ton Rulkens from Mozambique | CC-BY-SA-2.0 | 768×1024 | [voir](https://commons.wikimedia.org/wiki/File:Jatropha_curcas_11_(4350031767).jpg) |
| 5 | Starr-120620-9733-Jatropha curcas-seedlings in duff-Kula Agriculture P | Forest and Kim Starr | CC-BY-3.0 | 3456×2592 | [voir](https://commons.wikimedia.org/wiki/File:Starr-120620-9733-Jatropha_curcas-seedlings_in_duff-Kula_Agriculture_Park-Maui_(25185489735).jpg) |
| 6 | Starr-120620-9735-Jatropha curcas-seedlings in debris near parent plan | Forest and Kim Starr | CC-BY-3.0 | 2592×3456 | [voir](https://commons.wikimedia.org/wiki/File:Starr-120620-9735-Jatropha_curcas-seedlings_in_debris_near_parent_plantings-Kula_Agriculture_Park-Maui_(24558649453).jpg) |
| 7 | Starr-120620-9736-Jatropha curcas-seedlings in debris near parent plan | Forest and Kim Starr | CC-BY-3.0 | 3456×2592 | [voir](https://commons.wikimedia.org/wiki/File:Starr-120620-9736-Jatropha_curcas-seedlings_in_debris_near_parent_plantings-Kula_Agriculture_Park-Maui_(25159146496).jpg) |
| 8 | Starr-120620-7537-Jatropha curcas-seedling in duff-Kula Agriculture Pa | Forest and Kim Starr | CC-BY-3.0 | 2736×3648 | [voir](https://commons.wikimedia.org/wiki/File:Starr-120620-7537-Jatropha_curcas-seedling_in_duff-Kula_Agriculture_Park-Maui_(24850192310).jpg) |
| 9 | Starr-120620-7538-Jatropha curcas-biofuel trial plantings-Kula Agricul | Forest and Kim Starr | CC-BY-3.0 | 3648×2736 | [voir](https://commons.wikimedia.org/wiki/File:Starr-120620-7538-Jatropha_curcas-biofuel_trial_plantings-Kula_Agriculture_Park-Maui_(25119515196).jpg) |
| 10 | Starr-120620-7541-Jatropha curcas-seedling-Kula Agriculture Park-Maui | Forest and Kim Starr | CC-BY-3.0 | 2736×3648 | [voir](https://commons.wikimedia.org/wiki/File:Starr-120620-7541-Jatropha_curcas-seedling-Kula_Agriculture_Park-Maui_(24519017633).jpg) |
<details><summary>1 fichier(s) écarté(s) automatiquement</summary>
- File:Jatropha curcas1 henning.jpg — licence à attribution mais auteur introuvable dans les métadonnées
</details>
## `lorye-jonn` — *Cascabela thevetia* (plante_dangereuse)
| # | fichier | auteur | licence | dimensions | page de description |
|---|---|---|---|---|---|
| 1 | Thevetia peruviana1.jpg | No machine-readable author provided. Hans B.~commonswiki ass | PD | 2592×1944 | [voir](https://commons.wikimedia.org/wiki/File:Thevetia_peruviana1.jpg) |
| 2 | Yellow Oleander (Thevetia peruviana) leaves & flowers in Kolkata W IMG | J.M.Garg | CC-BY-SA-3.0 | 619×600 | [voir](https://commons.wikimedia.org/wiki/File:Yellow_Oleander_(Thevetia_peruviana)_leaves_%26_flowers_in_Kolkata_W_IMG_8008.jpg) |
| 3 | Starr 060916-8881 Thevetia peruviana.jpg | Forest &amp; Kim Starr | CC-BY-3.0 | 2592×1944 | [voir](https://commons.wikimedia.org/wiki/File:Starr_060916-8881_Thevetia_peruviana.jpg) |
| 4 | Starr 080609-7918 Thevetia peruviana.jpg | Forest &amp; Kim Starr | CC-BY-3.0 | 2112×2816 | [voir](https://commons.wikimedia.org/wiki/File:Starr_080609-7918_Thevetia_peruviana.jpg) |
| 5 | Thevetia peruviana plant.jpg | Vinayaraj | CC-BY-SA-3.0 | 2556×3648 | [voir](https://commons.wikimedia.org/wiki/File:Thevetia_peruviana_plant.jpg) |
| 6 | Tarrafal-Thevetia peruviana (2).jpg | Ji-Elle | CC-BY-SA-3.0 | 3648×2736 | [voir](https://commons.wikimedia.org/wiki/File:Tarrafal-Thevetia_peruviana_(2).jpg) |
| 7 | Cascabela thevetia 10.JPG | Vinayaraj | CC-BY-SA-3.0 | 3648×2736 | [voir](https://commons.wikimedia.org/wiki/File:Cascabela_thevetia_10.JPG) |
| 8 | Thevetia peruviana 'Alba' (338607342).jpg | Dinesh Valke from Thane, India | CC-BY-SA-2.0 | 2816×2112 | [voir](https://commons.wikimedia.org/wiki/File:Thevetia_peruviana_%27Alba%27_(338607342).jpg) |
| 9 | Thevetia peruviana 15zz.jpg | Photo by David J. Stang | CC-BY-SA-4.0 | 3504×2336 | [voir](https://commons.wikimedia.org/wiki/File:Thevetia_peruviana_15zz.jpg) |
| 10 | Thevetia peruviana 28zz.jpg | Photo by David J. Stang | CC-BY-SA-4.0 | 3504×2336 | [voir](https://commons.wikimedia.org/wiki/File:Thevetia_peruviana_28zz.jpg) |
+171
View File
@@ -0,0 +1,171 @@
# Session 0 — Cadre et données
**Date :** 2026-07-27 · **Type de mission :** B (création *ex nihilo*) · **Code applicatif écrit : aucun.**
---
## Ce qui a été fait
**Gouvernance.** `git init` et commit de protection des documents de cadrage **avant toute
autre action** (playbook §5b.1 — atlas-fediverse avait été perdu faute de ce réflexe). Le
pack de référence `doc2sveltekit-transition/` reste local et non versionné, conformément au
playbook §0. Branche `main`.
**Cadre.** Cinq ADR, `LICENSE` (AGPL-3.0-or-later, texte canonique récupéré depuis gnu.org),
`LICENSE-CONTENT`, audit des sept sources, `SOURCES.md`, deux lettres-types.
**Outillage.** Six scripts dans `tools/data/`, tous hors bundle :
| Commande | Rôle |
|---|---|
| `npm run verify:taxa` | vérifie 13 taxons contre Wikidata (SPARQL) et GBIF |
| `npm run ingest:commons` | remonte les photos candidates sous licence libre |
| `npm run build:dataset` | compose les entrées ; refuse d'écraser sans `--force` |
| `npm run validate:data` | **la porte** — schéma + règles métier, sortie non nulle = build refusé |
| `npm run test:porte` | prouve que la porte refuse les 9 cas interdits |
| `npm run build:credits` | régénère `CREDITS.md` depuis les données |
| `npm run check:audio` | liste les enregistrements kréyòl manquants |
**Données.** 13 entrées dans `src/lib/data/fruits/`, 39 médias candidats, 0 validé.
---
## Ce que la vérification a appris
### La graine était bonne sur la taxonomie
**13 taxons sur 13** trouvés dans Wikidata par correspondance exacte sur `P225`, et
**13 sur 13** acceptés par GBIF en `matchType: EXACT`, `status: ACCEPTED`. **Zéro divergence**
sur les familles annoncées dans `fruits.seed.json`.
Y compris *Cascabela thevetia* pour le laurier-jaune, alors que le synonyme
*Thevetia peruviana* circule largement. Le contrôle du statut GBIF était écrit pour attraper
exactement ce cas ; il n'a rien trouvé à corriger. C'est le bon résultat, et il est
maintenant **vérifié plutôt que supposé**`docs/verification-taxons.md`.
### Aucune machine ne peut valider une photo
La recherche Commons sur *Melicoccus bijugatus* (kénèt) remonte en deuxième position une
photographie de **singe capucin** mangeant le fruit. Le moteur de recherche classe par
pertinence textuelle, pas par contenu botanique.
Cette observation a produit une décision de conception : le schéma distingue désormais
`photo`, `planche_botanique` et `image_generee`. Les fonds Commons contiennent beaucoup de
planches anciennes du domaine public — Blanco, Merian — exactes mais stylisées. Une planche
documente une fiche ; elle ne peut pas porter une épreuve de reconnaissance du réel.
Sur 39 médias candidats retenus : **25 photographies, 14 planches botaniques.**
### Le mancenillier n'a aucune photographie dans le haut de sa pile
Trois entrées comptent moins de deux photographies parmi leurs trois premiers candidats :
| entrée | photos sur 3 candidats | ce que Commons remonte en tête |
|---|---|---|
| `mansiniye` (mancenillier) | **0** | trois planches gravées — Jacquin 1780, Green 1816-20, Hocquart 1821 |
| `pom-site` (pòm-sitè) | **0** | planches, dont deux Blanco |
| `medisinye` (medsinyé) | 1 | |
C'est l'entrée la plus critique du module « Pa touché » qui est la moins bien servie. Un
enfant doit reconnaître un mancenillier **sur une plage**, pas sur une gravure de 1780. Il
faudra descendre plus bas dans les dix candidats de `docs/planche-relecture-medias.md`, ou
photographier l'arbre sur le littoral — il est signalé par une bande de peinture rouge, ce
qui rend la séance de terrain praticable et sans risque de confusion.
Le pré-tri qui produit cette classification a lui-même été corrigé en cours de session : la
planche de Jacquin ressortait d'abord en « photo » parce que ni son titre ni son auteur ne
disent son siècle. La date de prise de vue est désormais examinée, et toute date antérieure
à 1900 classe le média en planche. Ce pré-tri reste **un tri, pas un verdict** : c'est le
relecteur humain qui corrige le champ.
### TRAMIL : la situation est pire que ce que le brief supposait
Vérification directe le 2026-07-27 : le pied de page de `tramil.net` affiche
« © Copyright 2017 TRAMIL all rights reserved », et le lien « Legal notice » du site renvoie
une **404**. Les conditions d'usage ne sont donc même pas consultables. La demande écrite
n'est pas une précaution, c'est la seule voie.
### iNaturalist : 93 % de non commercial, mesuré
Échantillon de 305 photographies de qualité recherche sur *Chrysobalanus icaco* : 280 en
CC BY-NC, 12 en CC0, 8 en CC BY, 5 en CC BY-NC-SA. Se limiter au non-NC réduirait
iNaturalist à un appoint marginal — ce qui donne son poids réel à la décision du porteur.
---
## Écarts constatés et signalés, non corrigés en silence
Le brief §9 impose de signaler les écarts plutôt que de les corriger discrètement.
1. **Le champ `danger` de la graine a deux formes.** Les niveaux « vigilance » (kénèt,
pòm-kannèl) portent leur texte dans `note`, les niveaux « élevé » et « critique » dans
`resume`. Le schéma impose un champ unique : la composition normalise vers `resume`, sans
réécrire un mot. C'est la porte de validation qui a levé l'incohérence, pas une relecture.
2. **Trois identifiants divergent du nom kréyòl au-delà des accents** : `ake`/`aki`,
`medisinye`/`medsinyé`, `lorye-jonn`/`lorié-jòn`. Non tranchés — `docs/kreyol-a-relire.md`.
3. **Deux planches Blanco produisaient le même identifiant de média** une fois tronquées à
60 caractères. Désambiguïsées par suffixe plutôt que perdues.
4. **`comestible: false` sur l'akée et la pomme-cajou** est une sous-estimation assumée :
les deux se mangent sous conditions strictes. Le choix prudent était le seul défendable
sans arbitrage humain — `docs/a-arbitrer.md` §1.
5. **Le brief demandait 8 fruits ; 13 entrées ont été produites** (les 5 plantes du module
« Pa touché » incluses, sur décision du porteur). La vérification coûtait le même effort
et le contenu de sécurité demande le plus long délai de relecture.
---
## La porte de validation
Le brief §2 exigeait que le contrôle soit « un script de build, pas une consigne ».
`tools/data/validate.mjs` refuse :
- une épreuve ou un indice s'appuyant sur un média non validé, non photographique, de
filière B, ou dont la vue n'est pas renseignée ;
- un média à attribution dont l'auteur est absent ;
- un compositing sur un média en partage à l'identique ou sous clause non commerciale ;
- une validation sans nom de validateur ;
- une épreuve portée par une plante dangereuse ;
- une entrée publiée avec moins de deux photos validées, ou dont l'orthographe kréyòl n'est
pas relue par un humain nommé.
`npm run test:porte` fabrique ces neuf cas et vérifie que le refus se produit, plus un cas
témoin conforme qui doit passer. **10/10.** Une règle de sécurité qu'on n'a jamais vue
refuser quelque chose est une intention, pas une règle.
---
## Ce qui bloque la suite
| Blocage | Bloque | Qui peut le lever |
|---|---|---|
| 0 média validé | Rekonèt sur données réelles (session 2) | le porteur, `docs/planche-relecture-medias.md` |
| Aucun relecteur kréyòl désigné | toute publication | le porteur |
| 13 enregistrements manquants | le moment de révélation | une après-midi d'enregistrement |
| Saisonnalité non sourcée | publication du mode Sézon | CIRAD, lettre prête |
| 6 points non arbitrés | publication | le porteur, `docs/a-arbitrer.md` |
**Le premier travail non délégable est la planche de relecture des médias.** La session 1 ne
l'exige pas — les fiches affichent texte, taxonomie et crédits sans photo. La session 2, si.
---
## Vérifications de fin de session
```
npm run verify:taxa → 13 taxons, 0 divergence
npm run ingest:commons → 130 candidats, 0 taxon sous le seuil de 2
npm run validate:data → 13 entrées, 39 médias, 0 validé, 0 erreur
npm run test:porte → 10/10
npm run build:credits → 13 entrées, 39 médias, 0 sous clause NC
npm run check:audio → 13 enregistrements à réaliser
```
Dépendances installées : `ajv` et `ajv-formats` uniquement, toutes deux importées et
utilisées (playbook §2.2 — aucune dépendance installée sans être utilisée).
**Prochaine session : 1 — Socle.** Ne pas la démarrer sans avoir relu ce document et
`docs/plan.md`.
+22
View File
@@ -0,0 +1,22 @@
# Vérification taxonomique — Wikidata × GBIF
> Généré par `npm run verify:taxa` le 2026-07-27.
> Ne pas éditer à la main : rejouer le script quand la graine change.
| id | nom de la graine | Wikidata | famille WD | GBIF | statut GBIF | famille GBIF | écarts |
|---|---|---|---|---|---|---|---|
| `kowosol` | *Annona muricata* | Q1709343 | Annonaceae | 5407273 | ACCEPTED | Annonaceae | aucun |
| `kenet` | *Melicoccus bijugatus* | Q279728 | Sapindaceae | 3189990 | ACCEPTED | Sapindaceae | aucun |
| `gouyav` | *Psidium guajava* | Q166843 | Myrtaceae | 5420380 | ACCEPTED | Myrtaceae | aucun |
| `pom-site` | *Spondias dulcis* | Q500383 | Anacardiaceae | 3190595 | ACCEPTED | Anacardiaceae | aucun |
| `zikak` | *Chrysobalanus icaco* | Q577669 | Chrysobalanaceae | 2985082 | ACCEPTED | Chrysobalanaceae | aucun |
| `pom-kannel` | *Annona squamosa* | Q275620 | Annonaceae | 5407099 | ACCEPTED | Annonaceae | aucun |
| `fwiyapen` | *Artocarpus altilis* | Q14677 | Moraceae | 2984573 | ACCEPTED | Moraceae | aucun |
| `pom-dlo` | *Syzygium samarangense* | Q11643111 | Myrtaceae | 3183180 | ACCEPTED | Myrtaceae | aucun |
| `mansiniye` | *Hippomane mancinella* | Q636480 | Euphorbiaceae | 3063705 | ACCEPTED | Euphorbiaceae | aucun |
| `ake` | *Blighia sapida* | Q417145 | Sapindaceae | 3189955 | ACCEPTED | Sapindaceae | aucun |
| `pom-kajou` | *Anacardium occidentale* | Q34007 | Anacardiaceae | 5421368 | ACCEPTED | Anacardiaceae | aucun |
| `medisinye` | *Jatropha curcas* | Q74644 | Euphorbiaceae | 3072953 | ACCEPTED | Euphorbiaceae | aucun |
| `lorye-jonn` | *Cascabela thevetia* | Q10694475 | Apocynaceae | 3169652 | ACCEPTED | Apocynaceae | aucun |
**0 entrée(s) sur 13 présentent au moins un écart.**
+298
View File
@@ -0,0 +1,298 @@
{
"$schema": "https://json-schema.org/draft/2020-12/schema",
"$id": "https://o-k-i.net/ki-fwi/fruits.schema.json",
"title": "Entrée du dataset KI FWI SA YÉ ?",
"description": "Un fruit ou une plante dangereuse. Un fichier par entrée dans src/lib/data/fruits/. Le kréyòl est la langue principale : noms.gcf est le nom de l'entrée, les autres langues en sont la traduction (ADR 0005).",
"type": "object",
"additionalProperties": false,
"required": [
"id",
"categorie",
"noms",
"orthographe",
"taxon",
"iles",
"comestible",
"danger",
"indices",
"medias",
"audio",
"sources_factuelles",
"valide"
],
"properties": {
"$schema": { "type": "string" },
"$comment": { "type": "string" },
"id": {
"type": "string",
"pattern": "^[a-z0-9]+(-[a-z0-9]+)*$",
"description": "Identifiant technique stable, sans diacritique. Sert de nom de fichier et de segment d'URL. Ne se renomme jamais après publication."
},
"categorie": {
"enum": ["fruit", "plante_dangereuse"]
},
"noms": {
"type": "object",
"additionalProperties": false,
"required": ["gcf"],
"properties": {
"gcf": { "type": "string", "minLength": 1, "description": "Nom kréyòl — nom principal de l'entrée." },
"fr": { "type": "string" },
"en": { "type": "string" },
"es": { "type": "string" }
}
},
"orthographe": {
"type": "object",
"additionalProperties": false,
"required": ["norme", "statut", "relu_par"],
"properties": {
"norme": {
"enum": ["gwadloupeyen"],
"description": "Norme unique du projet (ADR 0005). Ne jamais mélanger avec le matinitjé."
},
"statut": {
"enum": ["a_relire", "relu"],
"description": "Passe à 'relu' uniquement quand un locuteur humain a tranché. Aucun agent ne peut le faire."
},
"relu_par": {
"type": ["string", "null"],
"description": "Nom du relecteur humain. Obligatoirement non nul quand statut = relu."
}
}
},
"taxon": {
"type": "object",
"additionalProperties": false,
"required": ["scientifique", "famille", "wikidata", "gbif", "verifie_le", "verifie_contre"],
"properties": {
"scientifique": { "type": "string", "minLength": 3 },
"famille": { "type": "string", "pattern": "^[A-Z][a-z]+aceae$" },
"wikidata": { "type": "string", "pattern": "^Q[1-9][0-9]*$" },
"gbif": { "type": "integer", "minimum": 1 },
"verifie_le": { "type": "string", "format": "date" },
"verifie_contre": {
"type": "array",
"minItems": 2,
"uniqueItems": true,
"items": { "enum": ["wikidata", "gbif"] },
"description": "Le brief §8 exige les deux référentiels. Un seul ne suffit pas."
}
}
},
"iles": {
"type": "array",
"minItems": 1,
"uniqueItems": true,
"items": { "enum": ["gp", "mq", "gf", "re"] }
},
"saison_mois": {
"type": "array",
"uniqueItems": true,
"items": { "type": "integer", "minimum": 1, "maximum": 12 },
"description": "Mois de disponibilité. Alimente le mode Sézon. Varie selon l'île : à affiner avec le terrain."
},
"comestible": { "type": "boolean" },
"danger": {
"oneOf": [
{ "type": "null" },
{
"type": "object",
"additionalProperties": false,
"required": ["niveau", "resume"],
"properties": {
"niveau": { "enum": ["vigilance", "eleve", "critique"] },
"resume": { "type": "string", "minLength": 10 },
"note": { "type": "string" },
"signalement": { "type": "string" },
"conduite": { "type": "string", "description": "Conduite à tenir en cas d'exposition. Ton factuel, jamais anxiogène (brief §6)." }
}
}
]
},
"indices": {
"type": "object",
"additionalProperties": false,
"description": "Les indices lisibles sur le terrain. Alimentent le mode Kaché, dévoilés dans l'ordre feuille → écorce → coupe → fruit.",
"properties": {
"feuille": { "type": "string" },
"ecorce": { "type": "string" },
"port": { "type": "string" },
"coupe": { "type": "string" },
"fruit": { "type": "string" },
"fleur": { "type": "string" },
"latex": { "type": "string" },
"graine": { "type": "string" },
"usage_haie": { "type": "string" }
}
},
"medias": {
"type": "array",
"items": { "$ref": "#/$defs/media" }
},
"audio": {
"type": "object",
"additionalProperties": false,
"required": ["gcf", "locuteur"],
"properties": {
"gcf": {
"type": ["string", "null"],
"pattern": "^/audio/[a-z0-9-]+\\.opus$",
"description": "Prononciation kréyòl par une voix humaine. Aucune synthèse vocale (brief §6). Null tant que l'enregistrement manque ; le jeu doit se replier en silence."
},
"locuteur": { "type": ["string", "null"] }
}
},
"sources_factuelles": {
"type": "array",
"description": "Références consultées pour les indices, la saisonnalité et le danger. TRAMIL se cite ici — jamais comme source de fichiers (ADR 0001).",
"items": {
"type": "object",
"additionalProperties": false,
"required": ["titre", "url", "consulte_le"],
"properties": {
"titre": { "type": "string" },
"url": { "type": "string", "format": "uri" },
"consulte_le": { "type": "string", "format": "date" }
}
}
},
"valide": {
"type": "boolean",
"description": "L'entrée entière est-elle validée pour publication ? False par défaut. Ne passe à true que par décision humaine."
}
},
"allOf": [
{
"if": { "properties": { "categorie": { "const": "fruit" } }, "required": ["categorie"] },
"then": { "required": ["saison_mois"] }
},
{
"if": { "properties": { "categorie": { "const": "plante_dangereuse" } }, "required": ["categorie"] },
"then": {
"properties": { "danger": { "type": "object" } },
"description": "Une plante dangereuse a obligatoirement un bloc danger renseigné."
}
},
{
"if": { "properties": { "orthographe": { "properties": { "statut": { "const": "relu" } }, "required": ["statut"] } } },
"then": { "properties": { "orthographe": { "properties": { "relu_par": { "type": "string", "minLength": 2 } } } } }
}
],
"$defs": {
"media": {
"type": "object",
"additionalProperties": false,
"required": [
"id",
"filiere",
"type_media",
"vue",
"usages",
"source",
"auteur",
"licence",
"url_fichier",
"url_description",
"attribution_requise",
"partage_identique",
"usage_non_commercial",
"composite",
"valide",
"valide_par"
],
"properties": {
"id": { "type": "string", "pattern": "^[a-z0-9]+(-[a-z0-9]+)*$" },
"filiere": {
"enum": ["A", "B"],
"description": "A = vérité (photographie réelle, sert à identifier). B = décor (image générée, ne sert jamais à identifier). ADR 0004."
},
"type_media": {
"enum": ["photo", "planche_botanique", "image_generee"],
"description": "Une planche botanique ancienne est exacte mais stylisée : elle documente, elle n'entraîne pas la reconnaissance du réel. Seule une photo peut porter une épreuve."
},
"vue": {
"enum": ["fruit_entier", "coupe", "feuille", "ecorce", "port", "fleur", "graine", null],
"description": "Les quatre vues pédagogiques du pack (arbre · fruit entier · coupe · feuille), étendues. Null tant qu'un humain n'a pas regardé l'image."
},
"usages": {
"type": "array",
"uniqueItems": true,
"items": { "enum": ["epreuve", "indice", "fiche", "decor"] },
"description": "Où ce média est employé. 'epreuve' et 'indice' imposent filière A + photo + validé."
},
"source": {
"enum": ["wikimedia_commons", "inaturalist", "porteur", "herbier", "comfyui"]
},
"auteur": { "type": ["string", "null"] },
"licence": {
"enum": [
"CC0-1.0",
"PD",
"CC-BY-2.0",
"CC-BY-3.0",
"CC-BY-4.0",
"CC-BY-SA-2.0",
"CC-BY-SA-2.5",
"CC-BY-SA-3.0",
"CC-BY-SA-4.0",
"CC-BY-NC-4.0",
"CC-BY-NC-SA-4.0",
"OKI-CC-BY-SA-4.0"
]
},
"licence_url": { "type": ["string", "null"] },
"url_fichier": { "type": "string", "format": "uri" },
"url_description": { "type": "string", "format": "uri" },
"largeur": { "type": ["integer", "null"] },
"hauteur": { "type": ["integer", "null"] },
"mime": { "type": ["string", "null"] },
"description": { "type": ["string", "null"] },
"date_prise_de_vue": { "type": ["string", "null"] },
"attribution_requise": { "type": "boolean" },
"partage_identique": { "type": "boolean" },
"usage_non_commercial": {
"type": "boolean",
"description": "CC BY-NC. Accepté par l'ADR 0001 au prix d'un engagement non commercial définitif. Doit apparaître dans CREDITS.md."
},
"composite": {
"type": "boolean",
"description": "Ce média a-t-il été fusionné avec un autre ? Interdit sur tout média SA ou NC (conflit de licence, ADR 0001)."
},
"valide": { "type": "boolean" },
"valide_par": { "type": ["string", "null"] },
"valide_le": { "type": ["string", "null"], "format": "date" },
"note_validation": { "type": ["string", "null"] }
}
}
}
}
+96
View File
@@ -0,0 +1,96 @@
{
"name": "ki-fwi",
"version": "0.0.0",
"lockfileVersion": 3,
"requires": true,
"packages": {
"": {
"name": "ki-fwi",
"version": "0.0.0",
"license": "AGPL-3.0-or-later",
"devDependencies": {
"ajv": "^8.17.1",
"ajv-formats": "^3.0.1"
},
"engines": {
"node": ">=22"
}
},
"node_modules/ajv": {
"version": "8.20.0",
"resolved": "https://registry.npmjs.org/ajv/-/ajv-8.20.0.tgz",
"integrity": "sha512-Thbli+OlOj+iMPYFBVBfJ3OmCAnaSyNn4M1vz9T6Gka5Jt9ba/HIR56joy65tY6kx/FCF5VXNB819Y7/GUrBGA==",
"dev": true,
"license": "MIT",
"dependencies": {
"fast-deep-equal": "^3.1.3",
"fast-uri": "^3.0.1",
"json-schema-traverse": "^1.0.0",
"require-from-string": "^2.0.2"
},
"funding": {
"type": "github",
"url": "https://github.com/sponsors/epoberezkin"
}
},
"node_modules/ajv-formats": {
"version": "3.0.1",
"resolved": "https://registry.npmjs.org/ajv-formats/-/ajv-formats-3.0.1.tgz",
"integrity": "sha512-8iUql50EUR+uUcdRQ3HDqa6EVyo3docL8g5WJ3FNcWmu62IbkGUue/pEyLBW8VGKKucTPgqeks4fIU1DA4yowQ==",
"dev": true,
"license": "MIT",
"dependencies": {
"ajv": "^8.0.0"
},
"peerDependencies": {
"ajv": "^8.0.0"
},
"peerDependenciesMeta": {
"ajv": {
"optional": true
}
}
},
"node_modules/fast-deep-equal": {
"version": "3.1.3",
"resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz",
"integrity": "sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==",
"dev": true,
"license": "MIT"
},
"node_modules/fast-uri": {
"version": "3.1.4",
"resolved": "https://registry.npmjs.org/fast-uri/-/fast-uri-3.1.4.tgz",
"integrity": "sha512-8JnbkQ4juDyvYs4mgFGQqg4yCYtFDtUtmp2QIQq11ZZe5CFQ5wcqm1rqDgAh/QdMySuBnPzMUiJUNZG5N/AiQw==",
"dev": true,
"funding": [
{
"type": "github",
"url": "https://github.com/sponsors/fastify"
},
{
"type": "opencollective",
"url": "https://opencollective.com/fastify"
}
],
"license": "BSD-3-Clause"
},
"node_modules/json-schema-traverse": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-1.0.0.tgz",
"integrity": "sha512-NM8/P9n3XjXhIZn1lLhkFaACTOURQXjWhV4BA/RnOv8xvgqtqpAX9IO4mRQxSx1Rlo4tqzeqb0sOlruaOy3dug==",
"dev": true,
"license": "MIT"
},
"node_modules/require-from-string": {
"version": "2.0.2",
"resolved": "https://registry.npmjs.org/require-from-string/-/require-from-string-2.0.2.tgz",
"integrity": "sha512-Xf0nWe6RseziFMu+Ap9biiUbmplq6S9/p+7w7YXP/JBHhrUDDUhwa+vANyubuqfZWTveU//DYVGsDG7RKL/vEw==",
"dev": true,
"license": "MIT",
"engines": {
"node": ">=0.10.0"
}
}
}
}
+24
View File
@@ -0,0 +1,24 @@
{
"name": "ki-fwi",
"version": "0.0.0",
"private": true,
"description": "KI FWI SA YÉ ? — jeu éducatif libre : reconnaître les fruits, les arbres et les plantes des Antilles.",
"license": "AGPL-3.0-or-later",
"type": "module",
"engines": {
"node": ">=22"
},
"scripts": {
"verify:taxa": "node tools/data/verify-taxa.mjs",
"ingest:commons": "node tools/data/ingest-commons.mjs",
"build:dataset": "node tools/data/build-dataset.mjs",
"check:audio": "node tools/data/check-audio.mjs",
"validate:data": "node tools/data/validate.mjs",
"build:credits": "node tools/data/build-credits.mjs",
"test:porte": "node tools/data/test-porte.mjs"
},
"devDependencies": {
"ajv": "^8.17.1",
"ajv-formats": "^3.0.1"
}
}
+127
View File
@@ -0,0 +1,127 @@
{
"$schema": "../../../../fruits.schema.json",
"id": "ake",
"categorie": "plante_dangereuse",
"noms": {
"gcf": "aki",
"fr": "akée",
"en": "ackee",
"es": "seso vegetal"
},
"orthographe": {
"norme": "gwadloupeyen",
"statut": "a_relire",
"relu_par": null
},
"taxon": {
"scientifique": "Blighia sapida",
"famille": "Sapindaceae",
"wikidata": "Q417145",
"gbif": 3189955,
"verifie_le": "2026-07-27",
"verifie_contre": [
"wikidata",
"gbif"
]
},
"iles": [
"gp",
"mq",
"gf"
],
"comestible": false,
"danger": {
"niveau": "critique",
"conduite": "Ne jamais forcer un fruit fermé. En cas d'ingestion suspecte : urgences.",
"resume": "Comestible UNIQUEMENT ouvert naturellement et mûr, et seulement la partie charnue claire. Le fruit non mûr et les graines sont toxiques (hypoglycine)."
},
"indices": {
"fruit": "capsule rouge-orangé qui s'ouvre en trois valves à maturité, graines noires brillantes"
},
"medias": [
{
"id": "ackee-001",
"filiere": "A",
"type_media": "photo",
"vue": null,
"usages": [],
"source": "wikimedia_commons",
"auteur": "Jerome Walker",
"licence": "CC-BY-SA-3.0",
"licence_url": "http://creativecommons.org/licenses/by-sa/3.0/",
"url_fichier": "https://upload.wikimedia.org/wikipedia/commons/c/cf/Ackee_001.jpg",
"url_description": "https://commons.wikimedia.org/wiki/File:Ackee_001.jpg",
"largeur": 2848,
"hauteur": 2136,
"mime": "image/jpeg",
"description": "Photo of closed Ackee ( Blighia sapida ) fruit on tree",
"date_prise_de_vue": "2005-10-21",
"attribution_requise": true,
"partage_identique": true,
"usage_non_commercial": false,
"composite": false,
"valide": false,
"valide_par": null,
"valide_le": null,
"note_validation": null
},
{
"id": "walter-hood-fitch03",
"filiere": "A",
"type_media": "planche_botanique",
"vue": null,
"usages": [],
"source": "wikimedia_commons",
"auteur": "Walter Hood Fitch",
"licence": "PD",
"licence_url": null,
"url_fichier": "https://upload.wikimedia.org/wikipedia/commons/1/19/Walter_Hood_Fitch03.JPG",
"url_description": "https://commons.wikimedia.org/wiki/File:Walter_Hood_Fitch03.JPG",
"largeur": 1194,
"hauteur": 1732,
"mime": "image/jpeg",
"description": "Guava, Mango, Mangosteen, Lychee, Pistachio, Avocado Pear, Durian, from \"A History of the Vegetable Kingdom\" by William Rhind (published in London by Blackie &amp; Son, 1874). Walter Hood Fitch supplied most of the illus",
"date_prise_de_vue": "1874",
"attribution_requise": false,
"partage_identique": false,
"usage_non_commercial": false,
"composite": false,
"valide": false,
"valide_par": null,
"valide_le": null,
"note_validation": null
},
{
"id": "owoce-aka",
"filiere": "A",
"type_media": "photo",
"vue": null,
"usages": [],
"source": "wikimedia_commons",
"auteur": "Agnieszka Kwiecień ( Nova )",
"licence": "CC-BY-SA-3.0",
"licence_url": "https://creativecommons.org/licenses/by-sa/3.0",
"url_fichier": "https://upload.wikimedia.org/wikipedia/commons/1/15/Owoce_Aka.jpg",
"url_description": "https://commons.wikimedia.org/wiki/File:Owoce_Aka.jpg",
"largeur": 1860,
"hauteur": 1860,
"mime": "image/jpeg",
"description": "Ackee - the fruit of Blighia sapida .",
"date_prise_de_vue": "2013-05-11",
"attribution_requise": true,
"partage_identique": true,
"usage_non_commercial": false,
"composite": false,
"valide": false,
"valide_par": null,
"valide_le": null,
"note_validation": null
}
],
"audio": {
"gcf": null,
"locuteur": null
},
"sources_factuelles": [],
"valide": false
}
+135
View File
@@ -0,0 +1,135 @@
{
"$schema": "../../../../fruits.schema.json",
"id": "fwiyapen",
"categorie": "fruit",
"noms": {
"gcf": "fwiyapen",
"fr": "fruit à pain",
"en": "breadfruit",
"es": "fruta del pan"
},
"orthographe": {
"norme": "gwadloupeyen",
"statut": "a_relire",
"relu_par": null
},
"taxon": {
"scientifique": "Artocarpus altilis",
"famille": "Moraceae",
"wikidata": "Q14677",
"gbif": 2984573,
"verifie_le": "2026-07-27",
"verifie_contre": [
"wikidata",
"gbif"
]
},
"iles": [
"gp",
"mq",
"gf",
"re"
],
"saison_mois": [
7,
8,
9,
10,
11,
12
],
"comestible": true,
"danger": null,
"indices": {
"feuille": "très grande, profondément lobée — la plus reconnaissable de toutes",
"ecorce": "grise, latex blanc à l'entaille",
"port": "grand arbre 1525 m, houppier large",
"coupe": "chair blanc-crème dense, se cuisine, ne se mange pas cru"
},
"medias": [
{
"id": "artocarpus-incisus-blanco2-267",
"filiere": "A",
"type_media": "planche_botanique",
"vue": null,
"usages": [],
"source": "wikimedia_commons",
"auteur": "Francisco Manuel Blanco (O.S.A.)",
"licence": "PD",
"licence_url": null,
"url_fichier": "https://upload.wikimedia.org/wikipedia/commons/5/5e/Artocarpus_incisus_Blanco2.267.png",
"url_description": "https://commons.wikimedia.org/wiki/File:Artocarpus_incisus_Blanco2.267.png",
"largeur": 1379,
"hauteur": 2020,
"mime": "image/png",
"description": "Artocarpus incisa Blanco (inside Artocarpus altilis species)",
"date_prise_de_vue": "1880-1883?",
"attribution_requise": false,
"partage_identique": false,
"usage_non_commercial": false,
"composite": false,
"valide": false,
"valide_par": null,
"valide_le": null,
"note_validation": null
},
{
"id": "starr-031209-0031-artocarpus-altilis",
"filiere": "A",
"type_media": "photo",
"vue": null,
"usages": [],
"source": "wikimedia_commons",
"auteur": "Forest &amp; Kim Starr",
"licence": "CC-BY-3.0",
"licence_url": "https://creativecommons.org/licenses/by/3.0",
"url_fichier": "https://upload.wikimedia.org/wikipedia/commons/7/78/Starr_031209-0031_Artocarpus_altilis.jpg",
"url_description": "https://commons.wikimedia.org/wiki/File:Starr_031209-0031_Artocarpus_altilis.jpg",
"largeur": 1632,
"hauteur": 1224,
"mime": "image/jpeg",
"description": "Artocarpus altilis (leaves and fruit). Location: Maui, Puehuihueiki cemetary Lahaina",
"date_prise_de_vue": "2003-12-09",
"attribution_requise": true,
"partage_identique": false,
"usage_non_commercial": false,
"composite": false,
"valide": false,
"valide_par": null,
"valide_le": null,
"note_validation": null
},
{
"id": "artocarpus-altilis-fruit",
"filiere": "A",
"type_media": "photo",
"vue": null,
"usages": [],
"source": "wikimedia_commons",
"auteur": "Hans Hillewaert",
"licence": "CC-BY-SA-3.0",
"licence_url": "https://creativecommons.org/licenses/by-sa/3.0",
"url_fichier": "https://upload.wikimedia.org/wikipedia/commons/5/57/Artocarpus_altilis_%28fruit%29.jpg",
"url_description": "https://commons.wikimedia.org/wiki/File:Artocarpus_altilis_(fruit).jpg",
"largeur": 2848,
"hauteur": 3799,
"mime": "image/jpeg",
"description": "Breadfruit at Tortuguero, Costa Rica",
"date_prise_de_vue": "2009-08-12",
"attribution_requise": true,
"partage_identique": true,
"usage_non_commercial": false,
"composite": false,
"valide": false,
"valide_par": null,
"valide_le": null,
"note_validation": null
}
],
"audio": {
"gcf": null,
"locuteur": null
},
"sources_factuelles": [],
"valide": false
}
+134
View File
@@ -0,0 +1,134 @@
{
"$schema": "../../../../fruits.schema.json",
"id": "gouyav",
"categorie": "fruit",
"noms": {
"gcf": "gouyav",
"fr": "goyave",
"en": "guava",
"es": "guayaba"
},
"orthographe": {
"norme": "gwadloupeyen",
"statut": "a_relire",
"relu_par": null
},
"taxon": {
"scientifique": "Psidium guajava",
"famille": "Myrtaceae",
"wikidata": "Q166843",
"gbif": 5420380,
"verifie_le": "2026-07-27",
"verifie_contre": [
"wikidata",
"gbif"
]
},
"iles": [
"gp",
"mq",
"gf",
"re"
],
"saison_mois": [
8,
9,
10,
11,
12
],
"comestible": true,
"danger": null,
"indices": {
"feuille": "opposée, ovale, nervures secondaires très marquées en creux",
"ecorce": "lisse, se desquamant en plaques, brun-vert clair — indice très reconnaissable",
"port": "arbuste 38 m, tronc souvent tortueux",
"coupe": "chair rose ou blanche, nombreuses petites graines dures"
},
"medias": [
{
"id": "psidium-guajava-fruit-2",
"filiere": "A",
"type_media": "photo",
"vue": null,
"usages": [],
"source": "wikimedia_commons",
"auteur": "Own work",
"licence": "CC-BY-SA-3.0",
"licence_url": "http://creativecommons.org/licenses/by-sa/3.0/",
"url_fichier": "https://upload.wikimedia.org/wikipedia/commons/1/19/Psidium_guajava_fruit_%282%29.jpg",
"url_description": "https://commons.wikimedia.org/wiki/File:Psidium_guajava_fruit_(2).jpg",
"largeur": 744,
"hauteur": 768,
"mime": "image/jpeg",
"description": "Guava fruit bought and photographed in Taiwan. Binomial name is tentative.",
"date_prise_de_vue": "Taken on 20 January 2004",
"attribution_requise": true,
"partage_identique": true,
"usage_non_commercial": false,
"composite": false,
"valide": false,
"valide_par": null,
"valide_le": null,
"note_validation": null
},
{
"id": "apple-guava",
"filiere": "A",
"type_media": "photo",
"vue": null,
"usages": [],
"source": "wikimedia_commons",
"auteur": "Fuadsyazwan ( talk )",
"licence": "PD",
"licence_url": null,
"url_fichier": "https://upload.wikimedia.org/wikipedia/commons/3/34/Apple_Guava.jpg",
"url_description": "https://commons.wikimedia.org/wiki/File:Apple_Guava.jpg",
"largeur": 1632,
"hauteur": 1224,
"mime": "image/jpeg",
"description": "A shot of apple guava",
"date_prise_de_vue": "6 March 2008 (original upload date) ( Original text: 06 March 2008 )",
"attribution_requise": false,
"partage_identique": false,
"usage_non_commercial": false,
"composite": false,
"valide": false,
"valide_par": null,
"valide_le": null,
"note_validation": null
},
{
"id": "starr-111012-8771-psidium-guajava-burnt-fruit-kahana-maui-24",
"filiere": "A",
"type_media": "photo",
"vue": null,
"usages": [],
"source": "wikimedia_commons",
"auteur": "Forest and Kim Starr",
"licence": "CC-BY-3.0",
"licence_url": "https://creativecommons.org/licenses/by/3.0/us/deed.en",
"url_fichier": "https://upload.wikimedia.org/wikipedia/commons/c/cb/Starr-111012-8771-Psidium_guajava-burnt_fruit-Kahana-Maui_%2824488703784%29.jpg",
"url_description": "https://commons.wikimedia.org/wiki/File:Starr-111012-8771-Psidium_guajava-burnt_fruit-Kahana-Maui_(24488703784).jpg",
"largeur": 2592,
"hauteur": 3456,
"mime": "image/jpeg",
"description": "Psidium guajava (Guava) Burnt fruit at Kahana, Maui, Hawaii. October 12, 2011 #111012-8771 Image Use Policy",
"date_prise_de_vue": "2011-10-12 10:51",
"attribution_requise": true,
"partage_identique": false,
"usage_non_commercial": false,
"composite": false,
"valide": false,
"valide_par": null,
"valide_le": null,
"note_validation": null
}
],
"audio": {
"gcf": null,
"locuteur": null
},
"sources_factuelles": [],
"valide": false
}
+134
View File
@@ -0,0 +1,134 @@
{
"$schema": "../../../../fruits.schema.json",
"id": "kenet",
"categorie": "fruit",
"noms": {
"gcf": "kénèt",
"fr": "quenette",
"en": "Spanish lime",
"es": "mamoncillo"
},
"orthographe": {
"norme": "gwadloupeyen",
"statut": "a_relire",
"relu_par": null
},
"taxon": {
"scientifique": "Melicoccus bijugatus",
"famille": "Sapindaceae",
"wikidata": "Q279728",
"gbif": 3189990,
"verifie_le": "2026-07-27",
"verifie_contre": [
"wikidata",
"gbif"
]
},
"iles": [
"gp",
"mq"
],
"saison_mois": [
6,
7,
8,
9
],
"comestible": true,
"danger": {
"niveau": "vigilance",
"resume": "noyau volumineux — risque d'étouffement chez le jeune enfant. À mentionner sobrement."
},
"indices": {
"feuille": "composée paripennée, 2 paires de folioles",
"ecorce": "lisse, grise",
"port": "grand arbre pouvant dépasser 20 m",
"coupe": "pulpe orangée gélatineuse autour d'un gros noyau"
},
"medias": [
{
"id": "melicoccus-bijugatus",
"filiere": "A",
"type_media": "photo",
"vue": null,
"usages": [],
"source": "wikimedia_commons",
"auteur": "No machine-readable author provided. Hans B.~commonswiki assumed (based on copyright claims).",
"licence": "PD",
"licence_url": null,
"url_fichier": "https://upload.wikimedia.org/wikipedia/commons/6/6e/Melicoccus_bijugatus.jpg",
"url_description": "https://commons.wikimedia.org/wiki/File:Melicoccus_bijugatus.jpg",
"largeur": 2126,
"hauteur": 1757,
"mime": "image/jpeg",
"description": "Melicoccus bijugatus bought at the Visserijplein market in Rotterdam, The Netherlands",
"date_prise_de_vue": "18 May 2006 (original upload date)",
"attribution_requise": false,
"partage_identique": false,
"usage_non_commercial": false,
"composite": false,
"valide": false,
"valide_par": null,
"valide_le": null,
"note_validation": null
},
{
"id": "cebus-capucinus-puntarenas-costa-rica",
"filiere": "A",
"type_media": "photo",
"vue": null,
"usages": [],
"source": "wikimedia_commons",
"auteur": "kansasphoto",
"licence": "CC-BY-2.0",
"licence_url": "https://creativecommons.org/licenses/by/2.0",
"url_fichier": "https://upload.wikimedia.org/wikipedia/commons/0/0d/Cebus_capucinus_Puntarenas_Costa_Rica.jpg",
"url_description": "https://commons.wikimedia.org/wiki/File:Cebus_capucinus_Puntarenas_Costa_Rica.jpg",
"largeur": 3924,
"hauteur": 2616,
"mime": "image/jpeg",
"description": "Cebus capucinus , picture taked in Puntarenas, Costa Rica.",
"date_prise_de_vue": "2009-04-09",
"attribution_requise": true,
"partage_identique": false,
"usage_non_commercial": false,
"composite": false,
"valide": false,
"valide_par": null,
"valide_le": null,
"note_validation": null
},
{
"id": "una-rama-de-mamon",
"filiere": "A",
"type_media": "photo",
"vue": null,
"usages": [],
"source": "wikimedia_commons",
"auteur": "EEIM",
"licence": "CC-BY-SA-3.0",
"licence_url": "https://creativecommons.org/licenses/by-sa/3.0",
"url_fichier": "https://upload.wikimedia.org/wikipedia/commons/4/4f/Una_rama_de_mamon.jpeg",
"url_description": "https://commons.wikimedia.org/wiki/File:Una_rama_de_mamon.jpeg",
"largeur": 3264,
"hauteur": 2448,
"mime": "image/jpeg",
"description": "ramas",
"date_prise_de_vue": "8 December 2015 (according to Exif data)",
"attribution_requise": true,
"partage_identique": true,
"usage_non_commercial": false,
"composite": false,
"valide": false,
"valide_par": null,
"valide_le": null,
"note_validation": null
}
],
"audio": {
"gcf": null,
"locuteur": null
},
"sources_factuelles": [],
"valide": false
}
+133
View File
@@ -0,0 +1,133 @@
{
"$schema": "../../../../fruits.schema.json",
"id": "kowosol",
"categorie": "fruit",
"noms": {
"gcf": "kowosòl",
"fr": "corossol",
"en": "soursop",
"es": "guanábana"
},
"orthographe": {
"norme": "gwadloupeyen",
"statut": "a_relire",
"relu_par": null
},
"taxon": {
"scientifique": "Annona muricata",
"famille": "Annonaceae",
"wikidata": "Q1709343",
"gbif": 5407273,
"verifie_le": "2026-07-27",
"verifie_contre": [
"wikidata",
"gbif"
]
},
"iles": [
"gp",
"mq",
"gf"
],
"saison_mois": [
7,
8,
9,
10,
11
],
"comestible": true,
"danger": null,
"indices": {
"feuille": "simple, alterne, oblongue, vert foncé luisant dessus, odeur forte au froissement",
"ecorce": "grisâtre, fissurée avec l'âge",
"port": "petit arbre 48 m, houppier peu dense",
"coupe": "chair blanche fibreuse, nombreuses graines noires luisantes"
},
"medias": [
{
"id": "soursop-fruit",
"filiere": "A",
"type_media": "photo",
"vue": null,
"usages": [],
"source": "wikimedia_commons",
"auteur": "USGov",
"licence": "PD",
"licence_url": null,
"url_fichier": "https://upload.wikimedia.org/wikipedia/commons/a/a8/Soursop_fruit.jpg",
"url_description": "https://commons.wikimedia.org/wiki/File:Soursop_fruit.jpg",
"largeur": 365,
"hauteur": 274,
"mime": "image/jpeg",
"description": "Picture of soursop fruit, Annona muricata",
"date_prise_de_vue": "uploaded on 9 November 2005",
"attribution_requise": false,
"partage_identique": false,
"usage_non_commercial": false,
"composite": false,
"valide": false,
"valide_par": null,
"valide_le": null,
"note_validation": null
},
{
"id": "annona-muricata-1",
"filiere": "A",
"type_media": "planche_botanique",
"vue": null,
"usages": [],
"source": "wikimedia_commons",
"auteur": "Damien Boilley from suburbs of Paris, France",
"licence": "CC-BY-2.0",
"licence_url": "https://creativecommons.org/licenses/by/2.0",
"url_fichier": "https://upload.wikimedia.org/wikipedia/commons/6/6d/Annona_muricata_1.jpg",
"url_description": "https://commons.wikimedia.org/wiki/File:Annona_muricata_1.jpg",
"largeur": 960,
"hauteur": 1280,
"mime": "image/jpeg",
"description": "Soursop fruit ( Annona muricata ). Photograph taken at the Jardin d'Éden botanical park, Saint-Gilles les Bains ( commune of Saint-Paul ), Réunion Island (Indian Ocean, a part of the French Republic).",
"date_prise_de_vue": "2006-01-05",
"attribution_requise": true,
"partage_identique": false,
"usage_non_commercial": false,
"composite": false,
"valide": false,
"valide_par": null,
"valide_le": null,
"note_validation": null
},
{
"id": "annona-muricata2",
"filiere": "A",
"type_media": "photo",
"vue": null,
"usages": [],
"source": "wikimedia_commons",
"auteur": "User:Hans_B.",
"licence": "PD",
"licence_url": null,
"url_fichier": "https://upload.wikimedia.org/wikipedia/commons/b/bd/Annona_muricata2.jpg",
"url_description": "https://commons.wikimedia.org/wiki/File:Annona_muricata2.jpg",
"largeur": 2592,
"hauteur": 1944,
"mime": "image/jpeg",
"description": "Annona muricata , bought at the Binnenrotte market in Rotterdam, The Netherlands",
"date_prise_de_vue": "2006-05-30",
"attribution_requise": false,
"partage_identique": false,
"usage_non_commercial": false,
"composite": false,
"valide": false,
"valide_par": null,
"valide_le": null,
"note_validation": null
}
],
"audio": {
"gcf": null,
"locuteur": null
},
"sources_factuelles": [],
"valide": false
}
+129
View File
@@ -0,0 +1,129 @@
{
"$schema": "../../../../fruits.schema.json",
"id": "lorye-jonn",
"categorie": "plante_dangereuse",
"noms": {
"gcf": "lorié-jòn",
"fr": "laurier jaune",
"en": "yellow oleander",
"es": "cabalonga"
},
"orthographe": {
"norme": "gwadloupeyen",
"statut": "a_relire",
"relu_par": null
},
"taxon": {
"scientifique": "Cascabela thevetia",
"famille": "Apocynaceae",
"wikidata": "Q10694475",
"gbif": 3169652,
"verifie_le": "2026-07-27",
"verifie_contre": [
"wikidata",
"gbif"
]
},
"iles": [
"gp",
"mq",
"gf",
"re"
],
"comestible": false,
"danger": {
"niveau": "critique",
"resume": "Toute la plante est toxique, les graines particulièrement (cardiotoxiques). Plante ornementale très courante — d'où le risque."
},
"indices": {
"fleur": "trompette jaune vif",
"fruit": "drupe verte anguleuse devenant noire, une graine dure à l'intérieur",
"latex": "latex blanc à la cassure"
},
"medias": [
{
"id": "thevetia-peruviana1",
"filiere": "A",
"type_media": "planche_botanique",
"vue": null,
"usages": [],
"source": "wikimedia_commons",
"auteur": "No machine-readable author provided. Hans B.~commonswiki assumed (based on copyright claims).",
"licence": "PD",
"licence_url": null,
"url_fichier": "https://upload.wikimedia.org/wikipedia/commons/f/f0/Thevetia_peruviana1.jpg",
"url_description": "https://commons.wikimedia.org/wiki/File:Thevetia_peruviana1.jpg",
"largeur": 2592,
"hauteur": 1944,
"mime": "image/jpeg",
"description": "Thevetia peruviana , picture taken at the Passiflorahoeve in Harskamp, The Netherlands",
"date_prise_de_vue": "14 July 2006 (according to Exif data)",
"attribution_requise": false,
"partage_identique": false,
"usage_non_commercial": false,
"composite": false,
"valide": false,
"valide_par": null,
"valide_le": null,
"note_validation": null
},
{
"id": "yellow-oleander-thevetia-peruviana-leaves-flowers-in-kolkata",
"filiere": "A",
"type_media": "photo",
"vue": null,
"usages": [],
"source": "wikimedia_commons",
"auteur": "J.M.Garg",
"licence": "CC-BY-SA-3.0",
"licence_url": "https://creativecommons.org/licenses/by-sa/3.0",
"url_fichier": "https://upload.wikimedia.org/wikipedia/commons/8/87/Yellow_Oleander_%28Thevetia_peruviana%29_leaves_%26_flowers_in_Kolkata_W_IMG_8008.jpg",
"url_description": "https://commons.wikimedia.org/wiki/File:Yellow_Oleander_(Thevetia_peruviana)_leaves_%26_flowers_in_Kolkata_W_IMG_8008.jpg",
"largeur": 619,
"hauteur": 600,
"mime": "image/jpeg",
"description": "Yellow Oleander Thevetia peruviana in Kolkata , West Bengal , India .",
"date_prise_de_vue": "02.06.07",
"attribution_requise": true,
"partage_identique": true,
"usage_non_commercial": false,
"composite": false,
"valide": false,
"valide_par": null,
"valide_le": null,
"note_validation": null
},
{
"id": "starr-060916-8881-thevetia-peruviana",
"filiere": "A",
"type_media": "photo",
"vue": null,
"usages": [],
"source": "wikimedia_commons",
"auteur": "Forest &amp; Kim Starr",
"licence": "CC-BY-3.0",
"licence_url": "https://creativecommons.org/licenses/by/3.0",
"url_fichier": "https://upload.wikimedia.org/wikipedia/commons/d/dc/Starr_060916-8881_Thevetia_peruviana.jpg",
"url_description": "https://commons.wikimedia.org/wiki/File:Starr_060916-8881_Thevetia_peruviana.jpg",
"largeur": 2592,
"hauteur": 1944,
"mime": "image/jpeg",
"description": "Thevetia peruviana (habit). Location: Maui, Kula",
"date_prise_de_vue": "2006-09-16",
"attribution_requise": true,
"partage_identique": false,
"usage_non_commercial": false,
"composite": false,
"valide": false,
"valide_par": null,
"valide_le": null,
"note_validation": null
}
],
"audio": {
"gcf": null,
"locuteur": null
},
"sources_factuelles": [],
"valide": false
}
+129
View File
@@ -0,0 +1,129 @@
{
"$schema": "../../../../fruits.schema.json",
"id": "mansiniye",
"categorie": "plante_dangereuse",
"noms": {
"gcf": "mansiniyé",
"fr": "mancenillier",
"en": "manchineel",
"es": "manzanillo"
},
"orthographe": {
"norme": "gwadloupeyen",
"statut": "a_relire",
"relu_par": null
},
"taxon": {
"scientifique": "Hippomane mancinella",
"famille": "Euphorbiaceae",
"wikidata": "Q636480",
"gbif": 3063705,
"verifie_le": "2026-07-27",
"verifie_contre": [
"wikidata",
"gbif"
]
},
"iles": [
"gp",
"mq"
],
"comestible": false,
"danger": {
"niveau": "critique",
"signalement": "Arbres marqués d'une bande de peinture rouge sur le littoral en Martinique et en Guadeloupe.",
"conduite": "En cas de contact : rincer abondamment à l'eau, consulter.",
"resume": "Ne jamais toucher, ne jamais manger le fruit, ne jamais s'abriter dessous sous la pluie, ne jamais brûler le bois."
},
"indices": {
"feuille": "petite, ovale, luisante, nervure médiane jaune, souvent une glande à la base du limbe",
"port": "arbre du bord de mer, houppier étalé",
"fruit": "petite pomme verte à jaunâtre, d'aspect appétissant — c'est là tout le danger"
},
"medias": [
{
"id": "hippomane-mancinella-hocquart-1821",
"filiere": "A",
"type_media": "planche_botanique",
"vue": null,
"usages": [],
"source": "wikimedia_commons",
"auteur": "M. Hocquart",
"licence": "PD",
"licence_url": null,
"url_fichier": "https://upload.wikimedia.org/wikipedia/commons/1/17/Hippomane_mancinella-Hocquart_1821.jpeg",
"url_description": "https://commons.wikimedia.org/wiki/File:Hippomane_mancinella-Hocquart_1821.jpeg",
"largeur": 363,
"hauteur": 500,
"mime": "image/jpeg",
"description": "Hippomane mancinella illustration",
"date_prise_de_vue": "1821",
"attribution_requise": false,
"partage_identique": false,
"usage_non_commercial": false,
"composite": false,
"valide": false,
"valide_par": null,
"valide_le": null,
"note_validation": null
},
{
"id": "hyacinthus-orientalis-and-hippomane-mancinella",
"filiere": "A",
"type_media": "planche_botanique",
"vue": null,
"usages": [],
"source": "wikimedia_commons",
"auteur": "\"The Universal Herbal\" by Thomas Green (published 181620)",
"licence": "PD",
"licence_url": null,
"url_fichier": "https://upload.wikimedia.org/wikipedia/commons/0/09/Hyacinthus_orientalis_and_Hippomane_mancinella.gif",
"url_description": "https://commons.wikimedia.org/wiki/File:Hyacinthus_orientalis_and_Hippomane_mancinella.gif",
"largeur": 317,
"hauteur": 252,
"mime": "image/gif",
"description": "Hyacinthus orientalis and Hippomane mancinella",
"date_prise_de_vue": "181620",
"attribution_requise": false,
"partage_identique": false,
"usage_non_commercial": false,
"composite": false,
"valide": false,
"valide_par": null,
"valide_le": null,
"note_validation": null
},
{
"id": "hippomane-mancinella-jacquin",
"filiere": "A",
"type_media": "planche_botanique",
"vue": null,
"usages": [],
"source": "wikimedia_commons",
"auteur": "Nicolás Joseph Jacquin",
"licence": "PD",
"licence_url": null,
"url_fichier": "https://upload.wikimedia.org/wikipedia/commons/6/6d/Hippomane_mancinella-Jacquin.jpeg",
"url_description": "https://commons.wikimedia.org/wiki/File:Hippomane_mancinella-Jacquin.jpeg",
"largeur": 500,
"hauteur": 753,
"mime": "image/jpeg",
"description": "Hippomane mancinella",
"date_prise_de_vue": "1780",
"attribution_requise": false,
"partage_identique": false,
"usage_non_commercial": false,
"composite": false,
"valide": false,
"valide_par": null,
"valide_le": null,
"note_validation": null
}
],
"audio": {
"gcf": null,
"locuteur": null
},
"sources_factuelles": [],
"valide": false
}
+127
View File
@@ -0,0 +1,127 @@
{
"$schema": "../../../../fruits.schema.json",
"id": "medisinye",
"categorie": "plante_dangereuse",
"noms": {
"gcf": "medsinyé",
"fr": "médicinier",
"en": "physic nut",
"es": "piñón"
},
"orthographe": {
"norme": "gwadloupeyen",
"statut": "a_relire",
"relu_par": null
},
"taxon": {
"scientifique": "Jatropha curcas",
"famille": "Euphorbiaceae",
"wikidata": "Q74644",
"gbif": 3072953,
"verifie_le": "2026-07-27",
"verifie_contre": [
"wikidata",
"gbif"
]
},
"iles": [
"gp",
"mq",
"gf"
],
"comestible": false,
"danger": {
"niveau": "eleve",
"resume": "Graines toxiques — cause fréquente d'intoxication chez l'enfant aux Antilles. Quelques graines suffisent."
},
"indices": {
"fruit": "capsule verte devenant jaune puis noire, 2 à 3 graines brun foncé",
"usage_haie": "souvent planté en haie vive, donc à portée d'enfant"
},
"medias": [
{
"id": "jatropha-curcas-blanco2-384",
"filiere": "A",
"type_media": "planche_botanique",
"vue": null,
"usages": [],
"source": "wikimedia_commons",
"auteur": "Francisco Manuel Blanco (O.S.A.)",
"licence": "PD",
"licence_url": null,
"url_fichier": "https://upload.wikimedia.org/wikipedia/commons/5/5d/Jatropha_curcas_Blanco2.384.jpg",
"url_description": "https://commons.wikimedia.org/wiki/File:Jatropha_curcas_Blanco2.384.jpg",
"largeur": 1411,
"hauteur": 2061,
"mime": "image/jpeg",
"description": "Jatropha curcas Plate from book",
"date_prise_de_vue": "between 1880 and 1883 date QS:P,+1880-00-00T00:00:00Z/8,P1319,+1880-00-00T00:00:00Z/9,P1326,+1883-00-00T00:00:00Z/9",
"attribution_requise": false,
"partage_identique": false,
"usage_non_commercial": false,
"composite": false,
"valide": false,
"valide_par": null,
"valide_le": null,
"note_validation": null
},
{
"id": "jatropha-curcas-blanco2-384-cropped",
"filiere": "A",
"type_media": "planche_botanique",
"vue": null,
"usages": [],
"source": "wikimedia_commons",
"auteur": "Francisco Manuel Blanco (O.S.A.)",
"licence": "PD",
"licence_url": null,
"url_fichier": "https://upload.wikimedia.org/wikipedia/commons/3/35/Jatropha_curcas_Blanco2.384-cropped.jpg",
"url_description": "https://commons.wikimedia.org/wiki/File:Jatropha_curcas_Blanco2.384-cropped.jpg",
"largeur": 1300,
"hauteur": 1870,
"mime": "image/jpeg",
"description": "Jatropha curcas Plate from book",
"date_prise_de_vue": "between 1880 and 1883 date QS:P,+1880-00-00T00:00:00Z/8,P1319,+1880-00-00T00:00:00Z/9,P1326,+1883-00-00T00:00:00Z/9",
"attribution_requise": false,
"partage_identique": false,
"usage_non_commercial": false,
"composite": false,
"valide": false,
"valide_par": null,
"valide_le": null,
"note_validation": null
},
{
"id": "georg-forster-purgiernuss",
"filiere": "A",
"type_media": "photo",
"vue": null,
"usages": [],
"source": "wikimedia_commons",
"auteur": "Georg Forster",
"licence": "PD",
"licence_url": null,
"url_fichier": "https://upload.wikimedia.org/wikipedia/commons/7/73/Georg_Forster_-_Purgiernuss.jpeg",
"url_description": "https://commons.wikimedia.org/wiki/File:Georg_Forster_-_Purgiernuss.jpeg",
"largeur": 1836,
"hauteur": 2658,
"mime": "image/jpeg",
"description": null,
"date_prise_de_vue": null,
"attribution_requise": false,
"partage_identique": false,
"usage_non_commercial": false,
"composite": false,
"valide": false,
"valide_par": null,
"valide_le": null,
"note_validation": null
}
],
"audio": {
"gcf": null,
"locuteur": null
},
"sources_factuelles": [],
"valide": false
}
+134
View File
@@ -0,0 +1,134 @@
{
"$schema": "../../../../fruits.schema.json",
"id": "pom-dlo",
"categorie": "fruit",
"noms": {
"gcf": "pòm-dlo",
"fr": "pomme d'eau",
"en": "water apple",
"es": "manzana de agua"
},
"orthographe": {
"norme": "gwadloupeyen",
"statut": "a_relire",
"relu_par": null
},
"taxon": {
"scientifique": "Syzygium samarangense",
"famille": "Myrtaceae",
"wikidata": "Q11643111",
"gbif": 3183180,
"verifie_le": "2026-07-27",
"verifie_contre": [
"wikidata",
"gbif"
]
},
"iles": [
"gp",
"mq",
"gf",
"re"
],
"saison_mois": [
4,
5,
6,
7
],
"comestible": true,
"danger": null,
"indices": {
"feuille": "opposée, grande, coriace, sessile ou presque",
"ecorce": "brun clair, s'écaillant",
"port": "arbre 515 m",
"coupe": "chair blanche très aqueuse, cavité centrale creuse"
},
"medias": [
{
"id": "champanga-flower-buds",
"filiere": "A",
"type_media": "photo",
"vue": null,
"usages": [],
"source": "wikimedia_commons",
"auteur": "Vinayaraj",
"licence": "CC-BY-SA-3.0",
"licence_url": "https://creativecommons.org/licenses/by-sa/3.0",
"url_fichier": "https://upload.wikimedia.org/wikipedia/commons/2/2c/Champanga_flower_buds.jpg",
"url_description": "https://commons.wikimedia.org/wiki/File:Champanga_flower_buds.jpg",
"largeur": 2073,
"hauteur": 1590,
"mime": "image/jpeg",
"description": "Champanga flower buds",
"date_prise_de_vue": "2005-04-19",
"attribution_requise": true,
"partage_identique": true,
"usage_non_commercial": false,
"composite": false,
"valide": false,
"valide_par": null,
"valide_le": null,
"note_validation": null
},
{
"id": "lainwu-wax-apple-diamond-p00063",
"filiere": "A",
"type_media": "photo",
"vue": null,
"usages": [],
"source": "wikimedia_commons",
"auteur": "Taiwan7007",
"licence": "CC-BY-3.0",
"licence_url": "https://creativecommons.org/licenses/by/3.0",
"url_fichier": "https://upload.wikimedia.org/wikipedia/commons/3/39/Lainwu_%28Wax_apple%29_diamond_P00063.JPG",
"url_description": "https://commons.wikimedia.org/wiki/File:Lainwu_(Wax_apple)_diamond_P00063.JPG",
"largeur": 308,
"hauteur": 330,
"mime": "image/jpeg",
"description": "Black pearl wax apples. Photo by Yu Jen, Su.",
"date_prise_de_vue": "2005-07-08",
"attribution_requise": true,
"partage_identique": false,
"usage_non_commercial": false,
"composite": false,
"valide": false,
"valide_par": null,
"valide_le": null,
"note_validation": null
},
{
"id": "9956kfsyzygium-samarangense-pampangafvf-05",
"filiere": "A",
"type_media": "photo",
"vue": null,
"usages": [],
"source": "wikimedia_commons",
"auteur": "Judgefloro",
"licence": "CC-BY-SA-4.0",
"licence_url": "https://creativecommons.org/licenses/by-sa/4.0",
"url_fichier": "https://upload.wikimedia.org/wikipedia/commons/e/ed/9956kfSyzygium_samarangense_Pampangafvf_05.JPG",
"url_description": "https://commons.wikimedia.org/wiki/File:9956kfSyzygium_samarangense_Pampangafvf_05.JPG",
"largeur": 4608,
"hauteur": 3456,
"mime": "image/jpeg",
"description": "Syzygium samarangense in Barangay Santo Niño , San Fernando, Pampanga - San Fernando Subdivision Santo Niño .",
"date_prise_de_vue": "2015-04-22 14:33:45",
"attribution_requise": true,
"partage_identique": true,
"usage_non_commercial": false,
"composite": false,
"valide": false,
"valide_par": null,
"valide_le": null,
"note_validation": null
}
],
"audio": {
"gcf": null,
"locuteur": null
},
"sources_factuelles": [],
"valide": false,
"$comment": "ATTENTION : « pòm-dlo », « pòm-malaka » et « pòm-rose » désignent des Syzygium DIFFÉRENTS selon les îles (S. samarangense, S. malaccense, S. jambos). Point de confusion classique — à trancher explicitement avant publication."
}
+126
View File
@@ -0,0 +1,126 @@
{
"$schema": "../../../../fruits.schema.json",
"id": "pom-kajou",
"categorie": "plante_dangereuse",
"noms": {
"gcf": "pòm-kajou",
"fr": "pomme-cajou",
"en": "cashew apple",
"es": "marañón"
},
"orthographe": {
"norme": "gwadloupeyen",
"statut": "a_relire",
"relu_par": null
},
"taxon": {
"scientifique": "Anacardium occidentale",
"famille": "Anacardiaceae",
"wikidata": "Q34007",
"gbif": 5421368,
"verifie_le": "2026-07-27",
"verifie_contre": [
"wikidata",
"gbif"
]
},
"iles": [
"gp",
"mq",
"gf"
],
"comestible": false,
"danger": {
"niveau": "eleve",
"resume": "La pomme se mange. La coque de la noix contient un liquide caustique qui brûle la peau et les muqueuses. Ne jamais ouvrir ni mordre la noix crue."
},
"indices": {
"fruit": "pomme charnue jaune ou rouge surmontée d'une noix recourbée grise"
},
"medias": [
{
"id": "anacardium-occidentale-kohler-s-medizinal-pflanzen-010",
"filiere": "A",
"type_media": "planche_botanique",
"vue": null,
"usages": [],
"source": "wikimedia_commons",
"auteur": "Franz Eugen Köhler, Köhler's Medizinal-Pflanzen",
"licence": "PD",
"licence_url": null,
"url_fichier": "https://upload.wikimedia.org/wikipedia/commons/0/0e/Anacardium_occidentale_-_K%C3%B6hler%E2%80%93s_Medizinal-Pflanzen-010.jpg",
"url_description": "https://commons.wikimedia.org/wiki/File:Anacardium_occidentale_-_K%C3%B6hler%E2%80%93s_Medizinal-Pflanzen-010.jpg",
"largeur": 425,
"hauteur": 589,
"mime": "image/jpeg",
"description": "Kaschu. A Blühende Pflanze. 1 Blüte vergrössert ; 2 Stempel und Staubgefässe; 3 Dasselbe im Längsschnitt; 4 Frucht mit dem vergrösserten und reifen Fruchtstiel; 5 Frucht im Längsschnitt; 6 Frucht im Querschnitt.",
"date_prise_de_vue": "1897",
"attribution_requise": false,
"partage_identique": false,
"usage_non_commercial": false,
"composite": false,
"valide": false,
"valide_par": null,
"valide_le": null,
"note_validation": null
},
{
"id": "cashew2-flower",
"filiere": "A",
"type_media": "photo",
"vue": null,
"usages": [],
"source": "wikimedia_commons",
"auteur": "Aruna at Malayalam Wikipedia",
"licence": "CC-BY-SA-3.0",
"licence_url": "http://creativecommons.org/licenses/by-sa/3.0/",
"url_fichier": "https://upload.wikimedia.org/wikipedia/commons/b/bf/Cashew2-flower.JPG",
"url_description": "https://commons.wikimedia.org/wiki/File:Cashew2-flower.JPG",
"largeur": 1024,
"hauteur": 768,
"mime": "image/jpeg",
"description": "Cashew flower",
"date_prise_de_vue": "2007-12-07",
"attribution_requise": true,
"partage_identique": true,
"usage_non_commercial": false,
"composite": false,
"valide": false,
"valide_par": null,
"valide_le": null,
"note_validation": null
},
{
"id": "cashew-apples",
"filiere": "A",
"type_media": "photo",
"vue": null,
"usages": [],
"source": "wikimedia_commons",
"auteur": "Abhishek Jacob",
"licence": "CC-BY-SA-3.0",
"licence_url": "https://creativecommons.org/licenses/by-sa/3.0",
"url_fichier": "https://upload.wikimedia.org/wikipedia/commons/6/64/Cashew_apples.jpg",
"url_description": "https://commons.wikimedia.org/wiki/File:Cashew_apples.jpg",
"largeur": 2534,
"hauteur": 1982,
"mime": "image/jpeg",
"description": "Ripe cashew apples",
"date_prise_de_vue": "2009-04-14",
"attribution_requise": true,
"partage_identique": true,
"usage_non_commercial": false,
"composite": false,
"valide": false,
"valide_par": null,
"valide_le": null,
"note_validation": null
}
],
"audio": {
"gcf": null,
"locuteur": null
},
"sources_factuelles": [],
"valide": false
}
+134
View File
@@ -0,0 +1,134 @@
{
"$schema": "../../../../fruits.schema.json",
"id": "pom-kannel",
"categorie": "fruit",
"noms": {
"gcf": "pòm-kannèl",
"fr": "pomme-cannelle",
"en": "sugar apple",
"es": "anón"
},
"orthographe": {
"norme": "gwadloupeyen",
"statut": "a_relire",
"relu_par": null
},
"taxon": {
"scientifique": "Annona squamosa",
"famille": "Annonaceae",
"wikidata": "Q275620",
"gbif": 5407099,
"verifie_le": "2026-07-27",
"verifie_contre": [
"wikidata",
"gbif"
]
},
"iles": [
"gp",
"mq"
],
"saison_mois": [
8,
9,
10,
11
],
"comestible": true,
"danger": {
"niveau": "vigilance",
"resume": "graines des Annona non comestibles — ne jamais croquer."
},
"indices": {
"feuille": "alterne, oblongue, plus fine et plus claire que le corossol",
"ecorce": "grise, rameaux zigzagants",
"port": "petit arbre 36 m",
"coupe": "chair blanche en segments détachables, graines noires"
},
"medias": [
{
"id": "annona-squamosa-custurd-apple-plant-in-hyderabad-ap-w-img-93",
"filiere": "A",
"type_media": "photo",
"vue": null,
"usages": [],
"source": "wikimedia_commons",
"auteur": "J.M.Garg",
"licence": "CC-BY-SA-4.0",
"licence_url": "https://creativecommons.org/licenses/by-sa/4.0",
"url_fichier": "https://upload.wikimedia.org/wikipedia/commons/5/5a/Annona_squamosa_%28Custurd_Apple%29_plant_in_Hyderabad%2C_AP_W_IMG_9354.jpg",
"url_description": "https://commons.wikimedia.org/wiki/File:Annona_squamosa_(Custurd_Apple)_plant_in_Hyderabad,_AP_W_IMG_9354.jpg",
"largeur": 800,
"hauteur": 533,
"mime": "image/jpeg",
"description": "Custard-apple, sugar-apple, sweetsop, sitaphal or Sita's fruit, shareefah, aataa or Rahmapfel Annona squamosa in Hyderabad , India .",
"date_prise_de_vue": "2008-09-13",
"attribution_requise": true,
"partage_identique": true,
"usage_non_commercial": false,
"composite": false,
"valide": false,
"valide_par": null,
"valide_le": null,
"note_validation": null
},
{
"id": "annona-squamosa-fruits-leaves",
"filiere": "A",
"type_media": "photo",
"vue": null,
"usages": [],
"source": "wikimedia_commons",
"auteur": "Jim Conrad",
"licence": "PD",
"licence_url": null,
"url_fichier": "https://upload.wikimedia.org/wikipedia/commons/8/8d/Annona_squamosa-fruits-leaves.jpg",
"url_description": "https://commons.wikimedia.org/wiki/File:Annona_squamosa-fruits-leaves.jpg",
"largeur": 650,
"hauteur": 419,
"mime": "image/jpeg",
"description": "The syncarpous fruits of an Annona squamosa tree growing near Sabacché, Yucatán, MÉXICO.",
"date_prise_de_vue": "2008-08-18",
"attribution_requise": false,
"partage_identique": false,
"usage_non_commercial": false,
"composite": false,
"valide": false,
"valide_par": null,
"valide_le": null,
"note_validation": null
},
{
"id": "sharifa",
"filiere": "A",
"type_media": "photo",
"vue": null,
"usages": [],
"source": "wikimedia_commons",
"auteur": "Miansari66",
"licence": "CC0-1.0",
"licence_url": "http://creativecommons.org/publicdomain/zero/1.0/deed.en",
"url_fichier": "https://upload.wikimedia.org/wikipedia/commons/4/47/Sharifa.JPG",
"url_description": "https://commons.wikimedia.org/wiki/File:Sharifa.JPG",
"largeur": 2816,
"hauteur": 2112,
"mime": "image/jpeg",
"description": "Sharifa in urdu, Custard apple in english",
"date_prise_de_vue": null,
"attribution_requise": false,
"partage_identique": false,
"usage_non_commercial": false,
"composite": false,
"valide": false,
"valide_par": null,
"valide_le": null,
"note_validation": null
}
],
"audio": {
"gcf": null,
"locuteur": null
},
"sources_factuelles": [],
"valide": false
}
+133
View File
@@ -0,0 +1,133 @@
{
"$schema": "../../../../fruits.schema.json",
"id": "pom-site",
"categorie": "fruit",
"noms": {
"gcf": "pòm-sitè",
"fr": "prune de Cythère",
"en": "ambarella",
"es": "jobo indio"
},
"orthographe": {
"norme": "gwadloupeyen",
"statut": "a_relire",
"relu_par": null
},
"taxon": {
"scientifique": "Spondias dulcis",
"famille": "Anacardiaceae",
"wikidata": "Q500383",
"gbif": 3190595,
"verifie_le": "2026-07-27",
"verifie_contre": [
"wikidata",
"gbif"
]
},
"iles": [
"gp",
"mq",
"gf"
],
"saison_mois": [
11,
12,
1,
2,
3
],
"comestible": true,
"danger": null,
"indices": {
"feuille": "composée imparipennée, folioles nombreuses, caduque en saison sèche",
"ecorce": "grise, lenticelles visibles",
"port": "arbre 815 m, branches cassantes",
"coupe": "chair jaune croquante, noyau fibreux épineux caractéristique"
},
"medias": [
{
"id": "spondia-dulcis-blanco1-132",
"filiere": "A",
"type_media": "planche_botanique",
"vue": null,
"usages": [],
"source": "wikimedia_commons",
"auteur": "Francisco Manuel Blanco (O.S.A.)",
"licence": "PD",
"licence_url": null,
"url_fichier": "https://upload.wikimedia.org/wikipedia/commons/3/3a/Spondia_dulcis_Blanco1.132.png",
"url_description": "https://commons.wikimedia.org/wiki/File:Spondia_dulcis_Blanco1.132.png",
"largeur": 1417,
"hauteur": 2107,
"mime": "image/png",
"description": "Plate from book",
"date_prise_de_vue": "1880-1883?",
"attribution_requise": false,
"partage_identique": false,
"usage_non_commercial": false,
"composite": false,
"valide": false,
"valide_par": null,
"valide_le": null,
"note_validation": null
},
{
"id": "spondia-dulcis-blanco1-132-cropped",
"filiere": "A",
"type_media": "planche_botanique",
"vue": null,
"usages": [],
"source": "wikimedia_commons",
"auteur": "Francisco Manuel Blanco (O.S.A.)",
"licence": "PD",
"licence_url": null,
"url_fichier": "https://upload.wikimedia.org/wikipedia/commons/3/38/Spondia_dulcis_Blanco1.132-cropped.jpg",
"url_description": "https://commons.wikimedia.org/wiki/File:Spondia_dulcis_Blanco1.132-cropped.jpg",
"largeur": 1270,
"hauteur": 1770,
"mime": "image/jpeg",
"description": "Plate from book",
"date_prise_de_vue": "1880-1883?",
"attribution_requise": false,
"partage_identique": false,
"usage_non_commercial": false,
"composite": false,
"valide": false,
"valide_par": null,
"valide_le": null,
"note_validation": null
},
{
"id": "spondia-dulcis-blanco1-132-2",
"filiere": "A",
"type_media": "planche_botanique",
"vue": null,
"usages": [],
"source": "wikimedia_commons",
"auteur": "Francisco Manuel Blanco (O.S.A.)",
"licence": "PD",
"licence_url": null,
"url_fichier": "https://upload.wikimedia.org/wikipedia/commons/2/22/Spondia_dulcis_Blanco1.132.jpg",
"url_description": "https://commons.wikimedia.org/wiki/File:Spondia_dulcis_Blanco1.132.jpg",
"largeur": 1417,
"hauteur": 2107,
"mime": "image/jpeg",
"description": "Plate from book",
"date_prise_de_vue": "1880-1883?",
"attribution_requise": false,
"partage_identique": false,
"usage_non_commercial": false,
"composite": false,
"valide": false,
"valide_par": null,
"valide_le": null,
"note_validation": null
}
],
"audio": {
"gcf": null,
"locuteur": null
},
"sources_factuelles": [],
"valide": false
}
+132
View File
@@ -0,0 +1,132 @@
{
"$schema": "../../../../fruits.schema.json",
"id": "zikak",
"categorie": "fruit",
"noms": {
"gcf": "zikak",
"fr": "icaque",
"en": "cocoplum",
"es": "icaco"
},
"orthographe": {
"norme": "gwadloupeyen",
"statut": "a_relire",
"relu_par": null
},
"taxon": {
"scientifique": "Chrysobalanus icaco",
"famille": "Chrysobalanaceae",
"wikidata": "Q577669",
"gbif": 2985082,
"verifie_le": "2026-07-27",
"verifie_contre": [
"wikidata",
"gbif"
]
},
"iles": [
"gp",
"mq",
"gf"
],
"saison_mois": [
8,
9,
10,
11
],
"comestible": true,
"danger": null,
"indices": {
"feuille": "petite, arrondie, coriace, vert brillant — plante de bord de mer",
"ecorce": "brun-gris, arbuste buissonnant",
"port": "arbuste 13 m, littoral et arrière-plage",
"coupe": "chair blanche cotonneuse peu juteuse, gros noyau côtelé"
},
"medias": [
{
"id": "starr-031108-2161-chrysobalanus-icaco",
"filiere": "A",
"type_media": "photo",
"vue": null,
"usages": [],
"source": "wikimedia_commons",
"auteur": "Forest &amp; Kim Starr",
"licence": "CC-BY-3.0",
"licence_url": "https://creativecommons.org/licenses/by/3.0",
"url_fichier": "https://upload.wikimedia.org/wikipedia/commons/d/de/Starr_031108-2161_Chrysobalanus_icaco.jpg",
"url_description": "https://commons.wikimedia.org/wiki/File:Starr_031108-2161_Chrysobalanus_icaco.jpg",
"largeur": 1632,
"hauteur": 1224,
"mime": "image/jpeg",
"description": "Chrysobalanus icaco (flowers). Location: Florida, Long Key",
"date_prise_de_vue": "2003-11-08",
"attribution_requise": true,
"partage_identique": false,
"usage_non_commercial": false,
"composite": false,
"valide": false,
"valide_par": null,
"valide_le": null,
"note_validation": null
},
{
"id": "chrysobalanus-icaco-inflorescense",
"filiere": "A",
"type_media": "photo",
"vue": null,
"usages": [],
"source": "wikimedia_commons",
"auteur": "Hans Hillewaert",
"licence": "CC-BY-SA-3.0",
"licence_url": "https://creativecommons.org/licenses/by-sa/3.0",
"url_fichier": "https://upload.wikimedia.org/wikipedia/commons/3/3e/Chrysobalanus_icaco_%28inflorescense%29.jpg",
"url_description": "https://commons.wikimedia.org/wiki/File:Chrysobalanus_icaco_(inflorescense).jpg",
"largeur": 2473,
"hauteur": 3297,
"mime": "image/jpeg",
"description": "Cocoplum near Cahuita, Costa Rica",
"date_prise_de_vue": "2009-08-16",
"attribution_requise": true,
"partage_identique": true,
"usage_non_commercial": false,
"composite": false,
"valide": false,
"valide_par": null,
"valide_le": null,
"note_validation": null
},
{
"id": "flore-medicale-des-antilles-ou-traite-des-plantes-usuelles-p",
"filiere": "A",
"type_media": "planche_botanique",
"vue": null,
"usages": [],
"source": "wikimedia_commons",
"auteur": "Descourtilz, J. Theodore.; Descourtilz, M. E.; Pichard.",
"licence": "PD",
"licence_url": null,
"url_fichier": "https://upload.wikimedia.org/wikipedia/commons/e/e3/Flore_m%C3%A9dicale_des_Antilles%2C_ou%2C_Trait%C3%A9_des_plantes_usuelles_%28Pl._84%29_%288201963925%29.jpg",
"url_description": "https://commons.wikimedia.org/wiki/File:Flore_m%C3%A9dicale_des_Antilles,_ou,_Trait%C3%A9_des_plantes_usuelles_(Pl._84)_(8201963925).jpg",
"largeur": 1567,
"hauteur": 2592,
"mime": "image/jpeg",
"description": "li. 84- T 4 mt6k i /Wvw^mV^^ /W lA-Mrr*' ^ îCAOriKH I.'AMKR101^K.",
"date_prise_de_vue": "1822",
"attribution_requise": false,
"partage_identique": false,
"usage_non_commercial": false,
"composite": false,
"valide": false,
"valide_par": null,
"valide_le": null,
"note_validation": null
}
],
"audio": {
"gcf": null,
"locuteur": null
},
"sources_factuelles": [],
"valide": false
}
+131
View File
@@ -0,0 +1,131 @@
#!/usr/bin/env node
/**
* build-credits.mjs — génère CREDITS.md depuis les données.
*
* Le brief §3 exige un CREDITS.md « généré depuis les données ». Un fichier de crédits
* tenu à la main se désynchronise le jour où l'on remplace une photo, et une attribution
* fausse est une violation de licence. Ce fichier n'est donc jamais édité : il se rejoue.
*
* Les médias sous clause non commerciale sont isolés dans leur propre section, comme
* l'ADR 0001 l'impose.
*/
import { readFile, readdir, writeFile } from 'node:fs/promises';
import { fileURLToPath } from 'node:url';
import { dirname, join } from 'node:path';
const ROOT = join(dirname(fileURLToPath(import.meta.url)), '..', '..');
const DATA = join(ROOT, 'src', 'lib', 'data', 'fruits');
const LIBELLE = {
'CC0-1.0': 'CC0 1.0 (domaine public volontaire)',
PD: 'domaine public',
'CC-BY-2.0': 'CC BY 2.0',
'CC-BY-3.0': 'CC BY 3.0',
'CC-BY-4.0': 'CC BY 4.0',
'CC-BY-SA-2.0': 'CC BY-SA 2.0',
'CC-BY-SA-2.5': 'CC BY-SA 2.5',
'CC-BY-SA-3.0': 'CC BY-SA 3.0',
'CC-BY-SA-4.0': 'CC BY-SA 4.0',
'CC-BY-NC-4.0': 'CC BY-NC 4.0',
'CC-BY-NC-SA-4.0': 'CC BY-NC-SA 4.0',
'OKI-CC-BY-SA-4.0': 'ORGANISATION KA INTERNATIONALE, CC BY-SA 4.0'
};
const echapper = (s) => String(s ?? '—').replace(/\|/g, '\\|').replace(/\n/g, ' ');
async function main() {
const fichiers = (await readdir(DATA)).filter((f) => f.endsWith('.json')).sort();
const entrees = [];
for (const f of fichiers) entrees.push(JSON.parse(await readFile(join(DATA, f), 'utf8')));
const tous = entrees.flatMap((e) => e.medias.map((m) => ({ ...m, entree: e })));
const nc = tous.filter((m) => m.usage_non_commercial);
const sa = tous.filter((m) => m.partage_identique);
const l = [
'# Crédits — KI FWI SA YÉ ?',
'',
'> **Fichier généré.** Ne pas éditer à la main : `npm run build:credits`.',
`> Dernière génération : ${new Date().toISOString().slice(0, 10)}.`,
'',
'## Ce que couvre ce fichier',
'',
'Chaque média embarqué dans le jeu ou dans lencyclopédie est listé ci-dessous avec son',
'auteur, sa licence et le lien vers sa page de description dorigine. Rien nest',
'« libre de droit » : chaque ligne est une obligation contractuelle.',
'',
'Le code du projet est sous **AGPL-3.0-or-later** (`LICENSE`). Les textes rédigés par',
'ORGANISATION KA INTERNATIONALE sont sous **CC BY-SA 4.0** (`LICENSE-CONTENT`). Les médias',
'tiers restent sous leur licence propre : le jeu est une **œuvre collective**, pas une',
'œuvre dérivée — voir `docs/adr/0001-licences.md`.',
'',
`## Chiffres`,
'',
`- ${entrees.length} entrées · ${tous.length} médias`,
`- ${tous.filter((m) => m.valide).length} médias validés par un humain`,
`- ${sa.length} médias en partage à lidentique (CC BY-SA) — **aucun compositing autorisé**`,
`- ${nc.length} médias sous clause non commerciale (CC BY-NC)`,
''
];
if (nc.length) {
l.push(
'## ⚠ Médias sous clause non commerciale',
'',
'La présence de ces médias engage le projet à ne **jamais** être distribué à titre',
'commercial — ni vente, ni version payante, ni licence à un éditeur. Décision prise et',
'documentée dans `docs/adr/0001-licences.md`. Retirer ces médias est la seule façon de',
'revenir en arrière.',
'',
'| entrée | média | auteur | licence | source |',
'|---|---|---|---|---|'
);
for (const m of nc)
l.push(
`| \`${m.entree.id}\` | ${echapper(m.id)} | ${echapper(m.auteur)} | ${LIBELLE[m.licence] ?? m.licence} | [page](${m.url_description}) |`
);
l.push('');
}
l.push('## Médias par entrée', '');
for (const e of entrees) {
l.push(`### ${e.noms.gcf} — *${e.taxon.scientifique}* (\`${e.id}\`)`, '');
l.push(
`Taxonomie vérifiée le ${e.taxon.verifie_le} contre [Wikidata ${e.taxon.wikidata}](https://www.wikidata.org/wiki/${e.taxon.wikidata})`,
`et [GBIF ${e.taxon.gbif}](https://www.gbif.org/species/${e.taxon.gbif}).`,
''
);
if (!e.medias.length) {
l.push('_Aucun média._', '');
continue;
}
l.push('| média | vue | auteur | licence | validé | page dorigine |');
l.push('|---|---|---|---|---|---|');
for (const m of e.medias)
l.push(
`| ${echapper(m.id)} | ${m.vue ?? '—'} | ${echapper(m.auteur)} | ${LIBELLE[m.licence] ?? m.licence} | ${m.valide ? `oui (${echapper(m.valide_par)})` : 'non'} | [voir](${m.url_description}) |`
);
l.push('');
}
l.push(
'## Sources factuelles',
'',
'- **Wikidata** — identifiants et taxonomie (CC0). https://www.wikidata.org',
'- **GBIF** — noms scientifiques acceptés et clés dusage. https://www.gbif.org',
'- **Wikimedia Commons** — photographies. https://commons.wikimedia.org',
'',
'Voir `SOURCES.md` pour le détail des régimes de licence et `docs/audit-sources.md`',
'pour laudit complet, TRAMIL et CIRAD compris.',
''
);
await writeFile(join(ROOT, 'CREDITS.md'), l.join('\n'));
console.log(`✔ CREDITS.md — ${entrees.length} entrées, ${tous.length} médias, ${nc.length} sous clause NC.`);
}
main().catch((e) => {
console.error('✘', e.stack ?? e.message);
process.exit(1);
});
+200
View File
@@ -0,0 +1,200 @@
#!/usr/bin/env node
/**
* build-dataset.mjs — compose le dataset à partir de la graine et des sorties vérifiées.
*
* fruits.seed.json (contenu éditorial d'amorçage)
* + tools/data/out/taxa-verified.json (Wikidata + GBIF, réponses d'API)
* + tools/data/out/commons-candidats.json (médias sous licence libre)
* → src/lib/data/fruits/<id>.json
*
* AMORÇAGE SEUL. Une fois les fichiers écrits, ils sont édités à la main par le porteur
* (choix des photos, assignation des vues, passage de `valide` à true, corrections kréyòl).
* Le script refuse donc d'écraser un fichier existant sans `--force`, pour ne jamais
* détruire une validation humaine.
*/
import { readFile, writeFile, mkdir, access } from 'node:fs/promises';
import { fileURLToPath } from 'node:url';
import { dirname, join } from 'node:path';
const ROOT = join(dirname(fileURLToPath(import.meta.url)), '..', '..');
const DEST = join(ROOT, 'src', 'lib', 'data', 'fruits');
const FORCE = process.argv.includes('--force');
/** Nombre de médias candidats pré-inscrits par entrée. Le brief §8 en exige au moins deux. */
const MEDIAS_PAR_ENTREE = 3;
/** Licences à attribution — recopié de la classification d'ingest-commons.mjs. */
const SANS_ATTRIBUTION = new Set(['CC0-1.0', 'PD']);
const AVEC_SA = new Set(['CC-BY-SA-2.0', 'CC-BY-SA-2.5', 'CC-BY-SA-3.0', 'CC-BY-SA-4.0', 'CC-BY-NC-SA-4.0']);
const AVEC_NC = new Set(['CC-BY-NC-4.0', 'CC-BY-NC-SA-4.0']);
const slug = (s) =>
s
.replace(/^File:/, '')
.replace(/\.[a-z0-9]+$/i, '')
.normalize('NFD')
.replace(/[\u0300-\u036f]/g, '')
.toLowerCase()
.replace(/[^a-z0-9]+/g, '-')
.replace(/^-+|-+$/g, '')
.slice(0, 60)
.replace(/-+$/, '');
/**
* Une planche gravée du XVIIIe siècle est exacte mais stylisée : elle ne peut pas servir
* d'épreuve de reconnaissance du réel. On la détecte grossièrement — c'est un pré-tri,
* pas un verdict : le porteur corrige le champ à la relecture.
*/
const INDICES_PLANCHE = /blanco|merian|k[oö]hler|flora|sylva|botanical|plate|lithograph|engrav|descourtilz|1[6-9]\d\d/i;
function typeMedia(c) {
// La date de prise de vue fait partie du texte examiné : sans elle, la planche de
// Jacquin (1780) ressortait en « photo » — son titre et son auteur ne disent rien
// de son siècle. Constaté en session 0, corrigé ici.
const hay = `${c.titre} ${c.description ?? ''} ${c.auteur ?? ''} ${c.date_prise_de_vue ?? ''}`;
if (INDICES_PLANCHE.test(hay)) return 'planche_botanique';
// La photographie de terrain n'existe pas avant le XXe siècle dans ces fonds.
const annee = Number((c.date_prise_de_vue ?? '').match(/\b(1[5-9]\d\d)\b/)?.[1]);
if (annee && annee < 1900) return 'planche_botanique';
return 'photo';
}
/**
* Écart constaté dans la graine : les dangers de niveau « vigilance » (kénèt, pòm-kannèl)
* portent leur texte dans `note`, les niveaux « élevé » et « critique » dans `resume`.
* Le schéma impose un champ unique — on normalise vers `resume` sans rien réécrire.
* Écart signalé dans docs/sessions/00-cadre-et-donnees.md, conformément au brief §9.
*/
function normaliserDanger(d) {
if (!d) return null;
const { note, resume, ...reste } = d;
return { ...reste, resume: resume ?? note };
}
/** Deux planches Blanco tronquées au même slug : on désambiguïse plutôt que de perdre un média. */
function idsUniques(medias) {
const vus = new Map();
return medias.map((m) => {
const n = (vus.get(m.id) ?? 0) + 1;
vus.set(m.id, n);
return n === 1 ? m : { ...m, id: `${m.id}-${n}` };
});
}
async function existe(p) {
try {
await access(p);
return true;
} catch {
return false;
}
}
async function main() {
const seed = JSON.parse(await readFile(join(ROOT, 'fruits.seed.json'), 'utf8'));
const taxa = JSON.parse(await readFile(join(ROOT, 'tools/data/out/taxa-verified.json'), 'utf8'));
const medias = JSON.parse(await readFile(join(ROOT, 'tools/data/out/commons-candidats.json'), 'utf8'));
const parId = (arr) => new Map(arr.map((r) => [r.id, r]));
const T = parId(taxa.resultats);
const M = parId(medias.resultats);
const dateVerif = taxa.genere_le.slice(0, 10);
const entrees = [
...seed.fruits.map((f) => ({ ...f, categorie: 'fruit' })),
...seed.plantes_dangereuses.map((p) => ({ ...p, categorie: 'plante_dangereuse' }))
];
await mkdir(DEST, { recursive: true });
let ecrits = 0;
let ignores = 0;
for (const e of entrees) {
const chemin = join(DEST, `${e.id}.json`);
if (!FORCE && (await existe(chemin))) {
console.log(`· ${e.id} — existe déjà, conservé (--force pour écraser)`);
ignores++;
continue;
}
const t = T.get(e.id);
if (!t?.wikidata?.qid || !t?.gbif?.usageKey) {
console.error(`${e.id} — taxonomie non vérifiée, entrée non écrite`);
continue;
}
const candidats = idsUniques(
(M.get(e.id)?.candidats ?? []).slice(0, MEDIAS_PAR_ENTREE).map((c) => ({
id: slug(c.titre),
filiere: 'A',
type_media: typeMedia(c),
vue: null,
usages: [],
source: 'wikimedia_commons',
auteur: c.auteur,
licence: c.licence,
licence_url: c.licence_url ?? null,
url_fichier: c.url_fichier,
url_description: c.url_description,
largeur: c.largeur ?? null,
hauteur: c.hauteur ?? null,
mime: c.mime ?? null,
description: c.description ?? null,
date_prise_de_vue: c.date_prise_de_vue ?? null,
attribution_requise: !SANS_ATTRIBUTION.has(c.licence),
partage_identique: AVEC_SA.has(c.licence),
usage_non_commercial: AVEC_NC.has(c.licence),
composite: false,
valide: false,
valide_par: null,
valide_le: null,
note_validation: null
}))
);
const entree = {
$schema: '../../../../fruits.schema.json',
id: e.id,
categorie: e.categorie,
noms: e.noms,
orthographe: { norme: 'gwadloupeyen', statut: 'a_relire', relu_par: null },
taxon: {
scientifique: t.gbif.canonicalName ?? e.taxon.scientifique,
famille: t.gbif.famille ?? e.taxon.famille,
wikidata: t.wikidata.qid,
gbif: t.gbif.usageKey,
verifie_le: dateVerif,
verifie_contre: ['wikidata', 'gbif']
},
iles: e.iles,
...(e.categorie === 'fruit' ? { saison_mois: e.saison_mois } : {}),
// Les cinq plantes du module « Pa touché » sortent à comestible: false.
// C'est le défaut prudent, pas la vérité complète : l'akée mûre et la pomme-cajou
// se mangent sous conditions strictes. La nuance vit dans danger.resume et doit
// être arbitrée par un humain avant publication (voir docs/a-arbitrer.md).
comestible: e.categorie === 'fruit' ? (e.comestible ?? true) : false,
danger: normaliserDanger(e.danger),
indices: e.indices ?? {},
medias: candidats,
audio: { gcf: null, locuteur: null },
sources_factuelles: [],
valide: false
};
if (e.$comment) entree.$comment = e.$comment;
await writeFile(chemin, JSON.stringify(entree, null, '\t') + '\n');
console.log(`${e.id}${candidats.length} médias, ${entree.taxon.wikidata} / ${entree.taxon.gbif}`);
ecrits++;
}
console.log(`\n${ecrits} entrée(s) écrite(s), ${ignores} conservée(s).`);
}
main().catch((err) => {
console.error('✘', err.message);
process.exit(1);
});
+86
View File
@@ -0,0 +1,86 @@
#!/usr/bin/env node
/**
* check-audio.mjs — liste les enregistrements kréyòl manquants.
*
* Le brief §6 le demande explicitement : « prévois le contrat (audio.gcf, format .opus,
* repli silencieux si le fichier manque) et un script de vérification listant les
* enregistrements manquants. »
*
* Pas de synthèse vocale : ce script n'en fabrique aucune. Il produit une liste de courses
* pour la séance d'enregistrement — une après-midi de terrain vaut dix heures de code.
*
* Ce script n'échoue jamais : un enregistrement manquant est un travail à faire,
* pas un défaut de build. Le jeu doit se replier en silence.
*/
import { readFile, readdir, writeFile, access } from 'node:fs/promises';
import { fileURLToPath } from 'node:url';
import { dirname, join } from 'node:path';
const ROOT = join(dirname(fileURLToPath(import.meta.url)), '..', '..');
const DATA = join(ROOT, 'src', 'lib', 'data', 'fruits');
const STATIC = join(ROOT, 'static');
async function existe(p) {
try {
await access(p);
return true;
} catch {
return false;
}
}
async function main() {
const fichiers = (await readdir(DATA)).filter((f) => f.endsWith('.json')).sort();
const manquants = [];
const absents = [];
const presents = [];
for (const f of fichiers) {
const e = JSON.parse(await readFile(join(DATA, f), 'utf8'));
if (!e.audio.gcf) {
manquants.push(e);
continue;
}
// Le chemin est absolu depuis la racine du site : /audio/<id>.opus → static/audio/<id>.opus
if (await existe(join(STATIC, e.audio.gcf))) presents.push(e);
else absents.push(e);
}
const l = [
'# Enregistrements kréyòl à réaliser',
'',
'> Généré par `npm run check:audio`. Aucune synthèse vocale : ces noms doivent être',
'> prononcés par une voix humaine locale (brief §6).',
'',
"Format attendu : `.opus` — un fichier par entrée, déposé dans `static/audio/<id>.opus`.",
'',
`## À enregistrer (${manquants.length})`,
''
];
for (const e of manquants) l.push(`- [ ] **${e.noms.gcf}** — \`static/audio/${e.id}.opus\` _(${e.noms.fr ?? ''})_`);
l.push('');
if (absents.length) {
l.push(`## Déclarés mais fichier introuvable (${absents.length})`, '');
for (const e of absents) l.push(`- ⚠ \`${e.id}\`\`${e.audio.gcf}\` absent de \`static/\``);
l.push('');
}
if (presents.length) {
l.push(`## En place (${presents.length})`, '');
for (const e of presents) l.push(`- ✔ \`${e.id}\`${e.audio.locuteur ?? 'locuteur non renseigné'}`);
l.push('');
}
await writeFile(join(ROOT, 'docs', 'audio-a-enregistrer.md'), l.join('\n'));
console.log(`À enregistrer : ${manquants.length}`);
console.log(`Introuvables : ${absents.length}`);
console.log(`En place : ${presents.length}`);
console.log('\n docs/audio-a-enregistrer.md');
if (absents.length) console.log("\n⚠ Des chemins audio sont déclarés sans fichier : le jeu se repliera en silence.");
}
main().catch((e) => {
console.error('✘', e.stack ?? e.message);
process.exit(1);
});
+217
View File
@@ -0,0 +1,217 @@
#!/usr/bin/env node
/**
* ingest-commons.mjs — recherche de photographies candidates sur Wikimedia Commons.
*
* FILIÈRE A UNIQUEMENT (ADR 0004) : ce script ne produit que des photographies réelles,
* destinées aux épreuves d'identification. Aucun asset généré ne passe par ici.
*
* Ce que ce script fait : il interroge Commons, récupère pour chaque fichier l'auteur,
* la licence, l'URL du fichier et l'URL de sa page de description, et écarte tout ce
* dont la licence n'est pas explicitement libre.
*
* Ce que ce script NE fait PAS, et ne fera jamais :
* — il ne télécharge aucun fichier ;
* — il ne décide pas qu'une photo montre bien l'espèce annoncée. L'ordre des candidats
* est celui de la pertinence du moteur de recherche de Commons, ce qui n'est pas un
* jugement botanique. Tout candidat sort avec `valide: false` et le reste jusqu'à ce
* qu'un humain compétent tranche (brief §2, ADR 0004).
*
* Sorties :
* tools/data/out/commons-candidats.json — données brutes
* docs/planche-relecture-medias.md — planche de relecture pour le porteur
*/
import { readFile, writeFile, mkdir } from 'node:fs/promises';
import { fileURLToPath } from 'node:url';
import { dirname, join } from 'node:path';
const ROOT = join(dirname(fileURLToPath(import.meta.url)), '..', '..');
const UA = 'ki-fwi-dataset/0.1 (https://o-k-i.net ; projet educatif ORGANISATION KA INTERNATIONALE)';
const API = 'https://commons.wikimedia.org/w/api.php';
/** Nombre de candidats remontés par taxon. Le porteur en retiendra au moins deux. */
const CANDIDATS_PAR_TAXON = 10;
/**
* Licences acceptées, par préfixe de `LicenseShortName` normalisé.
* Commons n'héberge que du libre, mais on ne présume pas : on vérifie.
* Le champ `sa` marque le partage à l'identique, qui contamine les dérivés — d'où
* l'interdiction de compositing de l'ADR 0001.
*/
const LICENCES_OK = [
{ motif: /^cc0/i, id: 'CC0-1.0', attribution: false, sa: false },
{ motif: /^public domain|^pd-/i, id: 'PD', attribution: false, sa: false },
{ motif: /^cc by-sa 4/i, id: 'CC-BY-SA-4.0', attribution: true, sa: true },
{ motif: /^cc by-sa 3/i, id: 'CC-BY-SA-3.0', attribution: true, sa: true },
{ motif: /^cc by-sa 2\.5/i, id: 'CC-BY-SA-2.5', attribution: true, sa: true },
{ motif: /^cc by-sa 2/i, id: 'CC-BY-SA-2.0', attribution: true, sa: true },
{ motif: /^cc by 4/i, id: 'CC-BY-4.0', attribution: true, sa: false },
{ motif: /^cc by 3/i, id: 'CC-BY-3.0', attribution: true, sa: false },
{ motif: /^cc by 2/i, id: 'CC-BY-2.0', attribution: true, sa: false }
];
/** Retire le balisage HTML que Commons renvoie dans les champs d'attribution. */
const texte = (html) =>
html
? String(html)
.replace(/<[^>]+>/g, ' ')
.replace(/\s+/g, ' ')
.trim()
: null;
function classerLicence(nomCourt) {
if (!nomCourt) return null;
return LICENCES_OK.find((l) => l.motif.test(nomCourt.trim())) ?? null;
}
async function getJson(params) {
const u = new URL(API);
for (const [k, v] of Object.entries(params)) u.searchParams.set(k, v);
const res = await fetch(u, { headers: { 'User-Agent': UA, Accept: 'application/json' } });
if (!res.ok) throw new Error(`Commons ${res.status} ${res.statusText}`);
return res.json();
}
async function chercher(nomScientifique) {
const json = await getJson({
action: 'query',
format: 'json',
formatversion: '2',
generator: 'search',
gsrsearch: `"${nomScientifique}" filetype:bitmap`,
gsrnamespace: '6',
gsrlimit: String(CANDIDATS_PAR_TAXON * 2),
prop: 'imageinfo',
iiprop: 'url|size|mime|extmetadata',
iiextmetadatafilter: 'LicenseShortName|LicenseUrl|Artist|Credit|ImageDescription|DateTimeOriginal'
});
const pages = json.query?.pages ?? [];
const retenus = [];
const ecartes = [];
for (const p of pages) {
const info = p.imageinfo?.[0];
if (!info) continue;
const meta = info.extmetadata ?? {};
const nomCourt = texte(meta.LicenseShortName?.value);
const licence = classerLicence(nomCourt);
const commun = {
titre: p.title,
auteur: texte(meta.Artist?.value) ?? texte(meta.Credit?.value),
licence_libelle: nomCourt,
url_fichier: info.url,
url_description: info.descriptionurl,
largeur: info.width,
hauteur: info.height,
mime: info.mime,
description: texte(meta.ImageDescription?.value)?.slice(0, 220) ?? null,
date_prise_de_vue: texte(meta.DateTimeOriginal?.value)
};
if (!licence) {
ecartes.push({ ...commun, raison: `licence non reconnue comme libre : ${nomCourt ?? 'absente'}` });
continue;
}
if (licence.attribution && !commun.auteur) {
ecartes.push({ ...commun, raison: 'licence à attribution mais auteur introuvable dans les métadonnées' });
continue;
}
retenus.push({
...commun,
licence: licence.id,
licence_url: texte(meta.LicenseUrl?.value),
attribution_requise: licence.attribution,
partage_identique: licence.sa
});
}
return { retenus: retenus.slice(0, CANDIDATS_PAR_TAXON), ecartes };
}
async function main() {
const seed = JSON.parse(await readFile(join(ROOT, 'fruits.seed.json'), 'utf8'));
const entrees = [
...seed.fruits.map((f) => ({ ...f, categorie: 'fruit' })),
...seed.plantes_dangereuses.map((p) => ({ ...p, categorie: 'plante_dangereuse' }))
];
const resultats = [];
for (const e of entrees) {
process.stdout.write(`→ Commons : ${e.taxon.scientifique}`);
const { retenus, ecartes } = await chercher(e.taxon.scientifique);
console.log(`${retenus.length} candidats, ${ecartes.length} écartés`);
resultats.push({
id: e.id,
categorie: e.categorie,
taxon: e.taxon.scientifique,
candidats: retenus,
ecartes
});
}
await mkdir(join(ROOT, 'tools', 'data', 'out'), { recursive: true });
await writeFile(
join(ROOT, 'tools', 'data', 'out', 'commons-candidats.json'),
JSON.stringify({ genere_le: new Date().toISOString(), resultats }, null, 2) + '\n'
);
const insuffisants = resultats.filter((r) => r.candidats.length < 2);
const l = [
'# Planche de relecture des médias — filière A',
'',
`> Généré par \`npm run ingest:commons\` le ${new Date().toISOString().slice(0, 10)}.`,
"> Sortie de script : ne pas éditer à la main, rejouer `npm run ingest:commons`.",
'',
'## Ce qui est demandé au porteur',
'',
"Pour chaque taxon, ouvrir les pages de description et retenir au moins deux photographies",
"qui montrent réellement l'espèce. Reporter le choix dans `src/lib/data/fruits/<id>.json`,",
'assigner à chaque média sa vue (`fruit_entier`, `coupe`, `feuille`, `ecorce`, `port`),',
'puis passer `valide` à `true` **et seulement alors**.',
'',
"Aucune vérification botanique n'a été faite par la machine : l'ordre ci-dessous est celui du",
'moteur de recherche de Commons, rien de plus.',
''
];
for (const r of resultats) {
l.push(`## \`${r.id}\` — *${r.taxon}* (${r.categorie})`, '');
if (!r.candidats.length) {
l.push('**Aucun candidat sous licence libre exploitable.** À photographier sur le terrain.', '');
continue;
}
l.push('| # | fichier | auteur | licence | dimensions | page de description |');
l.push('|---|---|---|---|---|---|');
r.candidats.forEach((c, i) => {
const titre = c.titre.replace(/^File:/, '').replace(/\|/g, '\\|');
const auteur = (c.auteur ?? '—').replace(/\|/g, '\\|').slice(0, 60);
l.push(
`| ${i + 1} | ${titre.slice(0, 70)} | ${auteur} | ${c.licence} | ${c.largeur}×${c.hauteur} | [voir](${c.url_description}) |`
);
});
l.push('');
if (r.ecartes.length) {
l.push(`<details><summary>${r.ecartes.length} fichier(s) écarté(s) automatiquement</summary>`, '');
for (const x of r.ecartes) l.push(`- ${x.titre}${x.raison}`);
l.push('', '</details>', '');
}
}
if (insuffisants.length) {
l.push('## Taxons sous le seuil de deux candidats', '');
for (const r of insuffisants) l.push(`- \`${r.id}\` (*${r.taxon}*) — ${r.candidats.length} candidat(s)`);
l.push('');
}
await writeFile(join(ROOT, 'docs', 'planche-relecture-medias.md'), l.join('\n'));
const total = resultats.reduce((n, r) => n + r.candidats.length, 0);
console.log(`\n${total} candidats sur ${resultats.length} taxons — 0 validé (état attendu).`);
if (insuffisants.length) console.log(`${insuffisants.length} taxon(s) sous deux candidats.`);
console.log(' tools/data/out/commons-candidats.json');
console.log(' docs/planche-relecture-medias.md');
}
main().catch((err) => {
console.error('✘', err.message);
process.exit(1);
});
File diff suppressed because it is too large Load Diff
+343
View File
@@ -0,0 +1,343 @@
{
"genere_le": "2026-07-27T03:46:04.075Z",
"resultats": [
{
"id": "kowosol",
"categorie": "fruit",
"graine": {
"scientifique": "Annona muricata",
"famille": "Annonaceae"
},
"wikidata": {
"qid": "Q1709343",
"famille": "Annonaceae",
"rang": "espèce"
},
"wikidata_pistes": null,
"gbif": {
"usageKey": 5407273,
"scientificName": "Annona muricata L.",
"canonicalName": "Annona muricata",
"rank": "SPECIES",
"status": "ACCEPTED",
"matchType": "EXACT",
"confidence": 97,
"famille": "Annonaceae",
"accepte": null
},
"ecarts": []
},
{
"id": "kenet",
"categorie": "fruit",
"graine": {
"scientifique": "Melicoccus bijugatus",
"famille": "Sapindaceae"
},
"wikidata": {
"qid": "Q279728",
"famille": "Sapindaceae",
"rang": "espèce"
},
"wikidata_pistes": null,
"gbif": {
"usageKey": 3189990,
"scientificName": "Melicoccus bijugatus Jacq.",
"canonicalName": "Melicoccus bijugatus",
"rank": "SPECIES",
"status": "ACCEPTED",
"matchType": "EXACT",
"confidence": 99,
"famille": "Sapindaceae",
"accepte": null
},
"ecarts": []
},
{
"id": "gouyav",
"categorie": "fruit",
"graine": {
"scientifique": "Psidium guajava",
"famille": "Myrtaceae"
},
"wikidata": {
"qid": "Q166843",
"famille": "Myrtaceae",
"rang": "espèce"
},
"wikidata_pistes": null,
"gbif": {
"usageKey": 5420380,
"scientificName": "Psidium guajava L.",
"canonicalName": "Psidium guajava",
"rank": "SPECIES",
"status": "ACCEPTED",
"matchType": "EXACT",
"confidence": 99,
"famille": "Myrtaceae",
"accepte": null
},
"ecarts": []
},
{
"id": "pom-site",
"categorie": "fruit",
"graine": {
"scientifique": "Spondias dulcis",
"famille": "Anacardiaceae"
},
"wikidata": {
"qid": "Q500383",
"famille": "Anacardiaceae",
"rang": "espèce"
},
"wikidata_pistes": null,
"gbif": {
"usageKey": 3190595,
"scientificName": "Spondias dulcis Parkinson",
"canonicalName": "Spondias dulcis",
"rank": "SPECIES",
"status": "ACCEPTED",
"matchType": "EXACT",
"confidence": 97,
"famille": "Anacardiaceae",
"accepte": null
},
"ecarts": []
},
{
"id": "zikak",
"categorie": "fruit",
"graine": {
"scientifique": "Chrysobalanus icaco",
"famille": "Chrysobalanaceae"
},
"wikidata": {
"qid": "Q577669",
"famille": "Chrysobalanaceae",
"rang": "espèce"
},
"wikidata_pistes": null,
"gbif": {
"usageKey": 2985082,
"scientificName": "Chrysobalanus icaco L.",
"canonicalName": "Chrysobalanus icaco",
"rank": "SPECIES",
"status": "ACCEPTED",
"matchType": "EXACT",
"confidence": 99,
"famille": "Chrysobalanaceae",
"accepte": null
},
"ecarts": []
},
{
"id": "pom-kannel",
"categorie": "fruit",
"graine": {
"scientifique": "Annona squamosa",
"famille": "Annonaceae"
},
"wikidata": {
"qid": "Q275620",
"famille": "Annonaceae",
"rang": "espèce"
},
"wikidata_pistes": null,
"gbif": {
"usageKey": 5407099,
"scientificName": "Annona squamosa L.",
"canonicalName": "Annona squamosa",
"rank": "SPECIES",
"status": "ACCEPTED",
"matchType": "EXACT",
"confidence": 97,
"famille": "Annonaceae",
"accepte": null
},
"ecarts": []
},
{
"id": "fwiyapen",
"categorie": "fruit",
"graine": {
"scientifique": "Artocarpus altilis",
"famille": "Moraceae"
},
"wikidata": {
"qid": "Q14677",
"famille": "Moraceae",
"rang": "espèce"
},
"wikidata_pistes": null,
"gbif": {
"usageKey": 2984573,
"scientificName": "Artocarpus altilis (Parkinson) Fosberg",
"canonicalName": "Artocarpus altilis",
"rank": "SPECIES",
"status": "ACCEPTED",
"matchType": "EXACT",
"confidence": 97,
"famille": "Moraceae",
"accepte": null
},
"ecarts": []
},
{
"id": "pom-dlo",
"categorie": "fruit",
"graine": {
"scientifique": "Syzygium samarangense",
"famille": "Myrtaceae"
},
"wikidata": {
"qid": "Q11643111",
"famille": "Myrtaceae",
"rang": "espèce"
},
"wikidata_pistes": null,
"gbif": {
"usageKey": 3183180,
"scientificName": "Syzygium samarangense (Blume) Merr. & L.M.Perry",
"canonicalName": "Syzygium samarangense",
"rank": "SPECIES",
"status": "ACCEPTED",
"matchType": "EXACT",
"confidence": 99,
"famille": "Myrtaceae",
"accepte": null
},
"ecarts": []
},
{
"id": "mansiniye",
"categorie": "plante_dangereuse",
"graine": {
"scientifique": "Hippomane mancinella",
"famille": "Euphorbiaceae"
},
"wikidata": {
"qid": "Q636480",
"famille": "Euphorbiaceae",
"rang": "espèce"
},
"wikidata_pistes": null,
"gbif": {
"usageKey": 3063705,
"scientificName": "Hippomane mancinella L.",
"canonicalName": "Hippomane mancinella",
"rank": "SPECIES",
"status": "ACCEPTED",
"matchType": "EXACT",
"confidence": 99,
"famille": "Euphorbiaceae",
"accepte": null
},
"ecarts": []
},
{
"id": "ake",
"categorie": "plante_dangereuse",
"graine": {
"scientifique": "Blighia sapida",
"famille": "Sapindaceae"
},
"wikidata": {
"qid": "Q417145",
"famille": "Sapindaceae",
"rang": "espèce"
},
"wikidata_pistes": null,
"gbif": {
"usageKey": 3189955,
"scientificName": "Blighia sapida K.D.Koenig",
"canonicalName": "Blighia sapida",
"rank": "SPECIES",
"status": "ACCEPTED",
"matchType": "EXACT",
"confidence": 99,
"famille": "Sapindaceae",
"accepte": null
},
"ecarts": []
},
{
"id": "pom-kajou",
"categorie": "plante_dangereuse",
"graine": {
"scientifique": "Anacardium occidentale",
"famille": "Anacardiaceae"
},
"wikidata": {
"qid": "Q34007",
"famille": "Anacardiaceae",
"rang": "espèce"
},
"wikidata_pistes": null,
"gbif": {
"usageKey": 5421368,
"scientificName": "Anacardium occidentale L.",
"canonicalName": "Anacardium occidentale",
"rank": "SPECIES",
"status": "ACCEPTED",
"matchType": "EXACT",
"confidence": 98,
"famille": "Anacardiaceae",
"accepte": null
},
"ecarts": []
},
{
"id": "medisinye",
"categorie": "plante_dangereuse",
"graine": {
"scientifique": "Jatropha curcas",
"famille": "Euphorbiaceae"
},
"wikidata": {
"qid": "Q74644",
"famille": "Euphorbiaceae",
"rang": "espèce"
},
"wikidata_pistes": null,
"gbif": {
"usageKey": 3072953,
"scientificName": "Jatropha curcas L.",
"canonicalName": "Jatropha curcas",
"rank": "SPECIES",
"status": "ACCEPTED",
"matchType": "EXACT",
"confidence": 98,
"famille": "Euphorbiaceae",
"accepte": null
},
"ecarts": []
},
{
"id": "lorye-jonn",
"categorie": "plante_dangereuse",
"graine": {
"scientifique": "Cascabela thevetia",
"famille": "Apocynaceae"
},
"wikidata": {
"qid": "Q10694475",
"famille": "Apocynaceae",
"rang": "espèce"
},
"wikidata_pistes": null,
"gbif": {
"usageKey": 3169652,
"scientificName": "Cascabela thevetia (L.) Lippold",
"canonicalName": "Cascabela thevetia",
"rank": "SPECIES",
"status": "ACCEPTED",
"matchType": "EXACT",
"confidence": 99,
"famille": "Apocynaceae",
"accepte": null
},
"ecarts": []
}
]
}
+194
View File
@@ -0,0 +1,194 @@
#!/usr/bin/env node
/**
* test-porte.mjs — prouve que la porte se ferme.
*
* Une règle de sécurité qu'on n'a jamais vue refuser quoi que ce soit n'est pas une règle,
* c'est une intention. Ce test fabrique les cas interdits par le brief et vérifie que
* `validate.mjs` les rejette bien avec un code de sortie non nul.
*
* Chaque cas correspond à une phrase du brief, citée en regard.
*/
import { readFile, writeFile, mkdir, rm } from 'node:fs/promises';
import { fileURLToPath } from 'node:url';
import { dirname, join } from 'node:path';
import { spawnSync } from 'node:child_process';
const ROOT = join(dirname(fileURLToPath(import.meta.url)), '..', '..');
const BAC = join('tools', 'data', 'out', 'test-porte');
/** Applique une mutation à une copie profonde de l'entrée de référence. */
const muter = (base, fn) => {
const c = structuredClone(base);
fn(c);
return c;
};
/** Un média de référence, valide et utilisable comme épreuve. */
const mediaValide = (over = {}) => ({
id: 'photo-temoin',
filiere: 'A',
type_media: 'photo',
vue: 'fruit_entier',
usages: ['epreuve'],
source: 'wikimedia_commons',
auteur: 'Témoin',
licence: 'CC-BY-SA-4.0',
licence_url: null,
url_fichier: 'https://upload.wikimedia.org/temoin.jpg',
url_description: 'https://commons.wikimedia.org/wiki/File:temoin.jpg',
largeur: 800,
hauteur: 600,
mime: 'image/jpeg',
description: null,
date_prise_de_vue: null,
attribution_requise: true,
partage_identique: true,
usage_non_commercial: false,
composite: false,
valide: true,
valide_par: 'porteur',
valide_le: '2026-07-27',
note_validation: null
});
const CAS = [
{
nom: 'épreuve sur un média non validé',
regle: 'brief §2 — « Le build échoue si un média non validé est référencé par une épreuve. »',
muter: (e) => {
e.medias = [mediaValide({}), mediaValide()];
e.medias[0].id = 'photo-non-validee';
e.medias[0].valide = false;
e.medias[0].valide_par = null;
}
},
{
nom: 'épreuve sur un asset généré (filière B)',
regle: "brief §10 — « Aucune épreuve d'identification ne s'appuie sur un asset IA. »",
muter: (e) => {
e.medias = [mediaValide()];
e.medias[0].filiere = 'B';
e.medias[0].type_media = 'image_generee';
}
},
{
nom: 'épreuve sur une planche botanique',
regle: "brief §2 — filière A = photographie réelle ; une gravure documente mais n'entraîne pas la reconnaissance du réel.",
muter: (e) => {
e.medias = [mediaValide()];
e.medias[0].type_media = 'planche_botanique';
}
},
{
nom: 'épreuve portée par une plante dangereuse',
regle: 'brief §6 — « Pa touché : jamais chronométré, jamais scoré, jamais transformé en épreuve. »',
muter: (e) => {
e.categorie = 'plante_dangereuse';
e.danger = { niveau: 'critique', resume: 'Ne jamais toucher ni manger ce fruit.' };
delete e.saison_mois;
e.comestible = false;
e.medias = [mediaValide()];
}
},
{
nom: 'média à attribution sans auteur',
regle: 'brief §3 — « Récupérer auteur, licence, URL du fichier, URL de la page de description. »',
muter: (e) => {
e.medias = [mediaValide()];
e.medias[0].auteur = null;
}
},
{
nom: 'compositing sur un média en partage à lidentique',
regle: "ADR 0001 — le SA contamine les dérivés, le NC est incompatible avec le SA : aucun compositing.",
muter: (e) => {
e.medias = [mediaValide()];
e.medias[0].composite = true;
}
},
{
nom: 'entrée publiée avec une seule photo validée',
regle: 'brief §8 — « ≥ 2 photos Commons par fruit avec auteur, licence et URL. »',
muter: (e) => {
e.medias = [mediaValide()];
e.orthographe = { norme: 'gwadloupeyen', statut: 'relu', relu_par: 'relecteur' };
e.valide = true;
}
},
{
nom: 'entrée publiée sans relecture kréyòl',
regle: "brief §5 — « L'orthographe kréyòl n'est pas de ton ressort. »",
muter: (e) => {
e.medias = [mediaValide(), muter(mediaValide(), (m) => (m.id = 'photo-temoin-2'))];
e.valide = true;
}
},
{
nom: 'validation anonyme',
regle: 'porte du projet — une validation sans nom nengage personne.',
muter: (e) => {
e.medias = [mediaValide()];
e.medias[0].valide_par = null;
}
}
];
/** Cas témoin : doit passer. Un test qui échoue toujours ne prouve rien non plus. */
const TEMOIN = {
nom: 'TÉMOIN — entrée correcte, doit passer',
attendu: 0,
muter: (e) => {
e.medias = [mediaValide(), muter(mediaValide(), (m) => (m.id = 'photo-temoin-2'))];
e.orthographe = { norme: 'gwadloupeyen', statut: 'relu', relu_par: 'relecteur' };
e.valide = true;
}
};
async function jouer(cas, base, i) {
const dir = join(BAC, `cas-${i}`);
await mkdir(join(ROOT, dir), { recursive: true });
await writeFile(join(ROOT, dir, `${base.id}.json`), JSON.stringify(muter(base, cas.muter), null, '\t'));
const r = spawnSync(process.execPath, [join(ROOT, 'tools', 'data', 'validate.mjs')], {
cwd: ROOT,
env: { ...process.env, KI_FWI_DATA: dir },
encoding: 'utf8'
});
const attendu = cas.attendu ?? 1;
const obtenu = r.status;
const ok = obtenu === attendu;
console.log(`${ok ? '✔' : '✘'} ${cas.nom}`);
if (cas.regle) console.log(` ${cas.regle}`);
if (!ok) {
console.log(` attendu code ${attendu}, obtenu ${obtenu}`);
console.log((r.stderr || r.stdout).split('\n').slice(-8).join('\n'));
}
return ok;
}
async function main() {
const base = JSON.parse(await readFile(join(ROOT, 'src/lib/data/fruits/kowosol.json'), 'utf8'));
await rm(join(ROOT, BAC), { recursive: true, force: true });
console.log('\nTest de la porte de validation\n');
const resultats = [];
resultats.push(await jouer(TEMOIN, base, 0));
for (const [i, cas] of CAS.entries()) resultats.push(await jouer(cas, base, i + 1));
await rm(join(ROOT, BAC), { recursive: true, force: true });
const echecs = resultats.filter((r) => !r).length;
console.log(`\n${resultats.length - echecs}/${resultats.length} cas conformes.`);
if (echecs) {
console.error(`${echecs} cas non couvert(s) : la porte laisse passer ce qu'elle devrait refuser.`);
process.exit(1);
}
console.log('✔ La porte refuse tout ce que le brief interdit.');
}
main().catch((e) => {
console.error('✘', e.stack ?? e.message);
process.exit(1);
});
+163
View File
@@ -0,0 +1,163 @@
#!/usr/bin/env node
/**
* validate.mjs — LA PORTE. Ce script est la règle n°1 du projet écrite en code.
*
* Le brief §2 l'exige mot pour mot : « Le build échoue si un média non validé est
* référencé par une épreuve. Écris ce contrôle comme un script de build, pas comme
* une consigne. » Ce fichier est ce contrôle.
*
* Il vérifie deux couches :
* 1. la forme, contre fruits.schema.json (Ajv) ;
* 2. les règles que le schéma ne peut pas exprimer — filières, licences, sécurité.
*
* Sortie non nulle = build refusé. Aucune de ces règles ne se contourne par un flag.
*/
import { readFile, readdir } from 'node:fs/promises';
import { fileURLToPath } from 'node:url';
import { dirname, join, basename } from 'node:path';
import Ajv2020 from 'ajv/dist/2020.js';
import addFormats from 'ajv-formats';
const ROOT = join(dirname(fileURLToPath(import.meta.url)), '..', '..');
/** Surchargeable pour les tests de la porte (tools/data/test-porte.mjs). */
const DATA = process.env.KI_FWI_DATA ? join(ROOT, process.env.KI_FWI_DATA) : join(ROOT, 'src', 'lib', 'data', 'fruits');
/** Usages qui servent à identifier une espèce. Ce sont eux qui déclenchent la porte. */
const USAGES_IDENTIFIANTS = new Set(['epreuve', 'indice']);
const erreurs = [];
const alertes = [];
const err = (fichier, msg) => erreurs.push(`${fichier}${msg}`);
const warn = (fichier, msg) => alertes.push(`${fichier}${msg}`);
async function main() {
const schema = JSON.parse(await readFile(join(ROOT, 'fruits.schema.json'), 'utf8'));
const ajv = new Ajv2020({ allErrors: true, strict: false });
addFormats(ajv);
const valider = ajv.compile(schema);
const fichiers = (await readdir(DATA)).filter((f) => f.endsWith('.json')).sort();
if (!fichiers.length) {
console.error('✘ Aucune entrée dans src/lib/data/fruits/.');
process.exit(1);
}
const vus = new Map();
const entrees = [];
let nbMedias = 0;
let nbMediasValides = 0;
let nbNC = 0;
for (const f of fichiers) {
const brut = await readFile(join(DATA, f), 'utf8');
let e;
try {
e = JSON.parse(brut);
} catch (ex) {
err(f, `JSON illisible : ${ex.message}`);
continue;
}
// ── Couche 1 : la forme
if (!valider(e)) {
for (const d of valider.errors ?? []) err(f, `schéma : ${d.instancePath || '/'} ${d.message}`);
continue;
}
// ── Couche 2 : les règles métier
if (e.id !== basename(f, '.json')) err(f, `id « ${e.id} » ≠ nom de fichier`);
if (vus.has(e.id)) err(f, `id « ${e.id} » déjà utilisé par ${vus.get(e.id)}`);
vus.set(e.id, f);
const idsMedias = new Set();
for (const m of e.medias) {
nbMedias++;
if (m.valide) nbMediasValides++;
if (m.usage_non_commercial) nbNC++;
if (idsMedias.has(m.id)) err(f, `média « ${m.id} » en double`);
idsMedias.add(m.id);
const identifiant = m.usages.some((u) => USAGES_IDENTIFIANTS.has(u));
// LA PORTE — brief §2 et §10.
if (identifiant) {
if (m.filiere !== 'A')
err(f, `média « ${m.id} » sert à identifier mais relève de la filière ${m.filiere} : une image générée n'enseigne pas le réel`);
if (m.type_media !== 'photo')
err(f, `média « ${m.id} » sert à identifier mais n'est pas une photo (${m.type_media})`);
if (!m.valide)
err(f, `média « ${m.id} » sert à identifier mais n'est pas validé — aucun humain n'a confirmé qu'il montre bien ${e.taxon.scientifique}`);
if (!m.vue) err(f, `média « ${m.id} » sert à identifier mais sa vue n'est pas renseignée`);
}
// Cohérence des filières
if (m.filiere === 'B' && m.type_media !== 'image_generee')
err(f, `média « ${m.id} » : filière B impose type_media = image_generee`);
if (m.filiere === 'B' && m.usages.some((u) => u !== 'decor'))
err(f, `média « ${m.id} » : un média de filière B ne peut servir qu'au décor`);
if (m.filiere === 'A' && m.type_media === 'image_generee')
err(f, `média « ${m.id} » : filière A n'accepte aucune image générée`);
// Licences — brief §3
if (m.attribution_requise && !m.auteur)
err(f, `média « ${m.id} » : licence ${m.licence} à attribution, auteur manquant`);
if (m.composite && (m.partage_identique || m.usage_non_commercial))
err(f, `média « ${m.id} » : compositing interdit sur un média SA ou NC (conflit de licence, ADR 0001)`);
if (m.valide && !m.valide_par)
err(f, `média « ${m.id} » : validé sans nom de validateur — une validation anonyme n'en est pas une`);
// Signalement, pas blocage : l'ADR 0001 accepte le NC contre un engagement non commercial.
if (m.usage_non_commercial && m.source === 'wikimedia_commons')
warn(f, `média « ${m.id} » : NC annoncé sur une source Commons — vérifier, Commons n'héberge pas de NC`);
}
// Sécurité enfants — brief §6 : « Pa touché » n'est jamais une épreuve, jamais scoré.
if (e.categorie === 'plante_dangereuse') {
if (!e.danger) err(f, 'plante dangereuse sans bloc danger');
for (const m of e.medias)
if (m.usages.includes('epreuve'))
err(f, `média « ${m.id} » : une plante dangereuse ne peut pas porter d'épreuve — le module Pa touché n'est ni chronométré ni scoré`);
}
// Conditions de publication d'une entrée
if (e.valide) {
const photos = e.medias.filter((m) => m.valide && m.filiere === 'A' && m.type_media === 'photo');
if (photos.length < 2)
err(f, `entrée déclarée valide avec ${photos.length} photo(s) validée(s) — le brief §8 en exige au moins deux`);
if (e.orthographe.statut !== 'relu')
err(f, "entrée déclarée valide alors que l'orthographe kréyòl n'est pas relue (ADR 0005)");
} else {
warn(f, 'entrée non encore validée pour publication');
}
if (!e.audio.gcf) warn(f, 'aucun enregistrement kréyòl — le jeu devra se replier en silence');
if (e.orthographe.statut === 'a_relire') warn(f, 'orthographe kréyòl à relire');
entrees.push(e);
}
// ── Rapport
console.log(`\nEntrées : ${entrees.length}`);
console.log(`Médias : ${nbMedias} (${nbMediasValides} validés, ${nbNC} sous clause NC)`);
console.log(`Publiables : ${entrees.filter((e) => e.valide).length}`);
if (alertes.length) {
console.log(`\n${alertes.length} alerte(s) — n'empêchent pas le build :`);
for (const a of alertes) console.log(` · ${a}`);
}
if (erreurs.length) {
console.error(`\n${erreurs.length} erreur(s) — build refusé :`);
for (const e of erreurs) console.error(` · ${e}`);
process.exit(1);
}
console.log('\n✔ Dataset conforme. Aucune épreuve ne sappuie sur un média non validé.');
}
main().catch((e) => {
console.error('✘', e.stack ?? e.message);
process.exit(1);
});
+195
View File
@@ -0,0 +1,195 @@
#!/usr/bin/env node
/**
* verify-taxa.mjs — vérification taxonomique contre Wikidata et GBIF.
*
* Le brief §8 exige que chaque champ taxonomique soit vérifié contre Wikidata ET GBIF,
* « pas contre ta mémoire ». Ce script est ce contrôle : il lit les noms scientifiques
* d'amorçage, interroge les deux référentiels, et écrit un rapport de divergence.
*
* Il ne corrige rien tout seul : il constate. Les corrections sont reportées à la main
* dans src/lib/data/fruits/*.json, avec la trace de la réponse d'API en regard.
*
* Sorties :
* tools/data/out/taxa-verified.json — données brutes des deux API
* docs/verification-taxons.md — rapport lisible, versionné
*
* Hors ligne : ce script vit dans tools/, jamais dans le bundle. Aucun appel réseau
* ne subsiste au runtime du jeu (playbook P2 : bake au build).
*/
import { readFile, writeFile, mkdir } from 'node:fs/promises';
import { fileURLToPath } from 'node:url';
import { dirname, join } from 'node:path';
const ROOT = join(dirname(fileURLToPath(import.meta.url)), '..', '..');
const UA = 'ki-fwi-dataset/0.1 (https://o-k-i.net ; projet educatif ORGANISATION KA INTERNATIONALE)';
const WIKIDATA_SPARQL = 'https://query.wikidata.org/sparql';
const WIKIDATA_API = 'https://www.wikidata.org/w/api.php';
const GBIF_MATCH = 'https://api.gbif.org/v1/species/match';
const GBIF_SPECIES = 'https://api.gbif.org/v1/species';
/** Rang « famille » dans Wikidata. */
const Q_FAMILLE = 'wd:Q35409';
async function getJson(url, params) {
const u = new URL(url);
for (const [k, v] of Object.entries(params ?? {})) u.searchParams.set(k, v);
const res = await fetch(u, { headers: { 'User-Agent': UA, Accept: 'application/json' } });
if (!res.ok) throw new Error(`${res.status} ${res.statusText}${u}`);
return res.json();
}
/**
* Interroge Wikidata en une seule requête SPARQL : entité dont P225 (nom du taxon)
* vaut exactement le nom cherché, plus la famille remontée par P171+ filtrée sur P105 = famille.
*/
async function wikidataBatch(noms) {
const values = noms.map((n) => JSON.stringify(n)).join(' ');
const query = `SELECT ?taxon ?name ?fam ?rang WHERE {
VALUES ?name { ${values} }
?taxon wdt:P225 ?name .
OPTIONAL { ?taxon wdt:P105 ?r . ?r rdfs:label ?rang . FILTER(LANG(?rang) = "fr") }
OPTIONAL { ?taxon wdt:P171+ ?f . ?f wdt:P105 ${Q_FAMILLE} ; wdt:P225 ?fam . }
}`;
const u = new URL(WIKIDATA_SPARQL);
u.searchParams.set('query', query);
const res = await fetch(u, {
headers: { 'User-Agent': UA, Accept: 'application/sparql-results+json' }
});
if (!res.ok) throw new Error(`SPARQL ${res.status} ${res.statusText}`);
const json = await res.json();
const parNom = new Map();
for (const b of json.results.bindings) {
const nom = b.name.value;
if (!parNom.has(nom)) parNom.set(nom, { qid: null, famille: null, rang: null });
const e = parNom.get(nom);
e.qid = b.taxon.value.replace('http://www.wikidata.org/entity/', '');
if (b.fam) e.famille = b.fam.value;
if (b.rang) e.rang = b.rang.value;
}
return parNom;
}
/** Repli quand P225 ne correspond à rien : recherche plein texte, pour au moins pointer une piste. */
async function wikidataRecherche(nom) {
const json = await getJson(WIKIDATA_API, {
action: 'wbsearchentities',
search: nom,
language: 'en',
format: 'json',
limit: '3',
origin: '*'
});
return (json.search ?? []).map((r) => ({ qid: r.id, label: r.label, description: r.description }));
}
async function gbif(nom) {
const m = await getJson(GBIF_MATCH, { name: nom, strict: 'false' });
const out = {
usageKey: m.usageKey ?? null,
scientificName: m.scientificName ?? null,
canonicalName: m.canonicalName ?? null,
rank: m.rank ?? null,
status: m.status ?? null,
matchType: m.matchType ?? null,
confidence: m.confidence ?? null,
famille: m.family ?? null,
accepte: null
};
// Un synonyme est le piège classique de ce dataset : GBIF renvoie alors la clé du
// synonyme et il faut aller chercher le nom accepté pour ne pas figer un nom périmé.
if (out.status && out.status !== 'ACCEPTED' && out.usageKey) {
try {
const sp = await getJson(`${GBIF_SPECIES}/${out.usageKey}`, {});
out.accepte = {
usageKey: sp.acceptedKey ?? null,
scientificName: sp.accepted ?? null
};
} catch {
out.accepte = { erreur: 'lecture /species/{key} impossible' };
}
}
return out;
}
const ok = (a, b) => typeof a === 'string' && typeof b === 'string' && a.toLowerCase() === b.toLowerCase();
async function main() {
const seed = JSON.parse(await readFile(join(ROOT, 'fruits.seed.json'), 'utf8'));
const entrees = [
...seed.fruits.map((f) => ({ ...f, categorie: 'fruit' })),
...seed.plantes_dangereuses.map((p) => ({ ...p, categorie: 'plante_dangereuse' }))
];
const noms = entrees.map((e) => e.taxon.scientifique);
console.log(`→ Wikidata : ${noms.length} taxons en une requête SPARQL…`);
const wd = await wikidataBatch(noms);
const resultats = [];
for (const e of entrees) {
const nom = e.taxon.scientifique;
process.stdout.write(`→ GBIF : ${nom}`);
const g = await gbif(nom);
console.log(g.status ?? 'AUCUN MATCH');
let w = wd.get(nom) ?? null;
let pistes = null;
if (!w) pistes = await wikidataRecherche(nom);
const ecarts = [];
if (!w) ecarts.push('Wikidata : aucune entité avec P225 = ce nom exact');
if (w && !w.famille) ecarts.push('Wikidata : famille non remontée par P171+');
if (w?.famille && !ok(w.famille, e.taxon.famille))
ecarts.push(`famille Wikidata « ${w.famille} » ≠ graine « ${e.taxon.famille} »`);
if (g.famille && !ok(g.famille, e.taxon.famille))
ecarts.push(`famille GBIF « ${g.famille} » ≠ graine « ${e.taxon.famille} »`);
if (g.status && g.status !== 'ACCEPTED')
ecarts.push(`GBIF : statut ${g.status} — nom accepté ${g.accepte?.scientificName ?? '?'}`);
if (g.matchType && g.matchType !== 'EXACT') ecarts.push(`GBIF : matchType ${g.matchType}`);
resultats.push({
id: e.id,
categorie: e.categorie,
graine: { scientifique: nom, famille: e.taxon.famille },
wikidata: w,
wikidata_pistes: pistes,
gbif: g,
ecarts
});
}
await mkdir(join(ROOT, 'tools', 'data', 'out'), { recursive: true });
await writeFile(
join(ROOT, 'tools', 'data', 'out', 'taxa-verified.json'),
JSON.stringify({ genere_le: new Date().toISOString(), resultats }, null, 2) + '\n'
);
const lignes = [
'# Vérification taxonomique — Wikidata × GBIF',
'',
`> Généré par \`npm run verify:taxa\` le ${new Date().toISOString().slice(0, 10)}.`,
'> Ne pas éditer à la main : rejouer le script quand la graine change.',
'',
'| id | nom de la graine | Wikidata | famille WD | GBIF | statut GBIF | famille GBIF | écarts |',
'|---|---|---|---|---|---|---|---|'
];
for (const r of resultats) {
lignes.push(
`| \`${r.id}\` | *${r.graine.scientifique}* | ${r.wikidata?.qid ?? '—'} | ${r.wikidata?.famille ?? '—'} | ${r.gbif.usageKey ?? '—'} | ${r.gbif.status ?? '—'} | ${r.gbif.famille ?? '—'} | ${r.ecarts.length ? r.ecarts.join(' · ') : 'aucun'} |`
);
}
const nbEcarts = resultats.filter((r) => r.ecarts.length).length;
lignes.push('', `**${nbEcarts} entrée(s) sur ${resultats.length} présentent au moins un écart.**`, '');
await writeFile(join(ROOT, 'docs', 'verification-taxons.md'), lignes.join('\n'));
console.log(`\n${resultats.length} taxons vérifiés, ${nbEcarts} avec écart.`);
console.log(' tools/data/out/taxa-verified.json');
console.log(' docs/verification-taxons.md');
}
main().catch((err) => {
console.error('✘', err.message);
process.exit(1);
});