Fusion de chantier/acte-certification (lots H et S) dans le lot V : le tampon et ses états, avec le quorum et les Propositions seed
- conflits résolus des deux côtés : kept_params garde le quorum (S) et la part simulée, la version déplacée, le cran d'avant (V) ; proposals.rs garde seedMinimal / seedProposal (S) et tallyPending / tallySimulated / myVoteState (V) ; - simulation::reexamine juge sur le quorum gardé par l'adoption (params.quorum, à défaut celui de l'article) ; - l'acte répété n'examine plus une adoption qui tient (params.reexamined) ; - tests V repris sans texte en vigueur au départ (I1, E1 : la Proposition seed) et sur un quorum 2 (small_web) ; le test overview d'une personne invitée dans Monnaie libre suit la simulation (elle vote, chaîne fermée). Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
@@ -83,6 +83,20 @@ pub async fn pass(state: &AppState) -> anyhow::Result<()> {
|
||||
let rows: Vec<&Due> = due.iter().filter(|d| d.doc_id == doc_id).collect();
|
||||
let last = rows.iter().map(|d| d.id).max().unwrap_or(0);
|
||||
let attempts = rows.iter().map(|d| d.attempts).max().unwrap_or(0);
|
||||
if waits_for_a_text(state, &doc_id).await? {
|
||||
// Not a failure: no attempt counted, no error. The queue stays; the first
|
||||
// text that enters queues a row due now, and everything goes out with it.
|
||||
sqlx::query("UPDATE outbox SET next_at = ? WHERE doc_id = ? AND done_at IS NULL")
|
||||
.bind(util::in_seconds(MAX_BACKOFF_SECS))
|
||||
.bind(&doc_id)
|
||||
.execute(&state.db)
|
||||
.await?;
|
||||
tracing::info!(
|
||||
doc = %doc_id, waiting = rows.len(),
|
||||
"publication suspended: no article in force, the queue waits for the first text (LD_PUBLISH_WITHOUT_ARTICLES=1 publishes anyway)"
|
||||
);
|
||||
continue;
|
||||
}
|
||||
match publish_doc(state, &doc_id).await {
|
||||
Ok(sha) => {
|
||||
sqlx::query("UPDATE outbox SET done_at = ?, commit_sha = ?, last_error = NULL WHERE doc_id = ? AND done_at IS NULL AND id <= ?")
|
||||
@@ -109,6 +123,23 @@ pub async fn pass(state: &AppState) -> anyhow::Result<()> {
|
||||
Ok(())
|
||||
}
|
||||
|
||||
/// Does the document wait for a text before it is published? Yes when none of its
|
||||
/// articles is in force — the seed proposals are not (ADR 0011) — unless the
|
||||
/// publication is told to go out anyway (`LD_PUBLISH_WITHOUT_ARTICLES`). The default is
|
||||
/// Yvv's (2026-11-02, « Suspendre jusqu'au 1er texte »): never a document without a text.
|
||||
pub async fn waits_for_a_text(state: &AppState, doc_id: &str) -> anyhow::Result<bool> {
|
||||
if state.cfg.publish.as_ref().is_none_or(|p| p.without_articles) {
|
||||
return Ok(false);
|
||||
}
|
||||
let in_force: i64 = sqlx::query_scalar(
|
||||
"SELECT COUNT(*) FROM units WHERE doc_id = ? AND kind = 'article' AND in_force_id IS NOT NULL",
|
||||
)
|
||||
.bind(doc_id)
|
||||
.fetch_one(&state.db)
|
||||
.await?;
|
||||
Ok(in_force == 0)
|
||||
}
|
||||
|
||||
async fn git(dir: &Path, state: &AppState, args: &[&str]) -> anyhow::Result<String> {
|
||||
let publish = state.cfg.publish.as_ref().ok_or_else(|| anyhow::anyhow!("publication not configured"))?;
|
||||
let known_hosts = state.cfg.data_dir.join("keys/known_hosts");
|
||||
@@ -361,7 +392,7 @@ pub async fn render(state: &AppState, st: &DocState) -> anyhow::Result<Vec<(Stri
|
||||
let json = json!({
|
||||
"document": st.doc.slug, "group": st.group.slug, "title": titles, "sourceLang": src,
|
||||
"source": source_url, "updatedAt": updated, "electorate": st.electorate,
|
||||
"voteFloor": st.doc.vote_floor, "units": units, "modules": modules,
|
||||
"voteFloor": st.doc.vote_floor, "quorums": st.doc.quorums(), "units": units, "modules": modules,
|
||||
});
|
||||
files.push(("document.json".into(), format!("{}\n", serde_json::to_string_pretty(&json)?)));
|
||||
Ok(files)
|
||||
|
||||
Reference in New Issue
Block a user