Lot T3 : les tests d'abord, rouges sur les textes de T2 (aucun chiffre daté : l'exemple de N1.1 fait échouer le test des nombres ; la phrase du quorum de N1.1 vraie pour tout quorum, sur une grille de W, de quorums, de crans et de participations ; « comme d'habitude » au-delà du quorum seulement ; B^W ne compte jamais dans la toile ; l'amendement gardé qui suit celui de T2) ; textes de T2 gardés dans tests/fixtures/seed-quorum-t2.json ; wot::PLAUSIBLE public

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
Yvv
2026-11-03 17:22:37 +01:00
co-authored by Claude Opus 5.5
parent 8c1e7af12f
commit 03a7e19da0
4 changed files with 806 additions and 102 deletions
+63
View File
@@ -782,6 +782,61 @@ mod tests {
assert_eq!(verdict(Some(&written_by(&["m5", "t"])), &second, &["m5"]), Verdict::Refuse("revised"));
}
#[test]
fn a_fourth_amendment_admits_the_texts_the_three_before_wrote_and_nothing_else() {
// Lot T3 (2026-11-03): F1.2 and N1.1 were amended by M5, M6b and M6c (revision 4 in
// production); the texts without dated figures replace the text of M6c, after it only.
let fourth = Amendment { version: Version::Open("1.0.0"), follows: Some("t2"), ..A };
let before: &[&str] = &["m5", "t", "t2"];
// Production: M5, M6b, M6c, each its revision.
assert_eq!(verdict(Some(&written_by(&["m5", "t", "t2"])), &fourth, before), Verdict::Apply);
// A base born with the text of M5 (02/11): M6b and M6c wrote its revisions 2 and 3.
assert_eq!(verdict(Some(&written_by(&["t", "t2"])), &fourth, before), Verdict::Apply);
// A base born with the text of M6b, then of M6c: its revision 2, its revision 1.
assert_eq!(verdict(Some(&written_by(&["t2"])), &fourth, before), Verdict::Apply);
assert_eq!(verdict(Some(&intact()), &fourth, before), Verdict::Apply);
// The last revision is not M6c's, or not by them alone, or out of order: refused.
for applied in [
&["m5", "t"][..],
&["t"],
&["m5"],
&["t2", "t"],
&["m5", "t2", "t"],
&["other", "t", "t2"],
&["m5", "t", "t2", "t2"],
] {
assert_eq!(verdict(Some(&written_by(applied)), &fourth, before), Verdict::Refuse("revised"), "{applied:?}");
}
// A typo after M6c: a revision no amendment wrote.
let typo = Facts {
revision: 5,
revisions: vec![
"initial".into(),
"amendment".into(),
"amendment".into(),
"amendment".into(),
"typo".into(),
],
..written_by(&["m5", "t", "t2"])
};
assert_eq!(verdict(Some(&typo), &fourth, before), Verdict::Refuse("revised"));
// Any trace of a person keeps the text, with its reason.
for (f, why) in [
(Facts { votes: 1, ..written_by(&["m5", "t", "t2"]) }, "votes"),
(Facts { ballots: 1, ..written_by(&["m5", "t", "t2"]) }, "ballots"),
(Facts { typos: 1, ..written_by(&["m5", "t", "t2"]) }, "corrected"),
(Facts { member_translations: 1, ..written_by(&["m5", "t", "t2"]) }, "translation_edited"),
(Facts { signals: 1, ..written_by(&["m5", "t", "t2"]) }, "signalled"),
(Facts { fingerprint: "other".into(), ..written_by(&["m5", "t", "t2"]) }, "text_differs"),
(Facts { confirmed: true, ..written_by(&["m5", "t", "t2"]) }, "confirmed"),
] {
assert_eq!(verdict(Some(&f), &fourth, before), Verdict::Refuse(why), "{f:?}");
}
// Lot T2's own amendment never admits a revision 4.
let third = Amendment { version: Version::Open("1.0.0"), follows: Some("t"), ..A };
assert_eq!(verdict(Some(&written_by(&["m5", "t", "t2"])), &third, &["m5", "t"]), Verdict::Refuse("revised"));
}
#[test]
fn the_amendments_followed_are_read_through_the_list_oldest_first() {
let by_id = |id: &str| AMENDMENTS.iter().find(|a| a.id == id).expect("amendment");
@@ -794,6 +849,14 @@ mod tests {
["2026-11-02-n1-1-regles", "2026-11-03-n1-1-quorum"]
);
assert_eq!(earlier(AMENDMENTS, by_id("2026-11-03-f1-1-phrases")), ["2026-11-03-f1-1-quorum"]);
assert_eq!(
earlier(AMENDMENTS, by_id("2026-11-03-f1-2-chiffres")),
["2026-11-02-f1-2-regles", "2026-11-03-f1-2-quorum", "2026-11-03-f1-2-phrases"]
);
assert_eq!(
earlier(AMENDMENTS, by_id("2026-11-03-n1-1-chiffres")),
["2026-11-02-n1-1-regles", "2026-11-03-n1-1-quorum", "2026-11-03-n1-1-phrases"]
);
assert!(earlier(AMENDMENTS, by_id("2026-10-30-i1-raison-d-etre")).is_empty());
// Each one followed wrote the text the next replaces, and is superseded by it.
for a in AMENDMENTS.iter().filter(|a| a.follows.is_some()) {
+3 -1
View File
@@ -12,7 +12,9 @@ use std::time::Duration;
/// W is read again this often.
pub const REFRESH: Duration = Duration::from_secs(6 * 3600);
const PLAUSIBLE: std::ops::RangeInclusive<u32> = 100..=10_000_000;
/// The sizes of the web of trust taken as true; anything else read is ignored. The texts of
/// the seed are written true for every W in it (lot T3).
pub const PLAUSIBLE: std::ops::RangeInclusive<u32> = 100..=10_000_000;
fn twox_128(data: &[u8]) -> [u8; 16] {
let mut out = [0u8; 16];