forked from yvv/decision
Les deux côtés gardés partout. Aux coutures : - une objection (redit / contredit) porte sur deux articles, jamais sur un module ; un ordre ne se corrige pas, ni par son auteur ni par un autre ; une coquille du titre suit le chemin de F (l'auteur du titre, un administrateur pour le titre de départ, ou 3 jours), et documents.title suit à l'application ; - votable() couvre les modules ; leurs totaux passent par shown_tally, à l'écran et dans document.json ; - « Modules à voter » ne compte plus une version retenue par une objection (test vu rouge) ; la liste du groupe la compte toujours parmi les propositions en cours ; - le panier : une fonction pour les articles et les modules, avec les versions retenues de F ; un nouvel article se propose dans une section, à sa fin, et peut répondre à une objection ; - migrations 0007 (modules) puis 0008 (objections) ; - C25 et C26 supportent un groupe d'essai où une voix suffit (dès 16 membres). Boucle : fmt, clippy -D warnings, cargo test (227), svelte-check 0, vitest 55, build, e2e 35 / 35 (C1–C33 et M1). Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
135 lines
8.5 KiB
Markdown
135 lines
8.5 KiB
Markdown
# 0009 — Les modules : l'ordre des articles de chaque section, le titre du document
|
||
|
||
> Complète [0002](0002-vote-permanent.md) (vote permanent), [0007](0007-inertie-cinq-crans.md)
|
||
> (inertie à cinq crans) et [0008](0008-vote-par-transaction.md) (vote par la chaîne). Décisions
|
||
> d'Yvv à la revue du 2026-10-30 (L11) ; la règle des articles qui entrent ou sortent pendant le
|
||
> vote d'un ordre est le choix du lot D, isolé dans `ld-engine` pour être changé seul.
|
||
|
||
**Contexte.** Un texte de référence vit article par article : chacun entre en vigueur à son
|
||
seuil. Deux choses n'avaient pas de vote : la place des articles dans leur section (fixée par le
|
||
seed, puis « après tel article » au choix de qui proposait) et le titre du document (écrit une
|
||
fois, au seed). Yvv, 2026-10-30 : « En fin de section, il y a un "module" qui permet de changer
|
||
l'ordre des "articles". Lui-même à (2), avec une simple liste clipable. » ; « Le titre du doc à
|
||
(4). » ; « Non, titre et texte ensemble » — le titre d'un article reste voté avec son texte :
|
||
seul le titre du document est un module à part.
|
||
|
||
## Décision
|
||
|
||
### Un module est une unité du document, ses versions sont des propositions
|
||
|
||
`units.kind` (`article` par défaut, `title`, `order` ; migration `0007_modules.sql`, additive).
|
||
Un module a, comme un article, une inertie, une version en vigueur, des propositions ouvertes,
|
||
des votes, des changements d'inertie. Tout ce qui sert au vote d'un article lui sert sans
|
||
chemin à part : le vote déplié, le panier, le bulletin sur la chaîne Ğ1 (`ballots.rs` valide
|
||
les lignes contre les propositions du document : un module y est), le balayage, l'adoption
|
||
(`ld_engine::compose`), la marge du texte en place (0002), le cran (0007), « Décisions »
|
||
(`ld_engine::pending`).
|
||
|
||
- **Le titre du document** — code `titre`, inertie **4**. Une version = un titre dans la langue
|
||
source (corps vide). Elle se propose en tête du lecteur (« Proposer un autre titre »,
|
||
`POST /api/units/{id}/title`) ; une coquille s'y corrige sans vote (0003) ; elle se traduit.
|
||
- **L'ordre d'une section** — code `ordre.<section>`, inertie **2**, un par section. Une version =
|
||
la liste des articles de la section, un identifiant par ligne. Elle se propose en fin de
|
||
section (« Proposer un autre ordre », `POST /api/units/{id}/order`) avec une liste où l'on
|
||
clique : un article, puis sa nouvelle place, ou ses flèches, ou le clavier (Entrée choisit,
|
||
haut et bas déplacent). Un ordre ne se corrige pas et ne se traduit pas (`409 order_fixed`) :
|
||
on en propose un autre.
|
||
- L'écriture générique (`POST /api/docs/{id}/proposals`) refuse un module (`400 module`) : chacun
|
||
se propose à sa place.
|
||
|
||
### Qui est dans l'ordre d'une section
|
||
|
||
Les articles de la section qui ont un texte en vigueur ou une version ouverte (texte ou
|
||
retrait) ; ni les brouillons, ni les retirés. Dans l'ordre des positions. La même règle en Rust
|
||
(`DocState::members`) et en SQL (`order::sections_now`). Une section d'**un seul article n'a
|
||
rien à décider** : son ordre n'est jamais « à voter », ni montré, ni compté (`Module.moot`).
|
||
|
||
### Quand des articles entrent ou sortent pendant le vote d'un ordre : complété à la fin
|
||
|
||
Une proposition d'ordre garde **les votes reçus**. Ce qui est voté est l'ordre relatif des
|
||
articles qu'elle nomme ; on le lit toujours contre les articles présents
|
||
(`ld_engine::order::fit`) :
|
||
|
||
- les articles encore dans la section gardent l'ordre proposé ;
|
||
- un article **arrivé depuis** se place **à la fin**, dans l'ordre de la section (« 1 article
|
||
entré depuis, placé à la fin ») ;
|
||
- un article **sorti** (retiré, rejeté) disparaît de l'ordre, sans autre effet ;
|
||
- une proposition qui, ainsi complétée, **redit l'ordre en vigueur** ne peut pas entrer (« c'est
|
||
l'ordre en vigueur ») : elle reste ouverte, sans effet, jusqu'à ce qu'un autre ordre entre.
|
||
|
||
Écartées : **caduque** (un vote permanent dans une section vivante ne passerait jamais : chaque
|
||
nouvel article remettrait les compteurs à zéro) et **à reconfirmer** (même effet, plus lent, et
|
||
demande aux votants un geste qu'ils ne savent pas devoir faire). Compléter à la fin respecte ce
|
||
qui a été voté — l'ordre entre les articles connus — et la règle de placement par défaut.
|
||
|
||
### Les articles nouveaux se placent à la fin de leur section
|
||
|
||
Une proposition de nouvel article nomme sa **section** ; elle s'y place à la fin
|
||
(`ld_engine::order::place_at_end`). Un ancien client qui nomme un article (`afterUnitId`) obtient
|
||
la fin de la section de cet article. « Après tel article » n'existe plus : la place se vote, par
|
||
l'ordre de la section.
|
||
|
||
### Quand un ordre entre en vigueur
|
||
|
||
Il redistribue **les positions déjà tenues par la section** à ses articles, dans le nouvel ordre
|
||
(`ld_engine::order::positions`) : rien ne bouge hors de la section, aucun texte ne change, aucun
|
||
vote d'article n'est touché. L'ordre d'avant redevient une proposition ouverte, avec ses votes,
|
||
et peut revenir.
|
||
|
||
### Quand un titre entre en vigueur
|
||
|
||
`documents.title` prend le nouveau titre dans la langue source. Les traductions restent
|
||
éditoriales (le français voté fait foi) : la nouvelle version reprend celles du titre qu'elle
|
||
remplace, attachées au texte de ce titre-là, donc **« traduction à revoir »** jusqu'à ce qu'une
|
||
personne traduise le nouveau. Le titre du document dans les autres langues suit ses traductions,
|
||
fraîches ou à revoir (`doc_title::sync`, rejoué aussi à chaque mise en file de publication : une
|
||
coquille ou une traduction du titre en vigueur s'y reporte).
|
||
|
||
### Face aux objections et aux coquilles des autres (ADR 0010)
|
||
|
||
- **Une objection** (« redit », « contredit ») porte sur deux versions d'articles, jamais sur un
|
||
module : un titre ou un ordre ne se répète ni ne se contredit au sens d'un article
|
||
(`objections::raise` n'admet que des textes ; test
|
||
`the_generic_writing_stops_at_a_module_and_an_order_is_never_corrected`).
|
||
- **Un ordre ne se corrige pas** (`409 order_fixed`), ni par son auteur ni par un autre : pas de
|
||
coquille d'un autre sur un ordre. **Une coquille du titre** suit le chemin de toute coquille :
|
||
celle d'un autre attend l'auteur du titre (un administrateur pour le titre de départ) ou
|
||
3 jours ; appliquée, elle republie, et `documents.title` suit.
|
||
- `DocState::votable` couvre les modules comme les articles ; les totaux d'un module se lisent
|
||
par `shown_tally`, à l'écran et dans `document.json`.
|
||
- **« Modules à voter »** ne compte pas une version retenue par une objection : personne ne peut
|
||
la voter tant qu'elle est retenue (un article dont la seule version ouverte est retenue sort
|
||
du compte, et y revient à la levée). La liste du groupe la compte toujours parmi les
|
||
propositions en cours, ouvertes.
|
||
|
||
### Publication
|
||
|
||
`fr.md` ne change pas de forme : les articles dans leur ordre en vigueur, sous le titre en
|
||
vigueur. `en.md` / `es.md` portent une ligne de commentaire quand la traduction du titre est à
|
||
revoir. `document.json` gagne `modules` : le titre (inertie, statut, date d'entrée, votes,
|
||
traductions et leur fraîcheur) et chaque ordre (section, inertie, statut, date, votes, articles
|
||
par leur code).
|
||
|
||
### Les documents qui existent déjà
|
||
|
||
Le seed déclare les crans (`"modules": {"title": {"inertia": 4}, "order": {"inertia": 2}}`) ; une
|
||
base neuve crée les modules en même temps que les articles. Un document existant les reçoit par
|
||
un **ajout gardé** (`crates/ld-server/src/module_amend.rs`, dans la ligne de `seed_amend.rs` et
|
||
`inertia_amend.rs`) : une seule fois par document (journal `module_amendments`, migration
|
||
`0007`), depuis l'état présent — le titre en vigueur est le titre actuel du document, avec ses
|
||
traductions ; l'ordre en vigueur d'une section est l'ordre actuel de ses articles —, sans
|
||
toucher un article ni un vote. Les versions créées sont des « seed a minima » (en vigueur sans
|
||
vote, marge −C) : elles restent sous vote comme tout texte. Un document qui a déjà des modules,
|
||
ou sans titre, est noté et laissé.
|
||
|
||
## Ce que ça coûte
|
||
|
||
- Le seed de l'acte d'engagement passe de 33 à **41 modules à voter** : 33 articles, le titre, et
|
||
l'ordre de 7 sections (l'ordonnancement n'a qu'un article). C17 et les comptes de
|
||
« Décisions » le disent.
|
||
- Les aperçus (« si les bien cotées passent », « si tout passe ») montrent les articles seuls :
|
||
un ordre ou un titre proposé n'y change pas encore la place des articles ni le titre.
|
||
- Un ordre ouvert sur une section revenue à un seul article reste en base, sans être montré ni
|
||
compté.
|
||
- Les codes des nouveaux articles restent `N<n>` (sans lien avec la section), comme avant.
|