diff --git a/docs/adr/0008-vote-par-transaction.md b/docs/adr/0008-vote-par-transaction.md index 8f0658b..2642f45 100644 --- a/docs/adr/0008-vote-par-transaction.md +++ b/docs/adr/0008-vote-par-transaction.md @@ -3,7 +3,9 @@ > Complète [0002](0002-vote-permanent.md) (vote permanent) et [0006](0006-acces-connect-trustinwallet.md) > (accès). Décision d'Yvv du 2026-10-30 (revue, L9) ; le format du bulletin, la voie du > portefeuille et les réglages sont les choix par défaut d'orch (Q5, Q6, Q7), isolés pour être -> changés sans toucher au reste. +> changés sans toucher au reste. Corrigé le 2026-10-31 après la relecture indépendante de +> `74f96be` (lot B2) : finalité, recherche filtrée et paginée, tâche de fond, plafond, bulletin +> Ğecko, bulletins lâchés, reçu. **Contexte.** Jusqu'ici, un vote était une ligne écrite par le serveur pour la session connectée. Dans Monnaie libre, l'électorat W est la toile de confiance, mais la connexion Ğ1 @@ -77,27 +79,53 @@ fait signer par l'extension de portefeuille du navigateur (interface standard `i l'offrent), avec **polkadot-api chargé au seul moment de signer**, et l'envoie à un nœud Ğ1 (`LD_VOTE_NODES`). Sans portefeuille dans le navigateur : **Ğecko**, par un lien et un QR code `g1://?amount=0.1&comment=ld1:` (un virement commenté, ce que Ğecko sait faire) ; -ce bulletin-là n'est lié à aucun compte, et la page attend. +ce bulletin-là n'est lié à aucun compte : seul un commentaire **payé** le tranche (voir la +confirmation), et le serveur le guette, la page ouverte ou non. + +La page joint un nœud **avant** de demander la signature (comme polkadot-api, qui lit le nonce +et le runtime) : un nœud muet ne reçoit jamais rien, la page le dit et lâche le bulletin. ### La confirmation — `crates/ld-server/src/ballots.rs`, `indexer.rs` -Le serveur lit l'indexeur (duniter-squid, `LD_INDEXERS`) : +Le serveur lit l'indexeur (duniter-squid, PostGraphile, `LD_INDEXERS`) : ```graphql -query Ballot($hash: String!) { - txComments(condition: {hash: $hash}, orderBy: BLOCK_NUMBER_ASC, first: 20) { +query Ballot($hash: String!, $filter: TxCommentFilter, $after: Cursor) { + squidStatus { height } + txComments(condition: {hash: $hash}, filter: $filter, + orderBy: [BLOCK_NUMBER_ASC, ID_ASC], first: 50, after: $after) { + pageInfo { hasNextPage endCursor } nodes { id blockNumber remark author { id identity { index name isMember } } transfersByCommentId { nodes { fromId toId amount } } } } } ``` -`hash` = `0x` + blake2b-256 des octets de la remarque. Il garde la première occurrence, dans -l'ordre de la chaîne, qui ne vient pas d'un autre compte que celui lié, puis exige : +`hash` = `0x` + blake2b-256 des octets de la remarque. Le `filter` ne demande que ce qui peut +trancher : pour un bulletin lié, `{authorId: {equalTo: }}` ; pour un bulletin Ğecko, +`{transfersByCommentId: {some: {toId: {equalTo: }, amount: +{greaterThanOrEqualTo: ""}}}}`. Les commentaires viennent dans l'ordre de la chaîne, +**50 par page, page après page** (au plus 20 pages par lecture), jusqu'à celui qui tranche : +des copies ne masquent jamais le vrai commentaire (l'ancienne requête s'arrêtait à 20 ; la +remarque « Merci » en compte déjà 26 sur la chaîne). + +**La finalité.** L'indexeur sert la meilleure chaîne, blocs pas encore définitifs compris. +`squidStatus` n'expose que `name`, `height` et `hash` (pas de `finalizedHeight`) ; `height` est +le dernier bloc définitif traité. Relevé le 2026-10-31 sur indexer.duniter.org, par +`{ squidStatus { height } blocks(orderBy: HEIGHT_DESC, first: 1) { nodes { height } } }` : +`height` reste **3 blocs** derrière le plus récent bloc servi (3 407 340 contre 3 407 343, puis +3 407 342 contre 3 407 345…), les 2 à 3 blocs de la finalité de Duniter v2. Seul un commentaire +d'un bloc ≤ `height` compte, ou refuse ; au-dessus, le bulletin attend. + +Le moteur (`ld_engine::ballot::judge`) juge à nouveau ce qui revient — un indexeur qui ignore le +filtre ne change que le nombre de pages. Il garde le premier commentaire, dans l'ordre de la +chaîne, qui n'est pas une copie : pour un bulletin lié, un commentaire d'un autre compte est une +copie ; pour un bulletin Ğecko, **un commentaire sans le virement est une copie** (une remarque +seule ne coûte rien à envoyer). Puis il exige : 1. la remarque exacte ; 2. dans la même transaction, un virement **du signataire vers le compte des votes**, d'au moins - le montant ; + le montant (`transfer` sinon — seulement pour un bulletin lié : son propre compte s'est trompé) ; 3. une identité Ğ1 au signataire (`no_identity` sinon) ; 4. que cette identité soit **membre maintenant** (`not_member` sinon) — par la règle de trustinWallet. @@ -107,12 +135,19 @@ avec le bloc et le rang de l'évènement ; le balayage d'adoption tourne aussit demandé le bulletin voit ces votes comme « ton vote » — et seulement ceux de ses bulletins : une autre session ne voit jamais ce qu'a voté la même identité ailleurs. -Le serveur relit l'indexeur pour chaque bulletin en attente toutes les 10 secondes (tâche de -fond) et quand la page demande (au plus une lecture toutes les 3 secondes par bulletin). Un -bulletin non vu en **24 heures** est lâché. Cas d'erreur, chacun testé : indexeur muet (le -bulletin reste en attente), signataire non membre ou sans identité (refusé, et dit), mauvais -montant ou mauvais destinataire (refusé), déjà confirmé (rien ne change), révision changée entre -temps (le vote porte sur la révision votée : « à reconfirmer »). +**La tâche de fond** passe toutes les 10 secondes et lit **50 bulletins en attente au plus, le +moins récemment lu d'abord** (jamais lu, puis la plus ancienne lecture) : chaque bulletin en +attente est lu au moins toutes les ⌈n / 50⌉ passes, que la page l'attende ou non (un code Ğecko, +une fenêtre fermée). Il faudrait plus de 430 000 bulletins en attente pour qu'un seul ne soit pas +lu dans ses 24 heures. La page, elle, fait lire son bulletin au plus toutes les 3 secondes. + +Un bulletin non vu en **24 heures** est **lu une dernière fois à son échéance**, puis lâché ; +s'aucun indexeur ne répond, ou si son commentaire attend un bloc définitif, il reste en attente +et relu, une heure au plus. Cas d'erreur, chacun testé : indexeur muet (le bulletin reste en +attente), signataire non membre ou sans identité (refusé, et dit), mauvais montant ou mauvais +destinataire (refusé si lié, ignoré si Ğecko), copie nue ou mal payée d'un bulletin Ğecko +(ignorée), bloc pas encore définitif (en attente), déjà confirmé (rien ne change), révision +changée entre temps (le vote porte sur la révision votée : « à reconfirmer »). ### Le dernier fait foi @@ -122,9 +157,24 @@ un bulletin plus récent sur la chaîne. « Retirer mon vote » est un bulletin `none`. Les transactions d'un même compte gardent l'ordre de ses envois (le nonce) ; le désordre ne vient que de l'ordre de lecture de l'indexeur, et la règle l'absorbe. -Un bulletin que le portefeuille n'a pas signé (refus, fonds insuffisants, compte absent) est lâché -aussitôt par la page (`DELETE /api/ballots/{id}` : `expired`, raison `dropped`), pour ne pas -rester « en attente » une journée. Jamais un bulletin confirmé. +### Lâcher ou garder un bulletin + +**Rien n'est parti** : la page lâche le bulletin aussitôt (`DELETE /api/ballots/{id}` : +`expired`, raison `dropped`), pour ne pas le montrer « en attente » une journée. C'est le cas : +- d'un refus du portefeuille, d'un compte absent, de fonds insuffisants ; +- d'un nœud muet **avant** la signature (la page joint le nœud d'abord) ; +- d'une fenêtre fermée avant la signature ; si le portefeuille demande encore à ce moment (sa + propre fenêtre peut rester ouverte), le bulletin attend sa réponse : refusé, il est lâché ; +- d'un refus de la chaîne : rejet du nœud (transaction invalide), ou transaction incluse mais + défaite (le virement a échoué, `batchAll` défait tout : aucune remarque). + +**La transaction a pu partir** — signée, puis le nœud ou le portefeuille se tait — : le bulletin +est gardé, et la tâche de fond le guette jusqu'à son échéance. Un **code Ğecko** montré est gardé +aussi, fenêtre fermée : on peut payer plus tard, depuis le téléphone. Jamais un bulletin confirmé +n'est lâché. + +« Ton vote », sous l'article : un bulletin en attente demandé **avant** un vote confirmé sur la +même ligne ne s'y montre plus ; un bulletin demandé après, si. ### Le vote groupé @@ -132,7 +182,14 @@ Un panier : article par article ; « tout pour » / « tout contre » pour une s document — jamais pour un article dont plusieurs versions sont en concurrence : l'interface le montre, on choisit sa version. Puis **un geste** : une écriture (groupe géré), ou **une transaction** (chaîne) pour toutes les lignes, au même prix qu'une seule (0,1 Ğ1 par transaction, -pas par ligne ; 200 lignes au plus, 20 bulletins en attente par session). +pas par ligne ; 200 lignes au plus). + +**Le plafond vaut par identité, quelle que soit la session** : 20 bulletins au plus à la fois, +en attente **ou lâchés depuis moins d'une heure** — lâcher un bulletin ne libère pas sa place +aussitôt (la relecture avait créé 100 bulletins et 3 500 lignes en une session, par `DELETE`). +La tâche de fond **purge** les bulletins lâchés, lignes comprises : un jour après qu'un +portefeuille ne les a pas signés, une semaine après qu'ils n'ont pas été vus à temps (sous +l'article, il le dit d'ici là). Un bulletin lâché n'a jamais compté : rien d'un vote ne se perd. ### Ce que voit la chaîne @@ -140,13 +197,37 @@ Qu'un compte (et son identité) a envoyé 0,1 Ğ1 au compte des votes avec une r tel bloc : **qui a voté et quand, jamais quoi** — ni le document, ni le nombre de lignes, ni les choix. Le solde du compte des votes est public : il dit combien de votes ont été envoyés. +Recoupée avec les totaux affichés en direct, la chaîne peut laisser deviner un choix (un total +qui bouge juste après un vote) : une décision d'Yvv attend (secret par paliers, ou totaux en +direct). En attendant, les totaux affichés passent par une seule fonction, +`DocState::shown_tally` (et `shown_evaluation`), où une publication par paliers se branchera ; +l'adoption lit `tally`, et les textes publiés (`publish.rs`) suivraient `shown_tally`. + ### Ce que sait le serveur Les bulletins, leurs lignes, leurs sels, la session qui les a demandés et l'identité qui les a signés : il sait qui a voté quoi, comme pour un vote direct, et ne montre que les totaux. Il ne peut pas inventer un vote d'une identité (il faudrait sa signature sur la chaîne) ; il pourrait en taire un. Chaque vote compté se vérifie contre la chaîne en recalculant H depuis les lignes et le -sel — ce que personne d'autre ne peut faire tant que les sels restent au serveur. +sel. + +### Le reçu + +La note de recherche promet que chacun peut vérifier son propre vote avec son sel. Le serveur +rend donc le bulletin **à l'identité qui l'a demandé, et à elle seule** (404 pour toute autre) : + +- `GET /api/ballots/{id}/receipt` — le reçu, à télécharger (`recu-vote--.json`) : le + document, le compte lié, les lignes (version, révision, choix, et pour lire : l'article et son + titre), le sel, la forme canonique, H, la remarque, son empreinte pour l'indexeur, et où en est + le bulletin (état, bloc, évènement, signataire, identité comptée) ; +- `GET /api/ballots` — son historique, le plus récent d'abord (sans les bulletins jamais signés). + +L'interface les montre dans la fenêtre de vote (« Télécharger ton reçu », « Tes bulletins ») et +sur la page **« Tes bulletins »** (`/bulletins`), qui **vérifie un reçu dans le navigateur**, sans +rien demander au serveur : elle recalcule la forme canonique et H (`web/src/lib/receipt.ts`, mêmes +vecteurs que le moteur) et dit si le reçu donne bien sa remarque — à chercher dans l'historique +de son portefeuille, ou sur la chaîne au bloc indiqué. Garder son reçu pour soi : avec le sel, +n'importe qui recalculerait le choix. ### Les réglages (Q7) — `crates/ld-server/src/config.rs` @@ -166,7 +247,9 @@ Migration `0006`, additive : `ballots` (le bulletin, son sel, H, `0x`+blake2b-25 le compte et le montant du moment, l'état `pending | confirmed | refused | expired`, la raison, l'identité qui a voté, le signataire, le bloc, le rang, l'évènement, ce qui est entré en vigueur, les dates) et `ballot_lines` (version, révision, choix). `votes` gagne `source` (`server` par -défaut : tous les votes d'avant restent tels quels), `block`, `event_index`, `ballot_id`. +défaut : tous les votes d'avant restent tels quels), `block`, `event_index`, `ballot_id`. Les +corrections du 2026-10-31 n'ajoutent pas de migration ; la purge efface les bulletins lâchés +(`expired`) passé leur délai, jamais un bulletin confirmé ni refusé, jamais un vote. ## Coût @@ -178,10 +261,21 @@ défaut : tous les votes d'avant restent tels quels), `block`, `event_index`, `b indexeurs se configurent ; lire les évènements sur un nœud serait l'étape suivante. - Le droit de vote se vérifie **au moment de la confirmation sur la chaîne** : un membre sorti de la toile ensuite garde ses voix. -- Par Ğecko, le bulletin n'est lié à aucun compte : un autre compte qui recopierait la remarque - et la ferait inclure avant (en payant 0,1 Ğ1) prendrait ce bulletin — ses lignes compteraient - pour lui. Par l'extension, le bulletin est lié au compte et la copie est ignorée. -- Un paiement Ğecko fait après 24 heures ne compte pas (il est perdu pour le vote). +- Par Ğecko, le bulletin n'est lié à aucun compte. **Une copie nue de la remarque** (sans + virement, gratuite) **est ignorée** : elle ne refuse plus le bulletin. Seul un commentaire payé + le tranche. **Reste possible, la variante « prise par une copie payée »** : un autre compte qui + voit la remarque (dans la file des transactions, ou sur l'écran) et fait inclure avant une + copie **payée** (0,1 Ğ1 vers le compte des votes) prend ce bulletin — ses lignes comptent pour + lui, le paiement de la personne arrive après et ne compte plus. Elle coûte 0,1 Ğ1 à qui la tente + et se voit sur la chaîne ; un compte sans identité qui paie la copie fait refuser le bulletin + (`no_identity`). Par l'extension, le bulletin est lié au compte et toute copie est ignorée. +- Par Ğecko, un virement d'un mauvais montant ou vers un autre compte laisse le bulletin en + attente (au lieu d'un refus), jusqu'à son échéance : on ne distingue pas une erreur d'une copie. +- Un bulletin est lu une dernière fois à son échéance (24 heures) : ce qui est alors sur la + chaîne, en bloc définitif, compte encore ; un paiement Ğecko plus tardif est perdu pour le vote. +- Une identité Ğ1 créée par un vote sur la chaîne, jamais connectée ici, ne retient pas son nom + face à une personne qui arrive par un lien d'équipe (comme tout membre de la toile qui n'est + jamais venu) ; une identité Ğ1 qui s'est connectée le garde. - polkadot-api : environ 180 Ko (66 Ko compressés) chargés au moment de signer seulement ; `node_modules` grossit d'environ 77 Mo (son outillage). - La chaîne montre la participation de chacun (qui a voté, quand, combien de fois). diff --git a/docs/chantiers/acte-certification/CHANTIER.md b/docs/chantiers/acte-certification/CHANTIER.md index 8fe23b2..d268784 100644 --- a/docs/chantiers/acte-certification/CHANTIER.md +++ b/docs/chantiers/acte-certification/CHANTIER.md @@ -229,7 +229,9 @@ du bulletin (`ld1:` + 64 chiffres hexadécimaux). La voix est celle de **l'ident qui signe**, membre au moment où le serveur confirme la transaction sur l'indexeur ; quelle que soit la session (invitation ou connexion Ğ1), la même identité n'a qu'une voix par version, et **le dernier vote fait foi**, dans l'ordre de la chaîne. La chaîne montre qui a voté et quand, -jamais quoi ; chacun ne voit que les totaux. Sans compte des votes configuré +jamais quoi ; chacun ne voit que les totaux. Chacun reçoit **le reçu de son bulletin** (ses votes +et son sel), le retrouve sur « Tes bulletins » et le vérifie dans son navigateur ; personne +d'autre ne le reçoit (ADR 0008, « Le reçu »). Sans compte des votes configuré (`LD_VOTE_ACCOUNT`), le vote par la chaîne est fermé et l'interface le dit. Dans les groupes gérés (essai, Axiom…), tout membre vote directement, sans portefeuille. @@ -259,9 +261,11 @@ Les raisons longues sont dans `docs/adr/`. de la toile, ou dont l'accès est révoqué, garde les voix déjà confirmées. - Le serveur fait confiance à l'indexeur pour lire la transaction (remarque, virement, identité, appartenance à la toile) ; plusieurs indexeurs se configurent (ADR 0008). -- Par Ğecko, le bulletin n'est lié à aucun compte : une copie de son sceau incluse avant lui par - un autre compte le prendrait. Par l'extension, il est lié au compte qui signe. -- Un bulletin non vu sur la chaîne en 24 heures est lâché : un paiement plus tardif ne compte pas. +- Par Ğecko, le bulletin n'est lié à aucun compte : une copie nue de son sceau est ignorée, mais + une copie **payée** (0,1 Ğ1) incluse avant lui par un autre compte le prendrait. Par + l'extension, il est lié au compte qui signe. +- Un bulletin non vu sur la chaîne en 24 heures est lu une dernière fois, puis lâché : un + paiement plus tardif ne compte pas. - Dans un groupe géré (essai, Axiom…), une même personne admise sous une identité d'invitation **et** sous sa clé Ğ1 aurait deux voix : c'est à l'administration de n'en admettre qu'une. - Un administrateur peut créer un nouveau lien pour une identité d'invitation existante diff --git a/docs/chantiers/acte-certification/CONTROLES.md b/docs/chantiers/acte-certification/CONTROLES.md index e4da467..f599d1a 100644 --- a/docs/chantiers/acte-certification/CONTROLES.md +++ b/docs/chantiers/acte-certification/CONTROLES.md @@ -6,7 +6,7 @@ sur un contrôle vaut échec du contrôle tant qu'elle n'est pas traitée. Où tester : les contrôles qui écrivent (C5, C6, C7, C21, C22) se font dans le **groupe d'essai** (caché, plancher C = 1, jamais publié) — jamais sur le texte de la communauté. Les -votes par la chaîne Ğ1 (C11, C17, C23) ne se jouent, pour l'automate, que sur une **chaîne +votes par la chaîne Ğ1 (C11, C17, C23, C32, C33) ne se jouent, pour l'automate, que sur une **chaîne simulée** (`web/e2e/chain-mock.mjs` : un faux nœud, un faux indexeur, un faux portefeuille) ; pour une personne, ils coûtent 0,1 Ğ1 réels : c'est un acte « paye » d'Yvv. @@ -36,7 +36,9 @@ pour une personne, ils coûtent 0,1 Ğ1 réels : c'est un acte « paye » d'Yvv. | C21 | Le vote déplié | groupe d'essai : Unicité du compte → « Le vote », puis « Pour » ; une autre personne ouvre le même vote | sous l'article : le niveau d'eau, « 0 pour · 0 contre », « Seuil : … voix pour », « Il manque … », « Tu n'as pas voté sur cette version. » ; après « Pour » : « Ton vote : pour · enregistré », « 1 pour · 0 contre », le bouton enfoncé, « Ton vote ne se montre à personne : seuls les totaux sont visibles. » ; l'autre personne voit 1 pour, jamais qui ; « Le vote » replie ; « Retirer mon vote » remet 0 | | C22 | Le vote groupé | groupe d'essai : « Propositions en cours » → « Engagements techniques » → « Voter cette section » ; « Tout pour » ; dans « Connaissance suffisante », « Pour » sur la variante 1.0.0 ; recharger ; « Voter (n) » | le panier s'ouvre sur la section ; « Tout pour » remplit les articles à une version, pas « Connaissance suffisante » ni « Rencontre physique… » (« Plusieurs versions : choisis la tienne. », et le compte des articles laissés) ; le panier reste après rechargement (« Voter en lot · n ») ; un seul envoi : « n votes enregistrés. », le panier vide, la variante choisie à 1 pour | | C23 | Le vote par la chaîne Ğ1 | Monnaie libre, un portefeuille dans le navigateur : « Voter en lot », « Pour » sur Unicité du compte et Réciprocité, « Signer et envoyer (2) » ; puis sous Réciprocité, « Contre » (l'indexeur en retard) puis « Retirer mon vote » ; puis sans portefeuille : « Pour » → « Passer par Ğecko » | une seule signature pour les deux : 0,1 Ğ1 vers le compte des votes et une remarque `ld1:` + 64 chiffres, rien du vote en clair ; « Ton vote compte : il est inscrit sur la chaîne Ğ1. », « Compté pour l'identité Ğ1 « Alice ». » ; sous l'article « Ton vote : pour · inscrit sur la chaîne Ğ1 », 1 pour ; « En attente de la chaîne Ğ1 : contre. » ; le retrait, plus récent sur la chaîne, fait foi même quand le « contre » est confirmé après lui (0 pour · 0 contre) ; Ğecko : un QR code et le lien `g1://?amount=0.1&comment=ld1:…`, puis la confirmation dès que la chaîne la montre | -| C24 | Sans compte des votes | Monnaie libre sur un serveur sans `LD_VOTE_ACCOUNT`, puis le groupe d'essai | pas de « Voter en lot » ni « Voter cette section » ; sous l'article : « Le vote par la chaîne Ğ1 n'est pas encore ouvert : le compte qui reçoit les votes reste à créer. Tu peux lire, proposer et signaler une contradiction. », pas de bouton, les totaux et le seuil restent ; dans le groupe d'essai, le panier et les boutons sont là | +| C24 | Sans compte des votes | Monnaie libre sur un serveur sans `LD_VOTE_ACCOUNT`, puis le groupe d'essai | pas de « Voter en lot » ni « Voter cette section » ; sous l'article : « Le vote par la chaîne Ğ1 n'est pas encore ouvert : le compte qui reçoit les votes reste à créer. Tu peux lire, proposer et signaler une contradiction. », pas de bouton, les totaux et le seuil restent ; le panier ouvert par son adresse (`?onglet=panier`) dit la même chose, son bouton éteint, et **jamais** « Tes votes comptent dès l'envoi » ; dans le groupe d'essai, le panier et les boutons sont là | +| C32 | Lâcher ou garder un bulletin | Monnaie libre, un portefeuille dans le navigateur (Eve, chaîne simulée) : Réciprocité → « Contre » le nœud éteint ; puis « Contre », fermer la fenêtre pendant que le portefeuille demande, refuser dans le portefeuille ; puis « Contre », fermer, signer dans le portefeuille ; une autre personne, sans portefeuille : « Pour » → « Passer par Ğecko », fermer, payer depuis un téléphone | nœud éteint : « La chaîne Ğ1 ne répond pas. Réessaie dans un moment. », le bulletin lâché aussitôt, rien « en attente » sous l'article ; fenêtre fermée puis refus : lâché ; fenêtre fermée puis signature : gardé, et la chaîne le confirme sans la page (« Ton vote : contre · inscrit sur la chaîne Ğ1 ») ; Ğecko, fenêtre fermée : « En attente de la chaîne Ğ1 : pour. », puis confirmé sans la page | +| C33 | Le reçu de ton vote | Monnaie libre, un portefeuille : « Pour » sur Unicité du compte, « Télécharger ton reçu », « Tes bulletins » ; sur « Tes bulletins », « Fichier du reçu » : le reçu ; puis coller le reçu avec un choix changé, « Vérifier » ; une autre personne ouvre « Tes bulletins » | le reçu `recu-vote--.json` : les votes, le sel, la remarque `ld1:…`, « confirmed », l'identité « Alice » ; « Tes bulletins de vote » : « Compté pour l'identité Ğ1 « Alice » » et la remarque ; « Le reçu tient : ses votes et son sel donnent bien ce commentaire. », « Unicité du compte : pour » ; changé : « Le reçu ne tient pas » ; l'autre personne : « Tu n'as encore envoyé aucun bulletin par la chaîne Ğ1. », et le reçu lui est refusé | ## Au-delà de la liste