Lot T2 : les trois phrases de F1.1, F1.2 et N1.1 écrites justes (la part du cran, la plus haute au quorum, baisse quand la participation monte ; le quorum se fixe tant que l'article ne garde la trace d'aucun vote ; le quorum n'est pas un nombre minimal de votants), dans le seed et par un amendement gardé qui suit celui de M6b

- seed_amend : 2026-11-03-f1-1-phrases, -f1-2-phrases, -n1-1-phrases ; la garde admet la révision écrite par la chaîne des amendements suivis (earlier), dans leur ordre, le dernier étant celui de M6b (F1.1 en révision 2, F1.2 et N1.1 en révision 3) ; les amendements de M6b dépassés ; le commentaire dit les deux votes qui ne laissent pas de trace (vote direct retiré dans le groupe d'essai, votes simulés après « supprime »)
- tests : base faite comme la production après M6b (fixture seed-quorum-m6b.json), appliqué une fois, refus votes et ballots, second démarrage sans rejeu, base née le 02/11 ; les phrases et leur preuve par le moteur ; le quorum de nouveau réglable après un vote direct retiré et après « supprime »
- moteur : la part exigée au quorum en production (W 5 707) : 64,4 · 73,5 · 77,4 · 85,3 · 91,9 % (la relecture disait 74 au cran 2)

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
Yvv
2026-11-03 10:12:12 +01:00
co-authored by Claude Opus 5.5
parent f6c110a60c
commit a32912373d
8 changed files with 811 additions and 92 deletions
+30 -1
View File
@@ -248,7 +248,7 @@ pub fn quorum_bounds(electorate: u32, test_group: bool) -> (u32, u32) {
#[cfg(test)]
mod tests {
use super::*;
use crate::threshold::required_ratio;
use crate::threshold::{judged_voters, required_ratio};
const W: u32 = 7224;
/// The reference quorum of Monnaie libre (`vote_floor`): p0 = 2 × 50 / W.
@@ -312,6 +312,35 @@ mod tests {
// Ten voters, no quorum in the way: 7, 8, 9, 9 and 10 « pour », level 1 to 5.
let ten: Vec<u32> = InertiaLevel::ALL.iter().map(|k| scale.required(10, *k, 1).expect("valid")).collect();
assert_eq!(ten, [7, 8, 9, 9, 10]);
// The share asked is highest at the quorum, never near-unanimity (review of M6b, lot
// T2): 64,4 · 73,5 · 77,4 · 85,3 · 91,9 % of the quorum, level 1 to 5 — the review said
// 74 at level 2; rounded up to whole voters, 9 « pour » of 12 (75 %).
let at_quorum: Vec<f64> = InertiaLevel::ALL
.iter()
.map(|k| {
let q = scale.quorum(*k, None);
(required_ratio(w, judged_voters(0, q), &scale.params(*k, q)) * 1000.0).round() / 10.0
})
.collect();
assert_eq!(at_quorum, [64.4, 73.5, 77.4, 85.3, 91.9]);
assert_eq!((yes(2, 12, 0), scale.quorum(level(2), None)), (9, 12));
// Beyond the quorum the share only falls, down to M when everyone votes; under it,
// the voters counted are the quorum, and so is the share.
for k in InertiaLevel::ALL {
let q = scale.quorum(k, None);
let p = scale.params(k, q);
let share = |t: u32| required_ratio(w, judged_voters(t, q), &p);
let mut last = share(0);
for t in 0..=w {
let s = share(t);
assert!(s <= last, "level {}: the share never rises with the voters ({t})", k.get());
if t <= q {
assert_eq!(s, share(0), "level {}: under the quorum, the share of the quorum", k.get());
}
last = s;
}
assert!((share(w) - k.majority_pct() / 100.0).abs() < 1e-12, "level {}: M at full turnout", k.get());
}
}
#[test]