v3 : sur une version retenue, « contre » et retrait oui, « pour » non (moteur, serveur, chaîne)

Décision d'Yvv du 01/11/2026 : « Retirer ou "contre" ». Le moteur dit la règle
(objection::may_cast) ; le vote direct, le vote groupé et le bulletin de la chaîne
l'appliquent par DocState::admits : « pour » 409 objection, « contre » et retrait
acceptés, une ligne refusée refuse tout le vote. Un bulletin scellé avant
l'objection compte tel qu'il est signé ; une version retenue n'entre jamais.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
Yvv
2026-11-02 00:03:45 +01:00
co-authored by Claude Opus 5.5
parent 61547c11c0
commit 238c7db93f
8 changed files with 222 additions and 19 deletions
+26
View File
@@ -17,6 +17,10 @@
//! is changed by a proposal. The target is fixed when the objection is raised;
//! - the votes already cast on it stay, but it cannot enter into force
//! (`votable` and the adoption: a non-votable version is blocked);
//! - while it is held, one may still **vote against it or take one's vote
//! back**, never add a *for* (`may_cast`, Yvv 2026-11-01: « Retirer ou
//! "contre" »): it can only lose votes, and once lifted it enters with the
//! votes still there;
//! - its author **answers**: a substantive revision of it, or a proposal linked
//! to the objection (on the article it repeats, for a « redit »; a reworded
//! version, for a version without author). A substantive revision of **the
@@ -31,6 +35,7 @@
//! lift too (never reiterate: the objection is not theirs); withdrawing either
//! version ends it.
use crate::ballot::Choice;
use serde::{Deserialize, Serialize};
use std::cmp::Ordering;
@@ -296,6 +301,16 @@ pub fn votable(id: &str, in_force: bool, held: &[&str]) -> bool {
in_force || !held.contains(&id)
}
/// May this choice be cast on a version? `held` = a standing objection holds it
/// back now (never a version in force, `votable`). Yvv, 2026-11-01, to « pendant
/// qu'une objection retient une version, que permet-on ? »: « Retirer ou
/// "contre" ». On a held version one may take one's vote back or vote against,
/// never add a *for*: it can only lose votes while it is held, and once lifted it
/// enters with the votes still there. A version not held takes any choice.
pub fn may_cast(held: bool, choice: Choice) -> bool {
!held || choice != Choice::For
}
#[cfg(test)]
mod tests {
use super::*;
@@ -357,6 +372,17 @@ mod tests {
assert!(votable("x", true, &["x"]), "a version in force is never made non-votable");
}
#[test]
fn a_held_version_takes_against_and_withdrawal_never_for() {
// Yvv, 2026-11-01: « Retirer ou "contre" » — it can only lose votes while held.
assert!(!may_cast(true, Choice::For), "never a new *for* while held");
assert!(may_cast(true, Choice::Against), "against, yes");
assert!(may_cast(true, Choice::None), "taking one's vote back, yes");
for c in [Choice::For, Choice::Against, Choice::None] {
assert!(may_cast(false, c), "a version not held takes any choice: {c:?}");
}
}
#[test]
fn the_full_cycle_answer_reiterate_answer_lift() {
let start = Phase::Author { cycle: 1 };