Files
decision/CLAUDE.md
T
YvvandClaude Opus 5.5 40ab6e41c5 Lot S, phase 2 : le quorum documenté (ADR 0013, notes dans 0002 et 0007, CHANTIER, CONTROLES, CLAUDE.md)
ADR 0013 : la formule sur T' = max(T, Q), « Ils comptent comme non » dans
threshold::judged_voters, les quorums par cran 12 · 12 · 50 · 50 · 50 (1 dans le
groupe d'essai), le quorum d'un article fixé par l'auteur avant le premier vote
(« un vote existe » : quorum::voted_units, la limite du vote retiré), p0 = 2Q₀/W,
l'amendement 2026-11-03-quorums-par-cran, les nombres, le coût (une voix passe
dans le groupe d'essai ; F1.1 et N1.1 du seed décrivent encore C).

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-11-03 05:15:18 +01:00

152 lines
12 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# libreDecision
Rendre possible la décision collective — en fonction du contexte, processus et modalités,
boîte à outils. **v3 : Rust + Svelte**, un chantier à la fois, chacun livré en production avant
le suivant (`docs/chantiers/README.md`).
**Référence du chantier en cours : `docs/chantiers/acte-certification/CHANTIER.md`** — toute
décision de comportement s'y adosse ; les décisions durables dans `docs/adr/`.
La maquette v2 (Nuxt + FastAPI) vit dans `maquette/`, **intacte** (Yvv la présente) — ne pas y
développer.
## Protocole de début de session
1. `git pull --rebase origin main` (puis la branche du chantier : `chantier/acte-certification`)
2. Lire `HANDOFF.md` (où on en est, ce qui attend Yvv)
3. Si l'objectif de la session n'est pas précisé, le demander
## Stack
- **Serveur** : Rust edition 2024, toolchain **1.99** épinglée (`rust-toolchain.toml`) ;
rustup installé sans PATH → `export PATH=$HOME/.cargo/bin:$PATH`. axum 0.8, sqlx 0.8
(SQLite, requêtes runtime + `migrate!`), tokio, reqwest rustls.
- **Interface** : SvelteKit 2 / Svelte 5 (runes), adapter-static SPA, vite 7, vitest,
Playwright ; npm. Polices Literata (textes) + Nunito (interface), fontsource.
- **Ports** : dev interface **3002** (strict, proxy `/api` → 8002) · serveur **8002** ·
serveur jetable des e2e **8092** (sa chaîne Ğ1 simulée prend un port local éphémère).
- **Déploiement** : une image (`docker/app.Dockerfile`), Woodpecker `ci.open.us.org` dépôt
LPK/decision → sonic (fabio). `.woodpecker/app.yml` = le produit sur
**decision.librodrome.org** ; `.woodpecker/maquette.yml` = la maquette sur
**maquette.decision.librodrome.org** (le produit passe en premier et retire de la racine tout conteneur qui la revendique ; la maquette attend un déploiement réussi du produit).
Push sur `prod` (`gitea@git.open.us.org:EHV/decision.git`) branche `main` = déploiement.
## Structure
```
crates/
ld-engine/ # PUR (zéro I/O) : threshold (formule inertielle sur un quorum, judged_voters,
# yes_needed / no_needed), inertia (cinq crans, leurs quorums, bornes, médiane,
# référence, échelle), edit (coquille vs fond, diff), assist (découpage, similarité,
# longueur), compose (adoption, aperçus), ballot (bulletin scellé ld1:, le dernier
# fait foi, jugement d'une transaction), address (SS58, préfixe g1), objection
# (redit / contredit : la dernière arrivée retenue, les tours, l'échéance), correction
# (la coquille d'un autre : attendre, valider, refuser, l'échéance), order (l'ordre
# d'une section : qui en est, complété à la fin, places), pending (modules à voter)
trustin-access/ # règles d'accès de trustinWallet : sees / opens / manages_access, vote_way (serveur ou
# chaîne), answers_typo, lifts_objection / reiterates_objection, reads_message,
# sets_quorum, groupes par défaut (TEST_GROUP)
ld-server/
migrations/ # schéma SQLite — additif seulement
src/ # lib.rs (routes, csrf, run) · config.rs (LD_*) · auth.rs (connect OAuth2, invitations,
# dev, bootstrap) · team.rs (liens d'équipe) · docs.rs (lecture, aperçus) · proposals.rs (écrire, voter,
# traduire) · objections.rs (faire, lever, réitérer, la version retenue) · typos.rs
# (les coquilles des autres) · messages.rs (la boîte « Messages ») · deadlines.rs
# (les échéances de 3 jours) · clock.rs (horloge injectable) · adoption.rs
# (balayage, verrou) · participation.rs (p̃, une fois par
# jour) · publish.rs (file → git) · wot.rs (W sur la chaîne) · seed.rs ·
# seed_amend.rs / inertia_amend.rs / seed_proposal_amend.rs (amendements gardés ;
# le dernier fait des Propositions seed, ADR 0011) · ballots.rs (vote groupé,
# bulletins de la chaîne Ğ1, confirmation, « ton vote ») · indexer.rs (txComments)
# · modules.rs / order.rs / doc_title.rs (les modules, ADR 0009 : l'ordre d'une
# section, le titre du document) · module_amend.rs (ajout gardé) · quorum.rs (le quorum
# d'un article, PUT /units/{id}/quorum ; « un vote existe » : voted_units, ADR 0013) ·
# quorum_amend.rs (les quorums par cran, amendement gardé) · web.rs (sert web/build)
tests/ # api.rs (scénarios bout en bout) · ballots.rs (vote par la chaîne, indexeur simulé) ·
# objections.rs · typos.rs (lot F, horloge avancée, migration 0008) · modules.rs (ordre,
# titre, ajout gardé) · seed_proposals.rs (Propositions seed, publication suspendue) ·
# quorum.rs (quorums par cran, la route, « un vote existe », l'amendement) ·
# fixtures/seed-production-2026-11-02/ (le seed que la production fait tourner :
# I1/E1/E2 en vigueur, pour rejouer les amendements sur une base comme elle)
seeds/ # acte-engagement-certification.json (trilingue, 33 articles, aucun en vigueur ;
# I1/E1/E2 Propositions seed au cran 2 (seed::SEED_PROPOSAL_LEVEL), inertie 3 ailleurs ;
# modules en vigueur sans vote : le titre à 4, l'ordre de chaque section à 2 ;
# quorums par cran : 12 · 12 · 50 · 50 · 50 Monnaie libre, 1 partout essai)
# upcoming/<groupe>.json : les « À venir » des outils d'un groupe (fr, en, es), lus au démarrage
web/src/
lib/i18n/ # fr.ts SOURCE (types Key) · en.ts · es.ts — parité testée
lib/components/ # Sidebar, DocPanel, VoteFold (le vote déplié sous l'article), BallotPanel (panier),
# ChainSign (signature, Ğecko), VersionDetails, ProposeView, UnitBlock, DeepList,
# OrderModule / OrderEditor (l'ordre d'une section, la liste où l'on clique),
# TitleBar / TitlePropose (le titre du document), Seal…
lib/wallet/ # injected.ts (portefeuille injectedWeb3, polkadot-api chargé à la signature) · gecko.ts
lib/basket.ts # PUR : sections, tout pour / tout contre, versions en concurrence, versions retenues, modules
lib/objections.ts # où l'auteur répond à une objection · lib/diff.ts : le diff resserré d'une coquille
lib/order.ts # PUR : placer, monter / descendre, ce qui a bougé
routes/ # / (accueil + choix du groupe) · connexion · invitation · equipe · g/[group] (piliers, en cours) ·
# g/[group]/docs · g/[group]/docs/[doc] (lecteur,
# vote déplié ?vote=, panneau ?onglet=panier|propositions|proposer|details|reglages)
# · g/[group]/decisions · g/[group]/mandats ·
# g/[group]/protocoles (à venir) · acces (trustinWallet) · messages (la boîte) ;
# /groupes, /decisions… redirigent
web/e2e/ # Playwright C1–C33 + M1 ; serve.sh = serveur jetable /tmp/ld-e2e sur :8092 et
# chain-mock.mjs (nœud et indexeur Ğ1 simulés) ; faux portefeuille dans helpers.ts
docker/ # app.Dockerfile · app-compose.yml (sonic)
.woodpecker/ # app.yml · maquette.yml
docs/ # chantiers/ · adr/ · dev/BLUEPRINT-V2.md (doctrine de la maquette) · recherche/
maquette/ # v2 intacte (frontend Nuxt, backend FastAPI, docker, docs-v1)
```
## Données runtime — jamais écrasées
- **Production** : volume `lpk-libredecision-app_data` (`/data` : `libredecision.db`, `textes/`
= clone du dépôt publié, `keys/` = clé de publication, `bootstrap-admin.txt`). Jamais
`down -v`, jamais recréé.
- **Maquette** : volumes `lpk-decision-main_postgres-data` / `_ipfs-data` (inchangés).
- **Local** : `data/` (gitignoré) — le supprimer repart du seed. Les e2e utilisent `/tmp/ld-e2e`.
- Un document seedé n'est **jamais** réinstancié : dès qu'il existe en base, c'est de la donnée.
## Commandes — la boucle (tout vert = fait)
```bash
export PATH=$HOME/.cargo/bin:$PATH
cargo fmt --all --check && cargo clippy --workspace --all-targets -- -D warnings && cargo test --workspace
cd web && npm run check && npm test && npm run build && npm run e2e # e2e : 34 contrôles (35 tests, C25 en deux)
LD_DEV_LOGIN=1 cargo run -p ld-server # :8002, sert web/build
cd web && npm run dev # :3002 à chaud
docker build -f docker/app.Dockerfile --target production . # rejoue toute la boucle
```
## Conventions / pièges
- **UI français, code anglais** ; **trilingue** : aucune chaîne affichée en dur, tout passe par
`web/src/lib/i18n/fr.ts` puis en/es (test de parité + `FORBIDDEN_UI_TERMS`). Tutoyer ; le sujet
est la personne ou le groupe, jamais le système. Le français du texte voté fait foi.
- **Moteur pur** : une règle de vote / édition / composition s'écrit et se teste dans
`ld-engine` avant d'être câblée. Le serveur ne décide jamais l'accès seul : `trustin-access`.
- **Invariants** : au départ, aucun article n'est en vigueur : I1, E1 et E2 sont des Propositions
seed (ouvertes, mises en avant, au cran 2 ; seuls les modules sont des *seeds a minima*), et la
publication d'un document attend son premier texte en vigueur (ADR 0011) ; un quorum par cran
(12 · 12 · 50 · 50 · 50 dans Monnaie libre), que l'auteur d'un article change avant le premier
vote : sous le quorum, les votants qui manquent comptent comme « non », et une seule voix ne fait
jamais passer un texte (quorum ≥ 2), sauf dans le groupe d'essai (quorum 1 ; ADR 0013) ;
une coquille ne demande pas de vote, un changement de fond si ; la coquille d'un autre attend
son auteur (un administrateur pour le seed) ou 3 jours, et en vigueur seule une coquille validée
change le texte ; une objection retient la dernière arrivée jusqu'à sa levée (jamais un texte en
vigueur ; ADR 0010) : elle n'entre pas en vigueur, et on peut y retirer son vote ou passer à
« contre », jamais ajouter un « pour » (Yvv, 01/11/2026 : « Retirer ou "contre" ») ; l'inertie de l'inertie hérite du cran de l'article (cinq crans, ADR 0007) ;
le groupe d'essai ne publie jamais ; dans Monnaie libre, un vote est une transaction Ğ1 et le
dernier fait foi dans l'ordre de la chaîne (ADR 0008) — **jamais de transaction réelle en test**
(chaîne simulée ; un essai réel est un acte « paye » d'Yvv).
- **Écritures** : en-tête `x-requested-with: libredecision` obligatoire (CSRF) ; cookie
`ld_session`. Les tests d'API passent par `Client` (`tests/api.rs`).
- **Pièges vus** : `pkill -f target/debug/ld-server` tue son propre shell → `pkill -x ld-server` ;
un `from_secret` absent fait refuser tout le pipeline Woodpecker ; la route hôte `/*` de fabio
masque le webroot ACME → arrêter le service avant `acme.sh --issue` ; Playwright en locale
`fr-FR` (sinon l'interface part en anglais).
- **Design** : sans bordures, arrondis 16/12/20/14, quatre ambiances `pierre`, `calcaire`
(claires), `nuit`, `ardoise` (sombres) (`data-mood`, posé avant le premier rendu, clé `ld:mood`), logo
« Clé de voûte » (`Logo`, jamais incliné, `--cle` par ambiance), sceau hexagramme 井 #48 en SVG (`Seal` —
jamais le glyphe, qui s'affiche mal). Mouvement réduit respecté.
- **Domaine** : decision.librodrome.org ; dépôt des textes `git.open.us.org/yvv/decision-depot-textes-reference`
(provisoire : puis un dépôt pour l'ouverture, puis le dépôt officiel pour les textes en vigueur).