Lot T4 : les textes et la structure de l'Acte d'engagement (Yvv, 03/11) — I1, E1, E2 prennent les textes d'Yvv (fr, en, es ; « il y a une et une seule clé » lu comme la coquille de « il n'y a une et une seule ») ; E12 « Responsabilité civique », Proposition seed au cran 2, entre E1 et E2 ; les sections formule, inertie, ordonnancement sortent du document (ADR 0014). Migration 0012 additive (units.retired_at et retired_reason, retirement_amendments, article_amendments) ; une unité retirée n'est ni lue avec son document, ni listée, ni votée, ni proposée, corrigée, traduite ou objectée (404), ni comptée, ni publiée ; rien d'effacé. Amendements gardés, une fois par document : 2026-11-03-i1-amorce, -e1-amorce, -e2-amorce (Version::SeedProposal ; la ligne seed_proposal admise quand l'amendement de Proposition seed l'a écrite), 2026-11-03-e12-responsabilite-civique (article_amend : entre E1 et E2 tant que l'ordre de la section n'a pas de vote, sinon en fin de section), 2026-11-03-fonctionnement-hors-vote (retire : tous ou aucun, refus à la moindre trace d'une personne, avec sa raison et l'unité) ; les amendements dont le seed ne donne plus le texte, dépassés (superseded_by) ; seed::write_unit partagé
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
+102
-75
@@ -12,18 +12,26 @@
|
||||
//! 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; the quorums by level the seed now gives a document
|
||||
//! (ADR 0013), a quorum amendment (`quorum_amend`), where the document holds none.
|
||||
//! (ADR 0013), a quorum amendment (`quorum_amend`), where the document holds none; an
|
||||
//! article the seed now holds, an article amendment (`article_amend`), placed where the
|
||||
//! seed puts it while the order of its section was never voted on; the units the seed no
|
||||
//! longer holds — the information on how the vote works (ADR 0014) —, a retirement
|
||||
//! (`retire`), where no person left a trace on them: they stay in the database, out of
|
||||
//! the document.
|
||||
|
||||
use crate::AppState;
|
||||
use crate::article_amend;
|
||||
use crate::inertia_amend;
|
||||
use crate::module_amend;
|
||||
use crate::modules;
|
||||
use crate::quorum_amend;
|
||||
use crate::retire;
|
||||
use crate::seed_amend;
|
||||
use crate::seed_proposal_amend;
|
||||
use crate::util::{self, LangMap};
|
||||
use ld_engine::inertia::{InertiaLevel, quorum_bounds};
|
||||
use serde::Deserialize;
|
||||
use sqlx::SqliteConnection;
|
||||
use std::path::Path;
|
||||
|
||||
/// The level of inertia a seed proposal starts at (ADR 0011). Yvv, 2026-11-02: « on
|
||||
@@ -132,8 +140,9 @@ pub async fn ensure_groups(state: &AppState) -> anyhow::Result<()> {
|
||||
Ok(())
|
||||
}
|
||||
|
||||
/// On start: the groups, the documents missing from them, then the seed,
|
||||
/// inertia and module amendments (each decided once per document).
|
||||
/// On start: the groups, the documents missing from them, then the seed, inertia,
|
||||
/// module, seed proposal, quorum, article amendments and the retirements (each decided
|
||||
/// once per document).
|
||||
pub async fn ensure(state: &AppState) -> anyhow::Result<()> {
|
||||
let seeds = documents(state).await?;
|
||||
seed_amend::apply(state, &seeds, seed_amend::AMENDMENTS).await?;
|
||||
@@ -142,6 +151,8 @@ pub async fn ensure(state: &AppState) -> anyhow::Result<()> {
|
||||
// After the text amendments: a starting text replaced first, then put forward.
|
||||
seed_proposal_amend::apply(state, &seeds, seed_proposal_amend::AMENDMENTS).await?;
|
||||
quorum_amend::apply(state, &seeds, quorum_amend::AMENDMENTS).await?;
|
||||
article_amend::apply(state, &seeds, article_amend::AMENDMENTS).await?;
|
||||
retire::apply(state, &seeds, retire::AMENDMENTS).await?;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
@@ -225,7 +236,6 @@ fn check(seed: &SeedDoc) -> anyhow::Result<()> {
|
||||
|
||||
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();
|
||||
let now = util::now();
|
||||
let doc_id = util::id();
|
||||
let mut tx = state.db.begin().await?;
|
||||
@@ -253,77 +263,7 @@ async fn instantiate(state: &AppState, seed: &SeedDoc, inst: &SeedInstance) -> a
|
||||
.await?;
|
||||
}
|
||||
for unit in &seed.units {
|
||||
let unit_id = util::id();
|
||||
sqlx::query(
|
||||
"INSERT INTO units (id, doc_id, code, section, position, inertia, in_force_id, created_at)
|
||||
VALUES (?, ?, ?, ?, ?, ?, NULL, ?)",
|
||||
)
|
||||
.bind(&unit_id)
|
||||
.bind(&doc_id)
|
||||
.bind(&unit.code)
|
||||
.bind(&unit.section)
|
||||
.bind(unit.position)
|
||||
.bind(unit.level().as_db())
|
||||
.bind(&now)
|
||||
.execute(&mut *tx)
|
||||
.await?;
|
||||
for v in &unit.versions {
|
||||
let pid = util::id();
|
||||
let (title, body) = (pick(&v.title), pick(&v.body));
|
||||
let status = if v.status == "in_force" { "in_force" } else { "open" };
|
||||
sqlx::query(
|
||||
"INSERT INTO proposals (id, unit_id, kind, title, body, status, origin, label, author_id, revision,
|
||||
created_at, updated_at, submitted_at)
|
||||
VALUES (?, ?, 'text', ?, ?, ?, 'seed', ?, NULL, 1, ?, ?, ?)",
|
||||
)
|
||||
.bind(&pid)
|
||||
.bind(&unit_id)
|
||||
.bind(&title)
|
||||
.bind(&body)
|
||||
.bind(status)
|
||||
.bind(&v.label)
|
||||
.bind(&now)
|
||||
.bind(&now)
|
||||
.bind(&now)
|
||||
.execute(&mut *tx)
|
||||
.await?;
|
||||
sqlx::query(
|
||||
"INSERT INTO revisions (proposal_id, revision, kind, title, body, author_id, created_at) VALUES (?, 1, 'initial', ?, ?, NULL, ?)",
|
||||
)
|
||||
.bind(&pid)
|
||||
.bind(&title)
|
||||
.bind(&body)
|
||||
.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)
|
||||
.bind(&unit_id)
|
||||
.execute(&mut *tx)
|
||||
.await?;
|
||||
}
|
||||
let hash = util::source_hash(&title, &body);
|
||||
for lang in util::LANGS.iter().filter(|l| **l != src) {
|
||||
let (Some(t), Some(b)) = (v.title.get(*lang), v.body.get(*lang)) else { continue };
|
||||
sqlx::query(
|
||||
"INSERT INTO translations (proposal_id, lang, title, body, source_hash, origin, updated_by, updated_at)
|
||||
VALUES (?, ?, ?, ?, ?, 'seed', NULL, ?)",
|
||||
)
|
||||
.bind(&pid)
|
||||
.bind(lang)
|
||||
.bind(t)
|
||||
.bind(b)
|
||||
.bind(&hash)
|
||||
.bind(&now)
|
||||
.execute(&mut *tx)
|
||||
.await?;
|
||||
}
|
||||
}
|
||||
write_unit(&mut tx, &doc_id, src, unit, unit.position, &now).await?;
|
||||
}
|
||||
// The modules, from the document just written: its title, the order of each section.
|
||||
if let Some(m) = &seed.modules {
|
||||
@@ -343,6 +283,93 @@ async fn instantiate(state: &AppState, seed: &SeedDoc, inst: &SeedInstance) -> a
|
||||
Ok(())
|
||||
}
|
||||
|
||||
/// Writes one article of the seed into a document, at `position`: its unit (at its level),
|
||||
/// its versions — in force, open, put forward —, their first revision and their
|
||||
/// translations. A new base (`instantiate`), or an article a seed adds later
|
||||
/// (`article_amend`). Returns the unit's id.
|
||||
pub(crate) async fn write_unit(
|
||||
conn: &mut SqliteConnection,
|
||||
doc_id: &str,
|
||||
src: &str,
|
||||
unit: &SeedUnit,
|
||||
position: f64,
|
||||
now: &str,
|
||||
) -> sqlx::Result<String> {
|
||||
let pick = |m: &LangMap| m.get(src).cloned().unwrap_or_default();
|
||||
let unit_id = util::id();
|
||||
sqlx::query(
|
||||
"INSERT INTO units (id, doc_id, code, section, position, inertia, in_force_id, created_at)
|
||||
VALUES (?, ?, ?, ?, ?, ?, NULL, ?)",
|
||||
)
|
||||
.bind(&unit_id)
|
||||
.bind(doc_id)
|
||||
.bind(&unit.code)
|
||||
.bind(&unit.section)
|
||||
.bind(position)
|
||||
.bind(unit.level().as_db())
|
||||
.bind(now)
|
||||
.execute(&mut *conn)
|
||||
.await?;
|
||||
for v in &unit.versions {
|
||||
let pid = util::id();
|
||||
let (title, body) = (pick(&v.title), pick(&v.body));
|
||||
let status = if v.status == "in_force" { "in_force" } else { "open" };
|
||||
sqlx::query(
|
||||
"INSERT INTO proposals (id, unit_id, kind, title, body, status, origin, label, author_id, revision,
|
||||
created_at, updated_at, submitted_at)
|
||||
VALUES (?, ?, 'text', ?, ?, ?, 'seed', ?, NULL, 1, ?, ?, ?)",
|
||||
)
|
||||
.bind(&pid)
|
||||
.bind(&unit_id)
|
||||
.bind(&title)
|
||||
.bind(&body)
|
||||
.bind(status)
|
||||
.bind(&v.label)
|
||||
.bind(now)
|
||||
.bind(now)
|
||||
.bind(now)
|
||||
.execute(&mut *conn)
|
||||
.await?;
|
||||
sqlx::query(
|
||||
"INSERT INTO revisions (proposal_id, revision, kind, title, body, author_id, created_at) VALUES (?, 1, 'initial', ?, ?, NULL, ?)",
|
||||
)
|
||||
.bind(&pid)
|
||||
.bind(&title)
|
||||
.bind(&body)
|
||||
.bind(now)
|
||||
.execute(&mut *conn)
|
||||
.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 *conn).await?;
|
||||
}
|
||||
if status == "in_force" {
|
||||
sqlx::query("UPDATE units SET in_force_id = ? WHERE id = ?")
|
||||
.bind(&pid)
|
||||
.bind(&unit_id)
|
||||
.execute(&mut *conn)
|
||||
.await?;
|
||||
}
|
||||
let hash = util::source_hash(&title, &body);
|
||||
for lang in util::LANGS.iter().filter(|l| **l != src) {
|
||||
let (Some(t), Some(b)) = (v.title.get(*lang), v.body.get(*lang)) else { continue };
|
||||
sqlx::query(
|
||||
"INSERT INTO translations (proposal_id, lang, title, body, source_hash, origin, updated_by, updated_at)
|
||||
VALUES (?, ?, ?, ?, ?, 'seed', NULL, ?)",
|
||||
)
|
||||
.bind(&pid)
|
||||
.bind(lang)
|
||||
.bind(t)
|
||||
.bind(b)
|
||||
.bind(&hash)
|
||||
.bind(now)
|
||||
.execute(&mut *conn)
|
||||
.await?;
|
||||
}
|
||||
}
|
||||
Ok(unit_id)
|
||||
}
|
||||
|
||||
/// The quorums by level as `documents.quorums` holds them: `[12,12,50,50,50]`.
|
||||
pub fn quorums_json(quorums: &[u32; 5]) -> String {
|
||||
serde_json::to_string(quorums).unwrap_or_else(|_| "null".into())
|
||||
|
||||
Reference in New Issue
Block a user