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:
Yvv
2026-11-02 07:50:31 +01:00
co-authored by Claude Opus 5.5
parent 5cf30e0bfa
commit 6228d3913a
15 changed files with 2513 additions and 55 deletions
+22 -3
View File
@@ -232,15 +232,29 @@ pub struct ProposalRow {
pub submitted_at: Option<String>,
pub entered_at: Option<String>,
pub confirmed_at: Option<String>,
/// Put forward by the seed to start the vote (ADR 0011): see `seed_proposal`.
pub seed_featured: bool,
}
pub const PROPOSAL_SELECT: &str =
"SELECT p.id, p.unit_id, p.kind, p.inertia_target, p.title, p.body, p.status, p.origin,
p.label, p.author_id, i.display_name AS author_name, i.kind = 'invite' AS author_invited, p.revision, p.created_at, p.updated_at, p.submitted_at,
p.entered_at, p.confirmed_at
p.entered_at, p.confirmed_at, p.seed_featured
FROM proposals p LEFT JOIN identities i ON i.id = p.author_id";
impl ProposalRow {
/// A seed a minima: in force from the seed, never voted into force nor confirmed
/// (the title and the orders of a new base; a text a seed proposal amendment left).
pub fn seed_minimal(&self) -> bool {
self.status == "in_force" && self.entered_at.is_none() && self.confirmed_at.is_none() && self.origin == "seed"
}
/// A seed proposal (ADR 0011): open, from the seed, put forward to start the vote,
/// never voted into force. Not in force: it enters like any proposal.
pub fn seed_proposal(&self) -> bool {
self.seed_featured && self.status == "open" && self.origin == "seed" && self.entered_at.is_none()
}
pub fn kind(&self) -> ProposalKind {
match self.kind.as_str() {
"remove" => ProposalKind::Remove,
@@ -659,7 +673,7 @@ fn proposal_json(
"mine": p.author_id.as_deref() == Some(me),
"revision": p.revision, "createdAt": p.created_at, "updatedAt": p.updated_at,
"submittedAt": p.submitted_at, "enteredAt": p.entered_at, "confirmedAt": p.confirmed_at,
"seedMinimal": p.status == "in_force" && p.entered_at.is_none() && p.confirmed_at.is_none() && p.origin == "seed",
"seedMinimal": p.seed_minimal(), "seedProposal": p.seed_proposal(),
"tally": st.shown_tally(&p.id),
"evaluation": eval,
"votedAtInertia": voted_at,
@@ -797,10 +811,15 @@ pub async fn publication_status(state: &AppState, doc_id: &str) -> AppResult<ser
.bind(doc_id)
.fetch_optional(&state.db)
.await?;
// Waiting, not failing: no article in force, nothing goes out (ADR 0011).
let suspended = match &last {
Some(r) if r.done_at.is_none() => crate::publish::waits_for_a_text(state, doc_id).await?,
_ => false,
};
Ok(match last {
None => json!({ "state": "none", "configured": state.cfg.publish.is_some() }),
Some(r) => json!({
"state": if r.done_at.is_some() { "done" } else { "pending" },
"state": if r.done_at.is_some() { "done" } else if suspended { "suspended" } else { "pending" },
"configured": state.cfg.publish.is_some(),
"since": r.created_at, "doneAt": r.done_at, "commit": r.commit_sha,
"attempts": r.attempts, "error": r.last_error.map(|_| "retrying"),