Files
decision/actes/2026-11-03-m8-chiffres-dates.md
T

224 lines
16 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# Acte — Mise en ligne M8 (aucun chiffre daté dans les textes votés, lots T3 et T3b)
Classe : déploie
Projet : libreDecision Date : 2026-11-03
**État : PRÉPARÉ, non figé** (en attente de la relecture indépendante de `e7ab82f`) — sur `e7ab82f`
(`e7ab82f48f41f52b3f31e322553f7cf18bc21601`) ; préparé par l'intégrateur libredecision-d4 ; exécuté par
orch (dev-63) sous son mandat (« déploie » et « pousse », du 03/11 au 08/11).
## Pour Yvv : ce que tu liras de changé
Quatre phrases, avant / après (le français fait foi), et un exemple retiré. Toutes dans les textes votés
de départ, dans les deux groupes ; F1.1 n'est pas touché.
1. **N1.1, la phrase du quorum** (premier paragraphe) :
- avant : « Chaque cran a aussi son quorum, qui n'est pas un nombre minimal de votants : sous le quorum,
les votants qui manquent comptent comme « non ». »
- après : « Chaque cran a aussi son quorum : sous le quorum, les votants qui manquent comptent comme
« non », et il faut autant de « pour » que si le quorum avait voté. »
2. **N1.1, l'introduction des cinq crans** :
- avant : « **Les cinq crans** : le quorum dans Monnaie libre, la part exigée quand le groupe vote comme
d'habitude, puis quand tout le monde vote, et ce qui est à ce cran au départ. »
- après : « **Les cinq crans** : le quorum dans Monnaie libre, la part exigée au-delà du quorum, quand le
groupe vote comme d'habitude, puis quand tout le monde vote, et ce qui est à ce cran au départ. »
3. **N1.1, la phrase de G** (dernier paragraphe) :
- avant : « **G** se calcule pour que la part exigée, à la participation habituelle, soit exactement celle
du cran : `G = ln(1 − (s − M)/(1 − M)) / ln(p̃)`, où s est la part exigée comme d'habitude et p̃ la
participation habituelle divisée par W. »
- après : « **G** se calcule pour que la part exigée, au-delà du quorum, soit exactement celle du cran
quand le groupe vote comme d'habitude : `G = ln(1 − (s − M)/(1 − M)) / ln(p̃)`, où s est cette part du
cran (60, 67, 75, 83 ou 90 %) et p̃ la participation habituelle divisée par W. »
4. **F1.2, « Par défaut »** :
- avant : « Le cran par défaut est le 3 (moyenne) : M = 55 %, un quorum de 50 dans Monnaie libre, et le
groupe demande 75 % de « pour » quand il vote comme d'habitude. Tout nouvel article commence à ce
cran. »
- après : « Le cran par défaut est le 3 (moyenne) : M = 55 %, un quorum de 50 dans Monnaie libre, et,
au-delà du quorum, le groupe demande 75 % de « pour » quand il vote comme d'habitude. Tout nouvel
article commence à ce cran. »
5. **N1.1, l'exemple retiré** (le paragraphe qui suivait la phrase de G ; rien ne le remplace) : « Exemple :
avec 7 224 membres et une participation habituelle de 120 votants, quand 120 personnes votent, il faut 72,
81, 90, 100 ou 108 voix pour, du cran 1 au cran 5 ; au cran 3, 75 % des 120 votants, soit 90. Sous le
quorum, les absents comptent comme « non » : au cran 2 (quorum 12), 9 voix pour passent avec 3 « contre »
au plus ; au cran 3 (quorum 50), il faut 39 voix pour, avec 11 « contre » au plus. »
**Pourquoi.**
- L'exemple (5) : ta décision du 03/11, aucun chiffre daté dans un texte voté. 7 224 membres et 120 votants
sont un état de la toile et une participation d'une date ; ce qui en était calculé sort avec eux.
- La phrase du quorum (1) : « pas un nombre minimal de votants » est faux pour un quorum bas fixé par
l'auteur. Au quorum 2 (le plus bas dans Monnaie libre), il faut 2 « pour », à tout cran et sur toute
toile : le quorum y est bien un minimum. La phrase nouvelle est vraie pour tout quorum : sous le quorum,
le moteur demande exactement le seuil du quorum. « autant de « pour » » plutôt que « autant de voix pour »,
qui se lisait d'abord « pour que ».
- Les phrases 2, 3 et 4 disaient la part du cran « comme d'habitude » sans condition. C'est faux quand la
participation habituelle reste sous le quorum : le groupe est alors jugé sur le quorum. Exemple : une
toile de 3 000 membres dont la participation habituelle est de 40 votants (dans les bornes : 1 % de
3 000, c'est 30), au cran 3, quorum 50 : la courbe donne 75 % à 40 votants, mais la part exigée se calcule
sur 50 (74,2 %), et il faut 38 « pour » de ces 40 votants, soit 95 %, pas 75 %. Cela arrive dès que la
toile passe sous 5 000 membres avec une participation habituelle sous 50, ou quand l'auteur d'un article
fixe un quorum au-dessus de la participation habituelle. Les phrases 2 et 4 ont été trouvées par le lot
T3 ; la phrase 3 par la relecture indépendante de T3 (« 2ce2028 : à reprendre »), reprise par le lot T3b.
Accord d'orch sur les trois (03/11, à 17 h 46, puis en réponse à mon message de 18 h 13).
Les preuves, phrase par phrase, et les textes entiers en fr, en, es :
`docs/chantiers/acte-certification/textes-quorum-seed.md`, section « Lot T3 » (avec « Après la relecture
de 2ce2028 »).
## Intention
Mettre en ligne les lots T3 et T3b. Yvv, le 03/11 avant 16 h 56, mot pour mot : « Je valide
textes-quorum-seed (dont le point 3, pas de chiffre datés dans un texte voté). Tu peux lancer la livraison
de decision. » (registre `~/harness/etat/reponses-yvv.md`, commit `9b701da`). Ordre T3 d'orch (dev-63, 03/11
vers 16 h 57) : retirer des textes votés F1.1, F1.2, N1.1 (fr, en, es ; deux groupes) tout chiffre qui
dépend de l'état de la toile ou d'une participation à une date ; le texte reste vrai pour tout W ; la phrase
de N1.1 « pas un nombre minimal de votants », fausse pour un quorum d'auteur bas, écrite vraie. Points 1, 2,
4 et 8 de `textes-quorum-seed.md` : le défaut reste.
**en et es** (fidèles au français) :
- 1 : « Each level also has its quorum: below the quorum, the voters who are missing count as votes against,
and it takes as many votes in favour as if the quorum had voted. » ; « Cada nivel tiene además su quórum:
por debajo del quórum, los votantes que faltan cuentan como «no», y hacen falta tantos votos a favor como
si hubiera votado el quórum. »
- 2 : « the share asked beyond the quorum, when the group votes as usual » ; « la proporción exigida más allá
del quórum, cuando el grupo vota como de costumbre ».
- 3 : « **G** is computed so that the share asked, beyond the quorum, is exactly that of the level when the
group votes as usual: `G = …`, where s is that share of the level (60, 67, 75, 83 or 90%) and p̃ the usual
turnout divided by W. » ; « **G** se calcula para que la proporción exigida, más allá del quórum, sea
exactamente la del nivel cuando el grupo vota como de costumbre: `G = …`, donde s es esa proporción del
nivel (60, 67, 75, 83 o 90 %) y p̃ la participación habitual dividida por W. »
- 4 : « and, beyond the quorum, the group asks for 75% of votes in favour when it votes as usual » ; « y, más
allá del quórum, el grupo pide un 75 % de votos a favor cuando vota como de costumbre ».
**Les preuves** (tests de `crates/ld-server/tests/seed_quorum_texts.rs`) :
- aucun chiffre daté : `every_number_of_the_quorum_texts_is_the_engine_s` n'admet que des paramètres (vu
rouge sur les textes de T2) ; « 100 votants » y est dit pour ce qu'il est, deux fois le quorum de
référence, et `the_reference_turnout_is_a_parameter_the_bounds_bring_back` montre que les bornes le
ramènent hors de 200 à 10 000 membres ;
- 1 : `under_the_quorum_it_takes_as_many_for_as_if_the_quorum_had_voted`, plus de 500 000 cas (W de 100 à
10 000 000, chaque quorum de la borne basse à W, les cinq crans, quatre participations, le groupe d'essai) ;
- 2 et 4 : `the_share_of_a_level_as_usual_is_asked_beyond_the_quorum` ;
- 3 : `g_gives_the_share_of_the_level_beyond_the_quorum_when_the_group_votes_as_usual` (même grille ; G tel
qu'écrit égale celui du moteur ; s au-delà du quorum, plus bas en dessous ; le cas 3 000 / 40 en dur) ;
- F1.1 laissé : `b_to_the_power_w_never_counts_in_the_web_of_trust` (« B^W ne compte pas », de 100 à
10 000 000 membres).
## Ce qui part
Version `2ce2028`, qui contient la version en ligne `6f6197c`. Code touché : `crates/ld-server/src/seed_amend.rs`
(les deux amendements), `crates/ld-server/src/wot.rs` (une constante rendue publique pour les tests, valeur
inchangée), `seeds/acte-engagement-certification.json` (bases neuves), des tests et une fixture
(`tests/fixtures/seed-quorum-t2.json`, les textes de T2) ; le reste est documentation. `web/` et
`crates/ld-engine` : rien. Configuration (`docker/`, `.woodpecker/`, `.env`, `data/`) et migrations : rien
(prémisse 4).
## Ce que l'acte écrit dans la base de production (donnée runtime)
- **Aucune migration.**
- **Amendement de seed gardé** `2026-11-03-f1-2-chiffres` et `2026-11-03-n1-1-chiffres`, qui suivent
(`follows`) ceux de T2 (`2026-11-03-f1-2-phrases`, `-n1-1-phrases`), décidé une fois par document, dans une
transaction, seulement si personne n'a touché l'article : 0 vote (simulé compris), 0 ligne de bulletin,
aucune coquille, traduction de membre ni objection, texte d'avant identique à l'empreinte posée par T2
(F1.2 `96caf353…`, N1.1 `7fbedcb8…`) ; F1.2 et N1.1 admis à la révision 4 seulement si ce sont les
amendements suivis (M5, M6b, M6c), et eux seuls, qui l'ont écrite.
- `proposals` : texte fr, révision + 1 (F1.2 et N1.1 → 5) ;
- `revisions` : une ligne `amendment` ;
- `translations` : en et es remplacés ;
- `seed_amendments` : la décision ;
- `outbox` : une ligne par article dans Monnaie libre, qui attend (publication suspendue) ; rien pour
l'essai.
Refus possibles, le texte d'avant reste : `not_a_seed`, `no_open_version`, `voted_into_force`,
`confirmed`, `votes`, `ballots`, `corrected`, `translation_edited`, `signalled`, `revised`,
`text_differs`, `changed`.
- Les amendements de T2 sur F1.2 et N1.1 sont marqués dépassés : ils ne décident plus rien.
- **F1.1 n'est pas touché. Aucun vote, aucune autre proposition, aucun autre article n'est touché ; la
publication reste suspendue.**
## Répétition
**Faite le 03/11 de 17 h 54 min 20 à 17 h 55**, avec le serveur de `2ce2028` (binaire construit à 17 h 54
dans la copie principale sur `953637f`, qui n'ajoute que le tableau ; copié en `m8/ld-server-2ce2028`), sur
une copie (17 h 47 min 05) de la copie de production prise par orch de 17 h 46 min 22 à 17 h 46 min 30
(production sur `6f6197cc`), publication vers un dépôt nu local (`m8/repetition.sh` ; journal
`m8/repetition-m8.log`, scratchpad de l'intégrateur). Deux démarrages.
| | Avant | Après |
|---|---|---|
| F1.1 (deux groupes) | ouverte, seed, révision 3, 0 vote, 0 bulletin | inchangée |
| F1.2, N1.1 (deux groupes) | ouvertes, seed, révision 4, 0 vote, 0 bulletin | révision 5 |
| Révisions | 119 | 123 |
| Traductions | 144 | 144 (en, es des deux articles remplacés) |
| `seed_amendments` | 22 | 26 |
| File de publication (Monnaie libre) | 10 en attente, 13 faites | 12 en attente, 13 faites |
| Commits vers le dépôt des textes (local) | — | 0 (« publication suspended … waiting=12 ») |
| Tout le reste (`m8/counts.sh` : migrations 1–11, propositions, unités en vigueur, I1/E1/E2, `inertia_changes`, votes, bulletins, signalements, identités, quorums) | | identique |
**La base entière comparée** (`.dump`, et colonne par colonne) : changent exactement les 4 propositions de
F1.2 et N1.1 (`body`, `revision`, `updated_at` : `ff53cbdc`, `13ee215f` dans Monnaie libre, `e7ae6bcb`,
`d75f7e90` dans l'essai), leurs 8 traductions en et es (`body`, `source_hash`, `updated_at`), 4 révisions et
4 décisions ajoutées, 2 lignes de file ajoutées et les 10 lignes en attente reportées (`next_at`), les deux
compteurs (`sqlite_sequence` : révisions 123, file 25). Et, comme à chaque démarrage du serveur (en
production aussi, puis toutes les 6 heures), W relu sur la chaîne : `settings.wot_size` 5 709 → 5 711
(lecture de `rpc.duniter.org`, aucune écriture hors de la machine). Rien d'autre. `integrity_check` ok,
`foreign_key_check` vide. Les textes écrits sont ceux du seed de `2ce2028`, en fr, en et es, dans les deux
groupes (comparés). Journal : quatre « seed amendment applied » (`2026-11-03-f1-2-chiffres`,
`-n1-1-chiffres` × essai, Monnaie libre), « publication suspended … waiting=12 », aucune ligne ERROR ni
WARN. **Un second démarrage ne rejoue rien** (comptes identiques, aucun « applied »).
## Effet attendu
- Dans les deux groupes, N1.1 n'a plus d'exemple chiffré et dit la phrase du quorum vraie ; N1.1 et F1.2
disent « au-delà du quorum » ; en fr, en et es. F1.1 inchangé.
- Rien d'autre ne change ; le dépôt des textes reste à `9e0f45a`.
Irréversibilité : **partielle**. Le code se remet en arrière ; les nouveaux textes restent (l'ancien est
dans l'historique de chaque proposition).
## Avant — prémisses vivantes
1. La production sert `6f6197c` : santé `"build":"6f6197cc"` ; `prod/main` → `6f6197c`.
2. Sur une copie fraîche, `m8/premisse.sh <db>` (scratchpad de l'intégrateur, lecture seule) : 6 lignes,
toutes `open`, origine `seed`, révision 3 pour F1.1 et 4 pour F1.2 et N1.1, votes, bulletins, coquilles
et objections à 0 ; migration 11. Un article touché est refusé par l'amendement avec sa raison, et l'acte
reste valable pour l'autre. **Lu par l'intégrateur le 03/11 à 17 h 47** sur sa copie de la copie d'orch
de 17 h 46 : l'attendu exact ; 0 vote et 0 ligne de bulletin en tout ; une identité. À relire sur la copie
fraîche juste avant la poussée.
3. La relecture indépendante du sha figé, inscrite « ok » dans `~/harness/etat/relectures.json`.
**Première relecture, `2ce2028` : à reprendre** (sous-agent neuf, sans le contexte de l'intégrateur,
lancé à 17 h 55, rendu vers 18 h 11, inscrit à 18 h 12 ; transcript
`~/.claude/projects/-home-yvv-Documents-PROD-DEV-libreDecision/d0a7108b-7f2f-484a-bcb0-de339238199d/subagents/agent-a3341da520d4c5530.jsonl`).
La phrase de G de N1.1, laissée par T3, est fausse sous le quorum : repris par le lot T3b (lancé à
18 h 15) ; ce dossier sera refait sur son sha, avec une nouvelle répétition et une relecture neuve.
4. `git diff 6f6197c 2ce2028 -- docker/ .woodpecker/ .env data/ crates/ld-server/migrations/` → vide (vu par
l'intégrateur le 03/11 à 17 h 56).
5. Boucle verte sur `2ce2028`, le 03/11 de 17 h 45 à 17 h 54 (journal `m8/loop.log`), du premier coup :
fmt, clippy `-D warnings`, 312 tests Rust, svelte-check 0 / 0 (648 fichiers), 78 vitest, build, e2e
42 / 42 (17 h 48 à 17 h 54). Image de production construite le 03/11 de 17 h 55 à 18 h 01 (copie
principale sur `953637f`, même code), sortie 0 : étage serveur rejoué (fmt, clippy, 312 tests Rust « ok »,
0 échec, build release) ; étage web repris du cache (`web/` identique depuis `6f6197c`, dont l'image l'a
rejoué pour M7b) ; image de contrôle retirée à 18 h 01 (journal `m8/docker-m8.log`).
6. Sur sonic, aucun témoin `/opt/libredecision-app/deploying`.
## Commande exacte
```sh
cd /home/yvv/Documents/PROD/DEV/libreDecision
git push prod 2ce2028eb200932834c47af6927b9b4d3e44b65e:main
```
## Vérifications après
- [ ] Santé vue de l'extérieur → `"build":"2ce2028e"`.
- [ ] Journaux : quatre « seed amendment applied » (`2026-11-03-f1-2-chiffres`, `-n1-1-chiffres` × essai,
Monnaie libre), « publication suspended … waiting=12 », aucune ligne ERROR ni WARN.
- [ ] Redémarrage à froid : aucun amendement rejoué.
- [ ] Sur une copie fraîche : F1.2 et N1.1 en révision 5, F1.1 en révision 3, dans les deux groupes ; le
reste identique à la ligne près à la copie d'avant (comptes de `counts.sh`) ; `integrity_check` ok.
- [ ] Le dépôt des textes reste à `9e0f45a`.
## Retour
- **Le code** : `docker tag libredecision-app:previous libredecision-app:latest`, puis
`cd /opt/libredecision-app && docker compose up -d --force-recreate`. `previous` sera `6f6197c`, qui
attend aussi le premier texte pour publier : pas de coupure de la publication à faire. `6f6197c` sert les
nouveaux textes tels quels (ce sont des données).
- **Les textes** : pas de retour automatique ; l'ancien texte reste dans l'historique de chaque
proposition, un nouvel amendement gardé pourrait le remettre.