forked from yvv/decision
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:
@@ -12,6 +12,7 @@ use crate::participation;
|
||||
use crate::util::{self, LangMap};
|
||||
use axum::Json;
|
||||
use axum::extract::{Path, Query, State};
|
||||
use ld_engine::ballot::Choice;
|
||||
use ld_engine::compose::{self, PreviewMode, ProposalKind, ProposalState, UnitState, VersionText};
|
||||
use ld_engine::inertia::{InertiaLevel, Participation, Scale};
|
||||
use ld_engine::threshold::{Evaluation, Tally};
|
||||
@@ -265,7 +266,8 @@ pub struct DocState {
|
||||
pub module_kinds: HashMap<String, ModuleKind>,
|
||||
pub proposals: Vec<ProposalRow>,
|
||||
pub tallies: HashMap<String, Tally>,
|
||||
/// Versions held back by a standing objection: not votable, never entering into force.
|
||||
/// Versions held back by a standing objection: against or a withdrawal only, never
|
||||
/// a new *for* (`admits`), and never entering into force.
|
||||
pub blocked: HashSet<String>,
|
||||
/// Standing objections touching each version, either side.
|
||||
pub signal_counts: HashMap<String, i64>,
|
||||
@@ -353,7 +355,7 @@ pub async fn load_state(state: &AppState, doc_id: &str) -> AppResult<DocState> {
|
||||
}
|
||||
|
||||
// A standing objection holds back the latest arrival of its pair (never a version
|
||||
// in force): not votable, and it cannot enter into force (ADR 0010).
|
||||
// in force): no new *for*, and it cannot enter into force (ADR 0010).
|
||||
let (blocked, signal_counts) = crate::objections::held(state, doc_id, &units).await?;
|
||||
let (electorate, electorate_source) = electorate(state, &group).await?;
|
||||
let measure = participation::stored(state, &group.slug).await?;
|
||||
@@ -414,6 +416,14 @@ impl DocState {
|
||||
matches!(p.status.as_str(), "open" | "in_force") && !self.blocked.contains(&p.id)
|
||||
}
|
||||
|
||||
/// May `choice` be cast on `p` now — by one vote, a grouped one or a ballot of the
|
||||
/// chain? Open or in force; held back by an objection, against or a withdrawal
|
||||
/// only, never a *for* (`ld_engine::objection::may_cast`, Yvv 2026-11-01).
|
||||
pub fn admits(&self, p: &ProposalRow, choice: Choice) -> bool {
|
||||
matches!(p.status.as_str(), "open" | "in_force")
|
||||
&& ld_engine::objection::may_cast(self.blocked.contains(&p.id), choice)
|
||||
}
|
||||
|
||||
/// The module a unit is, if it is one.
|
||||
pub fn module_of(&self, unit_id: &str) -> Option<ModuleKind> {
|
||||
self.module_kinds.get(unit_id).copied()
|
||||
|
||||
Reference in New Issue
Block a user