WIP lot S : Propositions seed (I1, E1, E2 ouvertes, cran 2), amendement gardé, publication suspendue sans article en vigueur
Travail en cours, sauvegardé à la demande d'orch : le moteur, le serveur et tests/seed_proposals.rs (verts) ; les autres tests et les e2e ne sont pas encore repris. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
@@ -9,18 +9,29 @@
|
||||
//! inertia, an inertia amendment (`inertia_amend`), on an article whose inertia
|
||||
//! no vote changed; modules the seed declares (the title, the order of each
|
||||
//! section, ADR 0009), a module amendment (`module_amend`), built from what the
|
||||
//! document holds.
|
||||
//! document holds; a starting text in force the seed now puts forward as a seed
|
||||
//! proposal (ADR 0011), a seed proposal amendment (`seed_proposal_amend`), on an
|
||||
//! article nobody has touched.
|
||||
|
||||
use crate::AppState;
|
||||
use crate::inertia_amend;
|
||||
use crate::module_amend;
|
||||
use crate::modules;
|
||||
use crate::seed_amend;
|
||||
use crate::seed_proposal_amend;
|
||||
use crate::util::{self, LangMap};
|
||||
use ld_engine::inertia::InertiaLevel;
|
||||
use serde::Deserialize;
|
||||
use std::path::Path;
|
||||
|
||||
/// The level of inertia a seed proposal starts at (ADR 0011). Yvv, 2026-11-02: « on
|
||||
/// pouvait l'amorcer avec une inertie basse, pour que le nombre de votes initiaux soit
|
||||
/// assez petit pour commencer l'expérience en mode prod » — level 2 (« basse »), or
|
||||
/// level 1 (« très basse »): his answer awaited, 2 by default. The one place to change:
|
||||
/// the seed gives no level to an article it puts forward, and the seed proposal
|
||||
/// amendment (`seed_proposal_amend`) writes this one.
|
||||
pub const SEED_PROPOSAL_LEVEL: u8 = 2;
|
||||
|
||||
#[derive(Deserialize)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
pub struct SeedDoc {
|
||||
@@ -60,16 +71,38 @@ pub struct SeedUnit {
|
||||
pub code: String,
|
||||
pub section: Option<String>,
|
||||
pub position: f64,
|
||||
/// A level, 1 to 5 (a word of before is read as its level).
|
||||
pub inertia: InertiaLevel,
|
||||
/// A level, 1 to 5 (a word of before is read as its level). None for an article
|
||||
/// the seed puts forward: it starts at `SEED_PROPOSAL_LEVEL`.
|
||||
#[serde(default)]
|
||||
pub inertia: Option<InertiaLevel>,
|
||||
pub versions: Vec<SeedVersion>,
|
||||
}
|
||||
|
||||
impl SeedUnit {
|
||||
/// Holds a seed proposal (ADR 0011).
|
||||
pub fn puts_forward(&self) -> bool {
|
||||
self.versions.iter().any(|v| v.seed_proposal)
|
||||
}
|
||||
|
||||
/// The level it starts at: its own, or the one of seed proposals.
|
||||
pub fn level(&self) -> InertiaLevel {
|
||||
match self.inertia {
|
||||
Some(level) => level,
|
||||
None => InertiaLevel::new(SEED_PROPOSAL_LEVEL).unwrap_or_default(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Deserialize)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
pub struct SeedVersion {
|
||||
pub label: Option<String>,
|
||||
/// `in_force` (seed a minima) or `open` (proposal at zero votes).
|
||||
/// `in_force` (seed a minima: the title and the orders) or `open` (a proposal at
|
||||
/// zero votes).
|
||||
pub status: String,
|
||||
/// A seed proposal (ADR 0011): open, put forward to start the vote, not in force.
|
||||
#[serde(default)]
|
||||
pub seed_proposal: bool,
|
||||
pub title: LangMap,
|
||||
pub body: LangMap,
|
||||
}
|
||||
@@ -98,6 +131,9 @@ pub async fn ensure(state: &AppState) -> anyhow::Result<()> {
|
||||
seed_amend::apply(state, &seeds, seed_amend::AMENDMENTS).await?;
|
||||
inertia_amend::apply(state, &seeds, inertia_amend::AMENDMENTS).await?;
|
||||
module_amend::apply(state, &seeds, module_amend::AMENDMENTS).await?;
|
||||
// After the text amendments: a starting text replaced first, then put forward.
|
||||
seed_proposal_amend::apply(state, &seeds, seed_proposal_amend::AMENDMENTS).await?;
|
||||
crate::floor_amend::apply(state, &seeds, crate::floor_amend::AMENDMENTS).await?;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
@@ -130,6 +166,7 @@ pub async fn documents(state: &AppState) -> anyhow::Result<Vec<SeedDoc>> {
|
||||
async fn load_file(state: &AppState, path: &Path) -> anyhow::Result<SeedDoc> {
|
||||
let raw = tokio::fs::read_to_string(path).await?;
|
||||
let seed: SeedDoc = serde_json::from_str(&raw).map_err(|e| anyhow::anyhow!("{}: {e}", path.display()))?;
|
||||
check(&seed).map_err(|e| anyhow::anyhow!("{}: {e}", path.display()))?;
|
||||
for inst in &seed.instances {
|
||||
let group_exists: i64 = sqlx::query_scalar("SELECT COUNT(*) FROM groups WHERE slug = ?")
|
||||
.bind(&inst.group)
|
||||
@@ -153,6 +190,22 @@ async fn load_file(state: &AppState, path: &Path) -> anyhow::Result<SeedDoc> {
|
||||
Ok(seed)
|
||||
}
|
||||
|
||||
/// A seed proposal is open, and its article takes its level from `SEED_PROPOSAL_LEVEL`
|
||||
/// alone; every other article says its level.
|
||||
fn check(seed: &SeedDoc) -> anyhow::Result<()> {
|
||||
for u in &seed.units {
|
||||
if u.versions.iter().any(|v| v.seed_proposal && v.status != "open") {
|
||||
anyhow::bail!("{}: a seed proposal is open, never in force", u.code);
|
||||
}
|
||||
match (u.puts_forward(), u.inertia.is_some()) {
|
||||
(true, true) => anyhow::bail!("{}: a seed proposal starts at SEED_PROPOSAL_LEVEL, give it no level", u.code),
|
||||
(false, false) => anyhow::bail!("{}: no level of inertia", u.code),
|
||||
_ => {}
|
||||
}
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
||||
async fn instantiate(state: &AppState, seed: &SeedDoc, inst: &SeedInstance) -> anyhow::Result<()> {
|
||||
let src = seed.source_lang.as_str();
|
||||
let pick = |m: &LangMap| m.get(src).cloned().unwrap_or_default();
|
||||
@@ -185,7 +238,7 @@ async fn instantiate(state: &AppState, seed: &SeedDoc, inst: &SeedInstance) -> a
|
||||
.bind(&unit.code)
|
||||
.bind(&unit.section)
|
||||
.bind(unit.position)
|
||||
.bind(unit.inertia.as_db())
|
||||
.bind(unit.level().as_db())
|
||||
.bind(&now)
|
||||
.execute(&mut *tx)
|
||||
.await?;
|
||||
@@ -218,6 +271,13 @@ async fn instantiate(state: &AppState, seed: &SeedDoc, inst: &SeedInstance) -> a
|
||||
.bind(&now)
|
||||
.execute(&mut *tx)
|
||||
.await?;
|
||||
// The mark, written apart: only where the seed puts the version forward.
|
||||
if v.seed_proposal && status == "open" {
|
||||
sqlx::query("UPDATE proposals SET seed_featured = 1 WHERE id = ?")
|
||||
.bind(&pid)
|
||||
.execute(&mut *tx)
|
||||
.await?;
|
||||
}
|
||||
if status == "in_force" {
|
||||
sqlx::query("UPDATE units SET in_force_id = ? WHERE id = ?")
|
||||
.bind(&pid)
|
||||
|
||||
Reference in New Issue
Block a user