Fusion du lot V : le tampon des votes (ADR 0012), le vote simulé partout tant que la chaîne est fermée, marqué « simulé », qui compte puis s'efface par l'acte « supprime » ; la publication pas avant des votes prouvés
ci/woodpecker/push/app Pipeline was successful
ci/woodpecker/push/maquette Pipeline was successful

Boucle verte dans la copie du lot (98b4530 puis d57326d) : fmt, clippy,
286 tests Rust, svelte-check 0/0, 56 vitest, build, e2e 36 / 36 (C34).

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
Yvv
2026-11-03 06:16:08 +01:00
co-authored by Claude Opus 5.5
37 changed files with 2939 additions and 235 deletions
+4
View File
@@ -6,6 +6,10 @@
> 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.
> **Complétée par [0012](0012-tampon-des-votes.md)** (2026-11-02, lot V) : le bulletin en attente
> est une intention, visible aussitôt pour la personne et dans les totaux montrés (jamais dans
> l'adoption) ; la réconciliation remplace « le dernier fait foi » ligne à ligne ; sans
> `LD_VOTE_ACCOUNT`, le vote est simulé au lieu d'être fermé.
**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
@@ -6,6 +6,9 @@
> coquille d'un texte du seed validée par un administrateur sont les choix par défaut d'orch.
> Lot F, 2026-10-31. **Révisée le 2026-11-01** (décision d'Yvv, lot G) : sur une version
> retenue, on peut encore retirer son vote ou voter « contre », jamais ajouter un « pour ».
> **Révisée par [0012](0012-tampon-des-votes.md)** (2026-11-02, lot V) : un « pour » dont la
> preuve arrive sur la chaîne pendant qu'une objection retient la version est écarté ; il ne
> compte plus « tel qu'il est signé ».
**Contexte.** Le signalement de contradiction (0004) bloquait l'entrée en vigueur sans dire à
qui revenait le geste suivant, et une coquille corrigée par n'importe qui changeait le texte
@@ -37,7 +40,8 @@ d'un autre sans lui demander. Yvv, 2026-10-30 :
direct, vote groupé, bulletin de la chaîne : `409 objection`, et une ligne refusée refuse tout le
vote). La version ne peut que perdre des voix tant qu'elle est retenue ; à la levée, elle
n'entre qu'avec les voix encore là. Les votes déjà faits restent ; un bulletin scellé avant
l'objection et confirmé après compte tel qu'il est signé, sans la faire entrer. Règle :
l'objection et confirmé après compte tel qu'il est signé pour « contre » et le retrait ; son
« pour » est écarté (0012). Règle :
`ld_engine::objection::may_cast`, appliquée par `DocState::admits`.
- Une personne n'a qu'une objection debout sur une même paire (`objection_exists`).
- **L'auteur de la version retenue répond** : pour une redite, il **modifie l'article visé**
+296
View File
@@ -0,0 +1,296 @@
# 0012 — Le tampon des votes : l'intention tout de suite, la preuve de la chaîne, la réconciliation
> Complète [0008](0008-vote-par-transaction.md) (vote par la chaîne Ğ1) et révise une phrase de
> [0010](0010-objections-et-coquilles-validees.md) (un bulletin scellé avant une objection et
> confirmé après). Demande d'Yvv du 2026-11-02. **Deux décisions d'Yvv font foi** : le poids
> d'un vote simulé, « Il compte, puis s'efface » (2026-11-02, 06 h 26), et la publication d'un
> texte entré par des votes simulés, « Pas avant des votes prouvés » (2026-11-03, formulaire d'orch). La
> façon de compter une intention et ce qu'on dit quand elle est écartée restent les choix du lot
> V, isolés dans `ld_engine::buffer` pour être changés seuls. Se lit avec
> [0013](0013-quorum.md) (le quorum, jugé sur les totaux montrés). Lot V, 2026-11-02 et 03.
**Contexte.** Yvv, 2026-11-02 : « Simule le vote à tout endroit. […] du point de vue de
l'architecture, il faut prévoir le "tampon" entre la base des votes et la mise à jour par les
indexeurs de la chaîne. Il faut prévoir le bon process pour une ux moderne "je vois ce que j'ai
fait sans attendre", avec un contrôle a posteriori de l'intégrité du vote (bien unique, bien le
dernier qui vaut). » Et ses décisions déjà prises : une personne, une voix, autant de fois
qu'elle veut, le dernier vote fait foi ; dans Monnaie libre l'intégrité vient de la chaîne Ğ1
(0,1 Ğ1 par vote, un seul geste, un bulletin scellé) ; les totaux se voient en direct et
**chacun voit son propre vote en direct** (« tout le monde a maintenant cette habitude,
difficile de régresser ») ; rien n'est dit à l'écran du recoupement entre la chaîne et les
totaux ; sur une version retenue par une objection, « contre » et retrait, jamais « pour ».
Jusqu'ici, dans Monnaie libre, un bulletin restait « en attente » sans rien compter jusqu'à ce
que l'indexeur le confirme (6 à 30 secondes, une journée au plus par Ğecko), et sans
`LD_VOTE_ACCOUNT` le vote était éteint (« pas encore ouvert »). Un bulletin scellé avant une
objection et payé après comptait « pour » (relevé par une relecture).
## Décision
### Le cheminement d'un vote : trois temps
```
geste ──► INTENTION ──────────► PREUVE ─────────────► RÉCONCILIATION ──► votes (ce qui compte)
ballots (pending) la chaîne, lue par ld_engine::buffer
visible aussitôt l'indexeur ; ou le ::reconcile, par
(ton vote, totaux) confirmateur simulé identité et version
│
└── jamais prouvée dans sa fenêtre, refusée par la chaîne,
dépassée, « pour » prouvé sur une version retenue : ÉCARTÉE
```
1. **L'intention** est le geste lui-même : un bulletin scellé (`ballots`, `ballot_lines`,
0008), un seul pour tout un panier. Elle est écrite **avant** que le portefeuille signe et se
voit **aussitôt** : pour la personne (« ton vote », état `pending`) et dans les totaux
montrés (`DocState::shown_tally`). Rien n'est parti (refus du portefeuille, nœud muet,
fenêtre fermée avant la signature) : la page la lâche aussitôt (`DELETE`, 0008) et elle
disparaît des totaux. Un code Ğecko montré est gardé, comme avant.
2. **La preuve** vient de la chaîne, lue par l'indexeur, sans rien changer à 0008 : la
remarque exacte, le virement du signataire vers le compte des votes, une identité Ğ1 membre
au moment de la confirmation, un bloc définitif. Pendant la simulation (plus bas), un
**confirmateur simulé** tient la place de l'indexeur.
3. **La réconciliation** a lieu à chaque preuve, pour chaque version du bulletin, et pour
l'identité qui a signé : elle relit **toutes** les lignes prouvées de cette identité sur
cette version et en tire la voix qui tient (`ld_engine::buffer::reconcile`, pur, testé) :
- **une seule voix par identité Ğ1** et par version ;
- **la dernière dans l'ordre de la chaîne** (le bloc, puis le rang de l'évènement), quel que
soit l'ordre dans lequel l'indexeur les a lues : le résultat ne dépend pas de l'ordre des
confirmations ; « retirer mon vote » (`none`) qui tient efface la voix ;
- elle **écarte** : ce que la chaîne ne confirme jamais dans la fenêtre de validité (24
heures, plus une heure de grâce si l'indexeur se tait ou si le bloc n'est pas encore
définitif : `expired`) ; ce que la chaîne refuse (`refused` : pas d'identité, pas membre,
virement manquant) ; ce qu'un vote plus récent de la même identité a dépassé
(`superseded`) ; et **un « pour » dont la preuve arrive pendant qu'une objection retient la
version** (`objection`, voir plus bas).
Chaque ligne d'un bulletin prouvé porte son issue (`ballot_lines.outcome` : `counted`,
`superseded`, `objection`), recalculée à chaque réconciliation sauf `objection`, fixée au
moment de la preuve. La table `votes` reste ce qui compte : une ligne par identité et par
version, écrite par la réconciliation (sources `chain`, `simulated`) ou par le serveur dans
un groupe géré (`server`). Chaque vote compté se vérifie toujours contre la chaîne en
recalculant H depuis les lignes et le sel (0008).
**Dans un groupe géré** (essai, Axiom…), il n'y a pas de tampon : le serveur est l'autorité, le
vote est écrit d'un coup et il est enregistré (`recorded`) dès l'écriture, comme avant.
### Les états d'un vote, et ce que chacun pèse
| État | Ce que c'est | `myVoteState` | Totaux montrés (`shown_tally`) | Adoption (`tally`) |
|---|---|---|---|---|
| enregistré | prouvé par la chaîne, ou vote du serveur d'un groupe géré | `recorded` | oui | oui |
| en attente | une intention sans preuve, dans sa fenêtre | `pending` | oui, **à la place** du vote que la personne voit comme le sien ; jamais un « pour » sur une version retenue | **jamais** |
| simulé | un vote de la simulation, chaîne fermée | `simulated` | oui, **jusqu'à l'acte « supprime »** | oui, **jusqu'à l'acte « supprime »** (décision d'Yvv, « Il compte, puis s'efface ») |
| écarté | expiré, refusé, dépassé, « pour » sur une version retenue | — | non | non |
- **L'adoption ne compte jamais une intention non confirmée.** Une entrée en vigueur ne repose
que sur des votes prouvés, sur les votes du serveur dans un groupe géré, et sur les votes
simulés jusqu'à l'acte qui les écarte (plus bas). Le balayage d'adoption et la mesure de la
participation p̃ lisent les mêmes poids (`ld_engine::buffer::Rules`).
- **Le quorum se juge sur les totaux montrés** (ADR 0013) : l'évaluation qu'on montre
(`evaluation` : `quorum`, `yesNeeded`, `noNeeded`, `missing`) et les cinq crans du détail se
calculent sur `shown_tally` — votes enregistrés, en attente et simulés, l'intention à la place
du vote vu de la personne (`DocState::shown_evaluation`) ; l'adoption, sur `tally`
(`DocState::evaluation`).
- **Une intention compte pour la session qui l'a demandée** : elle remplace, dans les totaux
montrés, le vote que cette session voit comme le sien (`my_votes`), et la dernière intention
de la session sur une version remplace les précédentes. Une intention sur une révision
dépassée ne compte pas (elle serait « à reconfirmer ») mais retire bien le vote d'avant ; un
« pour » en attente sur une version retenue ne pèse rien tant qu'elle est retenue (il serait
écarté) : `ld_engine::buffer::weigh_intent`.
- `tallyPending` dit la part des totaux montrés qui attend encore sa preuve ; `tallySimulated`
la part qui vient de la simulation. Les textes publiés (`publish.rs`) ne publient jamais une
intention : ils lisent `recorded_tally` (ce qui est enregistré, simulation comprise tant
qu'elle compte), ou `tally` pour les articles en vigueur, comme avant ; et rien ne part tant
qu'une entrée due à des votes simulés ne tient pas sur les seuls votes prouvés (« La
publication », plus bas).
### Ce que la personne voit, à chaque étape
| Étape | Sous l'article (`myVote`, `myVoteState`, `myBallot`) | Totaux | Boîte « Messages » |
|---|---|---|---|
| elle vote (groupe géré) | son choix, `recorded` | aussitôt | — |
| elle vote, la chaîne ouverte | son choix, `pending` ; « En attente de la chaîne Ğ1 : … » | aussitôt, avec son choix | — |
| la chaîne le confirme | son choix, `recorded` ; « inscrit sur la chaîne Ğ1 » | inchangés (l'intention devient preuve) | — |
| rien n'est parti (portefeuille, nœud, fenêtre fermée) | son vote d'avant | son intention retirée | — |
| jamais vu sur la chaîne en 24 h | son vote d'avant ; « Ton dernier vote n'a pas été vu sur la chaîne Ğ1 à temps » | son intention retirée | « Ton vote … n'a pas été vu sur la chaîne Ğ1 en 24 heures : il est écarté. Tu peux voter à nouveau. » |
| refusé par la chaîne | son vote d'avant ; « Ton dernier vote n'a pas été compté : … » | son intention retirée | « Ton vote … n'a pas été compté : … » |
| un « pour » prouvé sur une version retenue | son vote d'avant ; « Ton dernier vote n'a pas été compté : une objection retenait cette version… » | inchangés | « Ton « pour » sur … est écarté : une objection retenait cette version quand la chaîne a confirmé ton vote. Ton vote d'avant reste. » |
| dépassé par un vote plus récent de la même identité | le plus récent | le plus récent | — (c'est son propre geste) |
| elle vote, la chaîne fermée (simulation) | son choix, `simulated` | aussitôt | — |
Rien n'est dit à l'écran sur le recoupement entre la chaîne et les totaux (décision d'Yvv).
Un message n'offre aucun geste : il dit ce qui s'est passé et mène au texte, où l'on revote.
### La simulation, tant que la chaîne est fermée
Sans `LD_VOTE_ACCOUNT`, on vote **quand même, partout, dans Monnaie libre**, sans portefeuille :
le bouton de vote s'affiche (l'accès dit `open: true`, `simulated: true`, `way: "server"`), le
vote part par l'écriture du serveur (`POST /api/proposals/{id}/vote`, `POST
/api/docs/{id}/votes`) et passe **par le même tampon** : un bulletin scellé (`ballots.mode =
'simulated'`, son sel et son empreinte, sans compte ni montant), puis le **confirmateur simulé**
le prouve aussitôt, dans la même requête (et le balayage reprend un bulletin simulé resté en
attente) : la voix est celle de **l'identité de la session** (il n'y a pas de portefeuille), sa
position est « bloc 0 », au rang de son arrivée ; puis la même réconciliation, le même
balayage d'adoption, les mêmes messages. L'architecture est ainsi éprouvée de bout en bout, en
production, sans la chaîne. Qui peut voter en simulation : la règle de trustinWallet,
`trustin_access::casts_simulated` (qui ouvre le groupe, la chaîne fermée) — une personne
invitée comprise.
**La décision d'Yvv, 2026-11-02 à 06 h 26 : « Il compte, puis s'efface ».**
- **Il compte.** Un vote simulé compte dans les totaux et **pour l'entrée en vigueur**, comme un
vote prouvé, avec la marque « simulé » (`myVoteState`, `tallySimulated`, `mode` du bulletin,
« Tes bulletins »). Avec les quorums de l'ADR 0013, neuf « pour » simulés suffisent à faire
entrer I1, E1 ou E2 au cran 2 (quorum 12) : le texte est alors en vigueur sur le site, et ne
se publie pas (« La publication », plus bas). La règle : `ld_engine::buffer::SIMULATED_ADOPTS
= true`, reprise par `Config::simulated_adopts` ; à `false`, « simulé = affiché, jamais compté
pour l'adoption » (les totaux montrés ne changent pas, l'adoption et p̃ les ignorent). Les deux
branches sont testées.
- **L'ouverture de la chaîne n'efface rien d'elle-même.** Dès que `LD_VOTE_ACCOUNT` est posé
(un acte « déploie »), on vote par la chaîne : un nouveau vote simulé est refusé (`409
chain_only`). Les votes simulés déjà là **continuent de compter**, marqués, jusqu'à l'acte qui
suit. Une identité Ğ1 (une session ouverte par la clé Ğ1, `idty:<index>`) qui vote ensuite
par la chaîne passe devant son vote simulé (bloc 0, avant tout bloc réel).
- **Puis il s'efface, par un acte « supprime » d'Yvv**, jamais déclenché par le code : ni le
serveur, ni l'ouverture de la chaîne, ni un balayage ne l'appellent. Il est préparé et testé
ici : `simulation::discard`, en ligne de commande dans l'image :
```sh
ld-server discard-simulation # à blanc : dit ce qu'il ferait, n'écrit rien
ld-server discard-simulation --apply # l'acte
```
Il lit la base du volume (`LD_DATA_DIR`, `libredecision.db`) et imprime un JSON : les
bulletins, lignes, votes et messages simulés, et chaque entrée réexaminée (article, sorte,
votes d'entrée et leur part simulée, votes prouvés, « pour » exigés, tient ou non, rendue ou
non, la version déplacée). Avec `--apply` :
1. **le tri** : il efface les messages des bulletins simulés, les votes simulés
(`votes.source = 'simulated'`), leurs lignes et les bulletins simulés, puis réconcilie de
nouveau chaque identité qui avait voté en simulation (son vote prouvé, s'il y en a un,
tient) ;
2. **le réexamen** : chaque entrée en vigueur qui a compté des votes simulés
(`adoptions.params.simulated`), la plus récente d'abord, encore en vigueur, est jugée de
nouveau sur les seuls votes prouvés, au cran et sur le quorum où elle a été votée
(`params.level`, `params.quorum`). **Sous son seuil, elle retourne parmi les
propositions** : la version qu'elle avait déplacée revient en vigueur (un texte retiré
revient, un cran d'inertie redescend, l'ordre et le titre d'avant s'appliquent de
nouveau), son adoption est effacée, une publication est mise en file. **À son seuil ou
au-dessus, elle reste**, et son adoption le dit (`params.reexamined`) ;
3. les envois en attente de la publication repartent.
Répété, l'acte ne trouve plus rien (aucun bulletin simulé, aucune entrée à réexaminer).
**À blanc**, le réexamen met les votes simulés de côté sans les effacer : une entrée qui ne
reviendrait qu'après le retour d'une plus récente est dite « plus en vigueur ».
- Pour les tests seulement, et seulement avec la connexion de développement, `POST
/api/dev/vote-chain {"open": false}` ferme la chaîne d'un serveur qui en a une (le contrôle
e2e de la simulation tourne sur le serveur jetable des e2e, qui a sa chaîne simulée).
### La publication : « Pas avant des votes prouvés »
**La décision d'Yvv, 2026-11-03 (formulaire d'orch) : « Pas avant des votes prouvés ».** Un texte qui
entre en vigueur grâce à des votes simulés est **en vigueur sur le site**, mais **ne déclenche
pas la publication** vers le dépôt des textes, que lisent les applis clientes. La publication
d'un document attend que tout ce qui y est en vigueur et y est entré par des votes simulés —
texte, retrait, cran d'inertie, ordre, titre — **tienne sur les seuls votes prouvés**, selon le
réexamen même de l'acte « supprime », fait à blanc (`simulation::unproven`). La chaîne étant
fermée, **rien ne se publie dans Monnaie libre avant son ouverture** ; après elle, la file part
dès que l'acte a rendu ce qui ne tient pas, ou dès que des votes prouvés portent ce qui est
entré.
- Un seul endroit : `publish::waits_for_proven_votes`, après `publish::waits_for_a_text` (ADR
0011), tous deux lus par `publish::waits`. Comme pour l'attente du premier texte, ce n'est pas
un échec : aucune tentative comptée, la file attend et se relit toutes les dix minutes ; l'API
dit `publication.state = "suspended"` et `publication.waitsFor = "proven"` (`"text"` pour
l'attente du premier texte).
- La bascule, pour publier quand même si Yvv revenait sur ce choix : `LD_PUBLISH_SIMULATED=1`
(`Publish::simulated`). Testé dans les deux sens.
- Plus strict qu'« un texte prouvé suffit » : tant qu'une entrée simulée ne tient pas, même un
texte prouvé du même document attend, pour que le dépôt ne porte jamais une entrée que les
votes prouvés ne portent pas.
### Un « pour » prouvé pendant une objection (révise 0010)
0010 disait : « un bulletin scellé avant l'objection et confirmé après compte tel qu'il est
signé, sans la faire entrer ». Une relecture a relevé qu'un « pour » entrait ainsi sur une
version qui ne doit plus en prendre. Désormais, **un « pour » dont la preuve arrive pendant
qu'une objection retient sa version est écarté** (`objection`) : il ne compte pas, comme s'il
n'avait pas été émis ; le vote d'avant de la même identité, s'il y en a un, reste ; la personne
qui l'a demandé reçoit un message. « Contre » et retrait, prouvés pendant l'objection, comptent
(Yvv, 01/11 : « Retirer ou "contre" »). « Arrive » se lit à l'heure du serveur qui lit la
preuve : la chaîne ne donne que des blocs, et l'objection une heure. Une objection levée avant
la preuve laisse le « pour » compter.
### « Un vote existe » (ADR 0013)
Le quorum d'un article se fixe avant le premier vote (`quorum::voted_units`, la seule
requête). Le tampon gardant l'historique des bulletins, elle compte : un vote qui compte
(serveur, chaîne, **simulé**) ; toute ligne d'un bulletin **en attente** ou **prouvé**, de la
chaîne ou de la simulation, **quel que soit son sort** (la voix qui compte, un vote dépassé, un
« pour » écarté par une objection, **un retrait**) ; une adoption. Un vote retiré sur la chaîne
ou en simulation laisse donc sa trace. Un bulletin lâché sans signature, jamais vu à temps ou
refusé par la chaîne n'est pas un vote. Deux limites : dans un groupe géré, sans tampon, un vote
retiré avant toute adoption ne laisse rien (ADR 0013) ; l'acte « supprime » emporte la trace des
votes simulés avec eux.
### L'API, contrat partagé avec les lots U et S
Dans le JSON d'une proposition (`GET /api/docs/{id}`, `GET /api/proposals/{id}`) :
- `tally: {for, against}` — les totaux montrés, intentions comprises ;
- `tallyPending: {for, against}` — la part encore sans preuve ;
- `tallySimulated: {for, against}` — la part simulée (ajouté) ;
- `evaluation` — sur les totaux montrés (ADR 0013 : `quorum`, `yesNeeded`, `noNeeded`) ;
- `myVote: 'for' | 'against' | null` — ce que la personne voit comme son vote maintenant : son
dernier geste, une intention en attente comprise (un retrait en attente : `null`) ;
- `myVoteState: 'recorded' | 'pending' | 'simulated' | null` ;
- inchangés : `myVoteStale`, `myVoteChain`, `myBallot` (qui peut dire `status: 'refused'`,
`reason: 'objection'` pour un « pour » écarté).
Dans l'accès (`vote` du JSON du document) : `{ way, open, simulated, reason, chain }` ;
pendant la simulation, `way: "server"`, `open: true`, `simulated: true`, `chain: null`. Un
vote écrit par le serveur répond `{ entered, simulated }` (et `count` pour un vote groupé).
Les bulletins (`GET /api/ballots/{id}`, `GET /api/ballots`, le reçu) gagnent `mode: 'chain' |
'simulated'` (le bloc d'un bulletin simulé n'est jamais montré). Les messages gagnent le sujet
`ballot`, de sortes `ballot_expired`, `ballot_refused`, `ballot_objection`, avec `ballot: {id,
status, reason, mode, createdAt, settledAt, lines: [{proposalId, unitId, code, title, choice,
outcome}]}`. La publication d'un document (`doc.publication`) gagne `waitsFor: 'text' |
'proven' | null`.
## Les données
Migration `0010_vote_buffer.sql`, additive (S a pris `0009` et `0011` ; les trois passent dans
l'ordre sur une base neuve comme sur une base arrêtée à `0008`, la production) :
- `ballots.mode TEXT NOT NULL DEFAULT 'chain'` (`chain` | `simulated`) : tous les bulletins
d'avant restent des bulletins de la chaîne ;
- `ballot_lines.outcome TEXT` (`counted` | `superseded` | `objection`, `NULL` tant que le
bulletin n'est pas prouvé ; les lignes d'avant restent à `NULL` et se lisent comme « pas
écartée par une objection » : la prochaine réconciliation de leur identité les qualifie) ;
- un index `ballots(doc_id, status)` pour lire les intentions d'un document ;
- `votes.source` prend une valeur de plus, `simulated` (colonne texte, rien à changer) ;
`messages.topic` aussi, `ballot` ; `adoptions.params` (JSON) garde de plus, pour l'acte, la
part simulée des votes d'entrée (`simulated`), la version déplacée (`displaced`), le cran
d'avant (`from_inertia`), et après l'acte `reexamined`.
Aucune ligne existante n'est réécrite, et le premier démarrage n'écrit rien du tampon (la
chaîne fermée en production : aucun bulletin). La purge (0008) efface avec un bulletin lâché
les messages qui en parlent.
## Coût
- **Les totaux montrés sont provisoires** le temps de la preuve : une intention compte pour la
session qui l'a demandée. Si une même identité vote depuis deux sessions à la fois, ou si une
session signe avec un autre portefeuille que celui de son vote précédent, les totaux montrés
peuvent s'écarter d'une voix jusqu'à la preuve ; la réconciliation remet le compte juste. Une
personne qui ouvre Monnaie libre peut faire paraître une voix dans les totaux montrés pendant
24 heures sans payer (une par session et par version, 20 bulletins au plus) : elle ne compte
jamais pour l'adoption.
- L'intention compte dès que le bulletin est scellé, quelques secondes avant la signature ; si
rien ne part, la page la lâche aussitôt.
- Un « pour » payé juste avant une objection mais lu juste après (l'indexeur suit à quelques
secondes) est écarté : la personne revote à la levée.
- **La simulation rend possible deux voix pour une personne** (une session par invitation, une
session Ğ1), ce que la chaîne empêche : accepté tant qu'elle dure, et effacé par l'acte
« supprime ». Chaque geste simulé laisse un bulletin en base jusqu'à l'acte.
- **Un texte entré par des votes simulés se lit en vigueur sur le site sans être publié** ; le
dépôt des textes garde la dernière publication jusqu'aux votes prouvés. L'acte peut faire
retourner parmi les propositions un texte que des personnes ont lu en vigueur.
- Un message sur un bulletin lâché disparaît avec lui à la purge (une semaine).
+1
View File
@@ -16,4 +16,5 @@ pas une décision : on en écrit une nouvelle qui la remplace, et on le note dan
| [0009](0009-modules-ordre-et-titre.md) | Les modules : l'ordre des articles de chaque section (inertie 2), le titre du document (inertie 4) | 2026-10-31 |
| [0010](0010-objections-et-coquilles-validees.md) | Objections « redit » / « contredit », coquilles validées, messagerie (remplace 0004, complète 0003) | 2026-10-31 |
| [0011](0011-propositions-seed.md) | Les Propositions seed : rien en vigueur au départ, trois textes mis en avant au cran 2, la publication attend le premier texte (complète 0002) | 2026-11-02 |
| [0012](0012-tampon-des-votes.md) | Le tampon des votes : l'intention visible tout de suite, la preuve de la chaîne, la réconciliation a posteriori ; la simulation tant que la chaîne est fermée (complète 0008, révise 0010) | 2026-11-02 |
| [0013](0013-quorum.md) | Le quorum par cran (12 · 12 · 50 · 50 · 50), fixé par l'auteur avant le premier vote ; sous le quorum, les votants qui manquent comptent comme « non » (remplace le C de 0002 et 0007) | 2026-11-03 |
@@ -49,6 +49,7 @@ pour une personne, ils coûtent 0,1 Ğ1 réels : c'est un acte « paye » d'Yvv.
| C31 | Coquille sur un texte en vigueur | groupe d'essai : une administratrice (Ada) ouvre le groupe ; Vera, sur « Raison d'être » → « Le vote » → « Coquilles, traductions, objections, historique » → « Corriger une coquille », « C'est le seul » → « C’est le seul » ; Ada ouvre « Messages » → « Valider » | chez Vera : « Ta correction attend un administrateur, ce texte venant du seed… » ; le texte en vigueur ne change pas (« C'est le seul ») ; la correction en attente se lit dans « Détails » ; chez Ada : « Vera propose une correction de coquille dans « Raison d'être », un texte du seed : un administrateur la valide. » ; après « Valider », le texte en vigueur porte « C’est le seul » et l'historique « validée par Ada » |
| C32 | Lâcher ou garder un bulletin | Monnaie libre, un portefeuille dans le navigateur (Eve, chaîne simulée), « Propositions en cours » → Document de révocation : « 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 : « Contre » → « 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 : contre. », puis confirmé sans la page |
| C33 | Le reçu de ton vote | Monnaie libre, un portefeuille : « Contre » sur Ne jamais certifier seul (« Propositions en cours »), « 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-<date>-<id>.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. », « Ne jamais certifier seul : contre » ; 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é |
| C34 | Le vote simulé, la chaîne fermée (ADR 0012) | Monnaie libre sur un serveur sans compte des votes (l'automate ferme la chaîne du serveur jetable, puis la rouvre) : « Propositions en cours » → Logiciel auditable → « Contre », sans portefeuille ; puis « Tes bulletins » | « Voter en lot » est là ; aucune fenêtre de portefeuille ; « Ton vote : contre » aussitôt, et un « contre » de plus dans les totaux ; dans l'API, `myVoteState` « simulated » et `tallySimulated` ; dans « Tes bulletins » : « Simulé : compté pour « Sacha » jusqu'à l'ouverture de la chaîne Ğ1 », sans bloc |
## Au-delà de la liste