forked from yvv/decision
v3 : moteur des objections « redit » / « contredit » et du circuit des coquilles
- ld-engine/objection.rs : la dernière arrivée (jamais une version en vigueur) n'est plus votable ; un cycle à la fois (réponse de l'auteur, puis lever ou réitérer) ; levée seule 3 jours après la réponse ; une révision de l'autre côté répond aussi ; l'administrateur lève, ne réitère jamais. - ld-engine/correction.rs : qui applique une coquille et quand (celui qui répond de la version l'applique, les autres attendent 3 jours au plus), l'auteur garde la main hors vigueur, deux coquilles en attente : la seconde devient caduque. - trustin-access : answers_typo, lifts_objection, reiterates_objection, reads_message. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
@@ -150,6 +150,33 @@ pub fn manages_access(identity: &Identity) -> bool {
|
||||
identity.admin
|
||||
}
|
||||
|
||||
/// Who answers a typo fix someone else wrote on a version (2026-10-30, L13):
|
||||
/// its author; for a text without author (a starting text), an administrator of
|
||||
/// trustinWallet. Whoever answers for a version also applies their own fix at once.
|
||||
pub fn answers_typo(identity: &Identity, version_author: Option<&str>) -> bool {
|
||||
match version_author {
|
||||
Some(author) => identity.id == author,
|
||||
None => identity.admin,
|
||||
}
|
||||
}
|
||||
|
||||
/// Who lifts an objection (2026-10-30, L12): the person who raised it, or an
|
||||
/// administrator of trustinWallet.
|
||||
pub fn lifts_objection(identity: &Identity, objector: &str) -> bool {
|
||||
identity.id == objector || identity.admin
|
||||
}
|
||||
|
||||
/// Who reiterates an objection: only the person who raised it — an
|
||||
/// administrator lifts, never speaks for someone else.
|
||||
pub fn reiterates_objection(identity: &Identity, objector: &str) -> bool {
|
||||
identity.id == objector
|
||||
}
|
||||
|
||||
/// A message of trustinWallet is read by its recipient only.
|
||||
pub fn reads_message(identity: &Identity, recipient: &str) -> bool {
|
||||
identity.id == recipient
|
||||
}
|
||||
|
||||
/// The groups a fresh deployment starts with. Ordered as displayed.
|
||||
pub fn default_groups() -> Vec<Group> {
|
||||
let g = |slug: &str, name: &str, parent: Option<&str>, policy, hidden| Group {
|
||||
@@ -251,6 +278,37 @@ mod tests {
|
||||
assert!(!asks_ballot(&invited, &essai, true), "no chain there: the test group stays easy to try");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn the_author_answers_a_typo_and_an_administrator_for_a_starting_text() {
|
||||
let chiara = Identity { id: "chiara".into(), ..who(IdentityKind::Invite, false, false) };
|
||||
let admin = Identity { id: "yvv".into(), ..who(IdentityKind::G1, true, true) };
|
||||
let other = Identity { id: "luna".into(), ..who(IdentityKind::G1, true, false) };
|
||||
assert!(answers_typo(&chiara, Some("chiara")));
|
||||
assert!(!answers_typo(&other, Some("chiara")));
|
||||
assert!(!answers_typo(&admin, Some("chiara")), "an administrator never answers for an author");
|
||||
assert!(answers_typo(&admin, None), "a starting text has no author: an administrator answers");
|
||||
assert!(!answers_typo(&other, None));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn the_objector_lifts_or_reiterates_an_administrator_only_lifts() {
|
||||
let objector = Identity { id: "luna".into(), ..who(IdentityKind::G1, true, false) };
|
||||
let admin = Identity { id: "yvv".into(), ..who(IdentityKind::G1, true, true) };
|
||||
let other = Identity { id: "chiara".into(), ..who(IdentityKind::Invite, false, false) };
|
||||
assert!(lifts_objection(&objector, "luna") && reiterates_objection(&objector, "luna"));
|
||||
assert!(lifts_objection(&admin, "luna"));
|
||||
assert!(!reiterates_objection(&admin, "luna"));
|
||||
assert!(!lifts_objection(&other, "luna") && !reiterates_objection(&other, "luna"));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn a_message_is_read_by_its_recipient_only() {
|
||||
let admin = Identity { id: "yvv".into(), ..who(IdentityKind::G1, true, true) };
|
||||
let luna = Identity { id: "luna".into(), ..who(IdentityKind::G1, true, false) };
|
||||
assert!(reads_message(&luna, "luna"));
|
||||
assert!(!reads_message(&admin, "luna"), "not even an administrator");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn no_atelier_du_canal() {
|
||||
assert!(default_groups().iter().all(|g| !g.slug.contains("atelier")));
|
||||
|
||||
Reference in New Issue
Block a user