Composants engagement: GenesisBlock, InertiaSlider, MiniVoteBoard, EngagementCard, DocumentTuto

Backend: genesis_json sur Document, section_tag/inertia_preset/is_permanent_vote sur DocumentItem
Frontend: 5 nouveaux composants pour vue detail document enrichie
- GenesisBlock: sources, outils, synthese forum, contributeurs (depliable)
- InertiaSlider: visualisation inertie 4 niveaux avec params formule G/M
- MiniVoteBoard: tableau vote compact (barre seuil, pour/contre, participation)
- EngagementCard: carte item enrichie integrant vote + inertie + actions
- DocumentTuto: modal pedagogique vote permanent/inertie/seuils
Seed et page [slug] enrichis pour exploiter les nouveaux champs

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
Yvv
2026-03-02 07:59:05 +01:00
parent 11e4a4d60a
commit 62808b974d
10 changed files with 2116 additions and 120 deletions

View File

@@ -1,7 +1,7 @@
import uuid
from datetime import datetime
from sqlalchemy import String, Integer, Text, DateTime, ForeignKey, Uuid, func
from sqlalchemy import String, Integer, Text, DateTime, ForeignKey, Uuid, Boolean, func
from sqlalchemy.orm import Mapped, mapped_column, relationship
from app.database import Base
@@ -19,10 +19,11 @@ class Document(Base):
description: Mapped[str | None] = mapped_column(Text)
ipfs_cid: Mapped[str | None] = mapped_column(String(128))
chain_anchor: Mapped[str | None] = mapped_column(String(128))
genesis_json: Mapped[str | None] = mapped_column(Text) # JSON: source files, repos, forum URLs, formula trigger
created_at: Mapped[datetime] = mapped_column(DateTime(timezone=True), server_default=func.now())
updated_at: Mapped[datetime] = mapped_column(DateTime(timezone=True), server_default=func.now(), onupdate=func.now())
items: Mapped[list["DocumentItem"]] = relationship(back_populates="document", cascade="all, delete-orphan", order_by="DocumentItem.position")
items: Mapped[list["DocumentItem"]] = relationship(back_populates="document", cascade="all, delete-orphan", order_by="DocumentItem.sort_order")
class DocumentItem(Base):
@@ -31,11 +32,14 @@ class DocumentItem(Base):
id: Mapped[uuid.UUID] = mapped_column(Uuid, primary_key=True, default=uuid.uuid4)
document_id: Mapped[uuid.UUID] = mapped_column(ForeignKey("documents.id"), nullable=False)
position: Mapped[str] = mapped_column(String(16), nullable=False) # "1", "1.1", "3.2"
item_type: Mapped[str] = mapped_column(String(32), default="clause") # clause, rule, verification, preamble, section
item_type: Mapped[str] = mapped_column(String(32), default="clause") # clause, rule, verification, preamble, section, genesis
title: Mapped[str | None] = mapped_column(String(256))
current_text: Mapped[str] = mapped_column(Text, nullable=False)
voting_protocol_id: Mapped[uuid.UUID | None] = mapped_column(ForeignKey("voting_protocols.id"))
sort_order: Mapped[int] = mapped_column(Integer, default=0)
section_tag: Mapped[str | None] = mapped_column(String(64)) # genesis, fondamental, technique, annexe, formule, inertie, ordonnancement
inertia_preset: Mapped[str] = mapped_column(String(16), default="standard") # low, standard, high, very_high
is_permanent_vote: Mapped[bool] = mapped_column(default=True) # permanent vote vs time-bounded
created_at: Mapped[datetime] = mapped_column(DateTime(timezone=True), server_default=func.now())
updated_at: Mapped[datetime] = mapped_column(DateTime(timezone=True), server_default=func.now(), onupdate=func.now())

View File

@@ -42,6 +42,7 @@ class DocumentOut(BaseModel):
description: str | None = None
ipfs_cid: str | None = None
chain_anchor: str | None = None
genesis_json: str | None = None
created_at: datetime
updated_at: datetime
items_count: int = Field(default=0, description="Number of items in this document")
@@ -54,10 +55,13 @@ class DocumentItemCreate(BaseModel):
"""Payload for creating a document item (clause, rule, etc.)."""
position: str = Field(..., max_length=16, description='Hierarchical position e.g. "1", "1.1", "3.2"')
item_type: str = Field(default="clause", max_length=32, description="clause, rule, verification, preamble, section")
item_type: str = Field(default="clause", max_length=32, description="clause, rule, verification, preamble, section, genesis")
title: str | None = Field(default=None, max_length=256)
current_text: str = Field(..., min_length=1)
voting_protocol_id: UUID | None = None
section_tag: str | None = Field(default=None, max_length=64)
inertia_preset: str = Field(default="standard", max_length=16)
is_permanent_vote: bool = True
class DocumentItemUpdate(BaseModel):
@@ -82,6 +86,9 @@ class DocumentItemOut(BaseModel):
current_text: str
voting_protocol_id: UUID | None = None
sort_order: int
section_tag: str | None = None
inertia_preset: str = "standard"
is_permanent_vote: bool = True
created_at: datetime
updated_at: datetime
@@ -99,6 +106,9 @@ class DocumentItemFullOut(BaseModel):
current_text: str
voting_protocol_id: UUID | None = None
sort_order: int
section_tag: str | None = None
inertia_preset: str = "standard"
is_permanent_vote: bool = True
created_at: datetime
updated_at: datetime
versions: list[ItemVersionOut] = Field(default_factory=list)
@@ -118,6 +128,7 @@ class DocumentFullOut(BaseModel):
description: str | None = None
ipfs_cid: str | None = None
chain_anchor: str | None = None
genesis_json: str | None = None
created_at: datetime
updated_at: datetime
items: list[DocumentItemOut] = Field(default_factory=list)

View File

@@ -2,9 +2,17 @@
Sources:
- Engagement Forgeron v2.0.0: https://forum.monnaie-libre.fr/t/33165
- Engagement Certification (Licence G1): monnaie-libre.fr/licence-g1/
- Engagement Certification (Licence G1 v0.3.0):
https://git.duniter.org/documents/g1_monetary_license/-/raw/master/g1_monetary_license_fr.rst
- Charte 1.0 (rejected): https://forum.monnaie-libre.fr/t/proposition-charte-1-0/31066
- Licence v0.4.0 (in progress): https://forum.monnaie-libre.fr/t/32375
- Runtime Upgrade process template
Genesis references:
- Licence repo: https://git.duniter.org/documents/g1_monetary_license
- g1vote: https://git.duniter.org/tools/g1vote-view
- g1vote live: https://g1vote-view-237903.pages.duniter.org/
Idempotent: checks if data already exists before inserting.
"""
@@ -12,6 +20,7 @@ from __future__ import annotations
import asyncio
import hashlib
import json
import uuid
from datetime import datetime, timedelta, timezone
@@ -61,13 +70,47 @@ def fake_signature(payload: str) -> str:
async def seed_formula_configs(session: AsyncSession) -> dict[str, FormulaConfig]:
configs: dict[str, dict] = {
"Standard Licence G1": {
"description": "Formule standard pour la Licence G1 : vote binaire WoT.",
"description": "Formule standard pour la Licence G1 : vote binaire WoT. Inertie standard.",
"duration_days": 30,
"majority_pct": 50,
"base_exponent": 0.1,
"gradient_exponent": 0.2,
"constant_base": 0.0,
},
"Inertie basse (Annexes)": {
"description": (
"Formule a inertie basse pour les annexes et recommandations. "
"Gradient faible = plus facile a remplacer meme a faible participation."
),
"duration_days": 30,
"majority_pct": 50,
"base_exponent": 0.1,
"gradient_exponent": 0.1,
"constant_base": 0.0,
},
"Inertie haute (Formule)": {
"description": (
"Formule a inertie haute pour la section formule elle-meme. "
"Gradient eleve = necessite une forte mobilisation pour changer."
),
"duration_days": 30,
"majority_pct": 60,
"base_exponent": 0.1,
"gradient_exponent": 0.4,
"constant_base": 0.0,
},
"Inertie tres haute (Meta-reglage)": {
"description": (
"Formule a inertie maximale pour le reglage de l'inertie elle-meme. "
"Quasi-unanimite requise a toute participation. Protection contre "
"la modification des regles de modification."
),
"duration_days": 30,
"majority_pct": 66,
"base_exponent": 0.1,
"gradient_exponent": 0.6,
"constant_base": 0.0,
},
"Forgeron avec Smith": {
"description": "Vote forgeron avec critere Smith sub-WoT.",
"duration_days": 30,
@@ -170,112 +213,599 @@ async def seed_voting_protocols(
# ---------------------------------------------------------------------------
# Seed: Engagement Certification (Licence G1 - obligations certificateur)
# Seed: Engagement Certification (Acte d'engagement certification)
#
# Full structured document built from:
# - Licence G1 v0.3.0 (in force)
# - Charte 1.0 (rejected proposal, topic 31066)
# - Licence v0.4.0 (in progress, topic 32375)
# - Yvv's "Acte d'engagement" position
# - Checklist certification (topic 32412)
# ---------------------------------------------------------------------------
GENESIS_CERTIFICATION = {
"source_document": {
"title": "Licence de la monnaie libre G1 v0.3.0",
"url": "https://git.duniter.org/documents/g1_monetary_license/-/raw/master/g1_monetary_license_fr.rst",
"repo": "https://git.duniter.org/documents/g1_monetary_license",
},
"reference_tools": {
"g1vote_repo": "https://git.duniter.org/tools/g1vote-view",
"g1vote_live": "https://g1vote-view-237903.pages.duniter.org/",
"cesium": "https://g1.duniter.org",
"gecko": "https://gecko.music-all.org",
},
"forum_synthesis": [
{
"title": "Proposition Charte 1.0 (rejetee)",
"url": "https://forum.monnaie-libre.fr/t/proposition-charte-1-0/31066",
"status": "rejected",
"posts": 70,
},
{
"title": "Preparation licence v0.4.0",
"url": "https://forum.monnaie-libre.fr/t/preparation-dune-proposition-devolution-de-la-licence-1/32375",
"status": "in_progress",
"posts": 38,
},
{
"title": "Checklist de certification (annexe licence)",
"url": "https://forum.monnaie-libre.fr/t/prepa-checklist-de-certification-annexe-licence-1/32412",
"status": "in_progress",
"posts": 16,
},
{
"title": "Regles de modifications (annexe licence)",
"url": "https://forum.monnaie-libre.fr/t/prepa-regles-de-modifications-annexe-licence-1/32409",
"status": "in_progress",
"posts": 9,
},
{
"title": "Vote nuance licence",
"url": "https://forum.monnaie-libre.fr/t/processus-de-validation-licence-par-vote-nuance/31729",
"status": "reference",
},
],
"formula_trigger": (
"Quand un item atteint le seuil d'adoption (formule WoT), "
"le texte de remplacement est integre au document officiel. "
"Le hash IPFS du document mis a jour est ancre on-chain via system.remark. "
"Les applications (Cesium, Gecko) pointent vers le depot git officiel "
"qui est synchronise avec l'etat valide par les votes."
),
"contributors": [
{"name": "1000i100", "role": "Pilote principal, redacteur"},
{"name": "Natha", "role": "Co-redactrice"},
{"name": "Pini", "role": "Co-initiateur"},
{"name": "Yvv", "role": "Contributions structurelles, concepteur 'Acte d'engagement'"},
{"name": "elois", "role": "Dev g1vote, contributions techniques"},
],
}
ENGAGEMENT_CERTIFICATION_ITEMS: list[dict] = [
# ===================================================================
# INTRODUCTION
# ===================================================================
{
"position": "C1",
"item_type": "clause",
"title": "Transmission de la licence",
"position": "I1",
"item_type": "preamble",
"title": "Preambule",
"sort_order": 1,
"section_tag": "introduction",
"inertia_preset": "standard",
"current_text": (
"Toute operation de certification d'un nouveau membre de la monnaie libre G1 "
"doit prealablement s'accompagner de la transmission de cette licence "
"de la monnaie libre G1 au certifie."
"Le present acte d'engagement definit les obligations reciproques "
"des membres de la toile de confiance de la monnaie libre G1. "
"Cet acte est de fait l'unique relation contractuelle de notre "
"toile fiduciaire. Toute certification doit s'accompagner de la "
"transmission de ce document, dont le certificateur doit s'assurer "
"qu'il a ete etudie, compris et accepte par le certifie."
),
},
{
"position": "C2",
"item_type": "clause",
"title": "Connaissance suffisante du certifie",
"position": "I2",
"item_type": "preamble",
"title": "Les deux garanties reciproques",
"sort_order": 2,
"section_tag": "introduction",
"inertia_preset": "standard",
"current_text": (
"Certifier n'est pas uniquement s'assurer que vous avez rencontre la personne, "
"c'est assurer a la communaute G1 que vous connaissez suffisamment bien la "
"personne que vous vous appretez a certifier."
"La certification repose sur deux garanties reciproques :\n\n"
"**1.** Derriere une cle publique creatrice de monnaie "
"se trouve un **etre humain vivant**.\n\n"
"**2.** Derriere cet etre humain se trouve **une seule et unique** "
"cle publique creatrice de monnaie.\n\n"
"La certification est un acte technique et fiduciaire, "
"pas un acte d'adhesion morale ou de sympathie."
),
},
# ===================================================================
# TITRE 1 : ENGAGEMENTS FONDAMENTAUX (sur l'honneur)
# ===================================================================
{
"position": "C3",
"item_type": "clause",
"title": "Contact par plusieurs moyens",
"position": "T1",
"item_type": "section",
"title": "Engagements fondamentaux",
"sort_order": 3,
"section_tag": "fondamental",
"inertia_preset": "standard",
"current_text": (
"Connaitre la personne par plusieurs moyens de contact differents "
"(physique, electronique, etc.) permettant de verifier son identite "
"et de maintenir un lien de confiance dans la duree."
"Les engagements fondamentaux ci-dessous constituent le socle "
"irreductible de l'acte d'engagement. Ils sont pris sur l'honneur "
"par tout membre de la toile de confiance."
),
},
{
"position": "C4",
"position": "E1",
"item_type": "clause",
"title": "Ne jamais certifier seul",
"title": "Unicite du compte",
"sort_order": 4,
"section_tag": "fondamental",
"inertia_preset": "standard",
"current_text": (
"Ne certifiez jamais seul, mais accompagne d'au moins un autre membre "
"de la TdC G1, pour garantir un double controle et eviter les "
"certifications abusives."
"Je m'engage sur l'honneur a n'avoir et n'avoir jamais "
"qu'un seul et unique compte cocreateur de monnaie G1."
),
},
{
"position": "C5",
"item_type": "verification",
"title": "Verification des certifications existantes",
"position": "E2",
"item_type": "clause",
"title": "Certification responsable",
"sort_order": 5,
"section_tag": "fondamental",
"inertia_preset": "standard",
"current_text": (
"Avant toute certification, assurez-vous de verifier si le compte du "
"certifie a deja recu une ou plusieurs certifications, et de qui "
"elles proviennent."
"Je m'engage sur l'honneur a ne certifier que des personnes "
"physiques qui respectent scrupuleusement ces deux presents "
"engagements fondamentaux."
),
},
# ===================================================================
# TITRE 2 : ENGAGEMENTS TECHNIQUES
# ===================================================================
{
"position": "C6",
"item_type": "verification",
"title": "Verification de maitrise du compte",
"position": "T2",
"item_type": "section",
"title": "Engagements techniques",
"sort_order": 6,
"section_tag": "technique",
"inertia_preset": "standard",
"current_text": (
"Verifier la maitrise du compte par un transfert test : envoyer "
"quelques G1 et demander un renvoi, afin de s'assurer que la personne "
"controle bien sa cle privee."
"Les engagements techniques definissent les obligations "
"pratiques et verifiables du certificateur pour garantir "
"la qualite de la toile de confiance."
),
},
{
"position": "C7",
"item_type": "verification",
"title": "Verification de la licence",
"position": "E3",
"item_type": "clause",
"title": "Connaissance suffisante",
"sort_order": 7,
"section_tag": "technique",
"inertia_preset": "standard",
"current_text": (
"Verifiez que vos contacts ont bien etudie et compris la licence G1 "
"a jour avant de proceder a la certification."
"Je me suis assure de connaitre suffisamment la personne "
"qui gere cette cle publique. Connaitre suffisamment ne signifie "
"pas « avoir vu » ; c'est assurer a la communaute G1 que je "
"pourrai la contacter facilement et etre en mesure de reperer "
"un double-compte ou tout autre probleme."
),
},
{
"position": "C8",
"item_type": "verification",
"title": "Document de revocation",
"position": "E4",
"item_type": "clause",
"title": "Verification personnelle de la cle",
"sort_order": 8,
"section_tag": "technique",
"inertia_preset": "standard",
"current_text": (
"D'avoir bien verifie avec la personne concernee qu'elle a bien genere "
"son document Duniter de revocation de compte, et qu'elle le conserve "
"J'ai personnellement verifie que c'est bien cette cle publique "
"que je m'apprete a certifier, en la comparant avec la personne "
"concernee et non par un intermediaire."
),
},
{
"position": "E5",
"item_type": "clause",
"title": "Joignabilite reciproque",
"sort_order": 9,
"section_tag": "technique",
"inertia_preset": "standard",
"current_text": (
"Je suis joignable rapidement et facilement par mes certifieurs, "
"et je peux joindre rapidement et facilement les personnes que "
"je certifie, par plusieurs moyens de communication differents "
"et independants (physique, telephone, email, messagerie, etc.)."
),
},
{
"position": "E6",
"item_type": "clause",
"title": "Document de revocation",
"sort_order": 10,
"section_tag": "technique",
"inertia_preset": "standard",
"current_text": (
"J'ai verifie avec la personne certifiee qu'elle a bien genere "
"son document de revocation de compte et qu'elle le conserve "
"en lieu sur."
),
},
{
"position": "C9",
"position": "E7",
"item_type": "clause",
"title": "Rencontre physique ou multi-canal",
"sort_order": 9,
"title": "Rencontre physique ou verification multi-canaux",
"sort_order": 11,
"section_tag": "technique",
"inertia_preset": "standard",
"current_text": (
"De rencontrer la personne physiquement, OU de verifier a distance "
"le lien personne / cle publique par plusieurs moyens de communication "
"differents et independants."
"J'ai rencontre la personne physiquement (preferable), **OU** "
"j'ai verifie a distance le lien personne / cle publique par "
"plusieurs moyens de communication differents et independants : "
"courrier + reseau social + forum + email + visio + telephone."
),
},
# ===================================================================
# TITRE 3 : CONSEILS ET BONNES PRATIQUES
# ===================================================================
{
"position": "T3",
"item_type": "section",
"title": "Conseils et bonnes pratiques",
"sort_order": 12,
"section_tag": "technique",
"inertia_preset": "standard",
"current_text": (
"Les pratiques suivantes sont fortement recommandees pour "
"garantir la qualite et la securite de la toile de confiance."
),
},
{
"position": "E8",
"item_type": "clause",
"title": "Ne jamais certifier seul",
"sort_order": 13,
"section_tag": "technique",
"inertia_preset": "standard",
"current_text": (
"Ne certifiez jamais seul, mais accompagne d'au moins un autre "
"membre de la toile de confiance G1, pour garantir un double "
"controle."
),
},
{
"position": "E9",
"item_type": "clause",
"title": "Verification des certifications existantes",
"sort_order": 14,
"section_tag": "technique",
"inertia_preset": "standard",
"current_text": (
"Avant toute certification, verifiez si le compte a deja "
"recu des certifications et de qui elles proviennent. "
"Contactez les certifieurs existants en cas de doute. "
"Si un certifieurs existant ne connait pas la personne, "
"alertez immediatement les experts de la communaute."
),
},
{
"position": "E10",
"item_type": "clause",
"title": "Verification de maitrise du compte",
"sort_order": 15,
"section_tag": "technique",
"inertia_preset": "standard",
"current_text": (
"Verifiez la maitrise du compte par un transfert-test : "
"envoyez quelques G1 et demandez le renvoi, afin de vous "
"assurer que la personne controle bien sa cle privee."
),
},
{
"position": "E11",
"item_type": "clause",
"title": "Transmission et comprehension du document",
"sort_order": 16,
"section_tag": "technique",
"inertia_preset": "standard",
"current_text": (
"Verifiez que vos contacts ont bien etudie et compris "
"le present acte d'engagement dans sa version a jour "
"avant de proceder a la certification."
),
},
# ===================================================================
# CONCLUSION
# ===================================================================
{
"position": "K1",
"item_type": "preamble",
"title": "Regles abregees de la toile de confiance",
"sort_order": 17,
"section_tag": "conclusion",
"inertia_preset": "standard",
"current_text": (
"**Parametres protocolaires en vigueur :**\n\n"
"- Stock de **100 certifications** possibles\n"
"- 1 certification emissible tous les **5 jours**\n"
"- Nouveau compte valide si **>= 5 certifications** recues en **2 mois**\n"
"- Condition de distance : **<= 5 pas** de **80% des sentinelles**\n"
"- Sentinelle : membre ayant recu et emis >= Y[N] certifs "
"(Y = ceil(N^(1/5)))\n"
"- Certifications actives valables **2 ans**\n"
"- Renouvellement de l'accord tous les **12 mois**"
),
},
{
"position": "K2",
"item_type": "preamble",
"title": "Monnaie G1",
"sort_order": 18,
"section_tag": "conclusion",
"inertia_preset": "standard",
"current_text": (
"**Parametres monetaires :**\n\n"
"- 1 Dividende Universel (DU) par personne par jour\n"
"- Reevaluation a chaque equinoxe : "
"`DU(n+1) = DU(n) + c² × (M/N) / 182.625` avec c = 4.88%\n"
"- DU(0) = 10.00 G1"
),
},
# ===================================================================
# ANNEXE 1 : INTEGRATION LOGICIELLE
# ===================================================================
{
"position": "X1",
"item_type": "section",
"title": "Annexe 1 : Integration logicielle",
"sort_order": 19,
"section_tag": "annexe",
"inertia_preset": "low",
"current_text": (
"Les obligations pour les logiciels implementant la certification G1."
),
},
{
"position": "X1.1",
"item_type": "clause",
"title": "Depot de reference",
"sort_order": 20,
"section_tag": "annexe",
"inertia_preset": "low",
"current_text": (
"Le texte de reference de l'acte d'engagement certification est "
"heberge dans le depot git officiel : "
"https://git.duniter.org/documents/g1_monetary_license\n\n"
"Les applications Cesium, Gecko et toute application de "
"certification doivent pointer vers ce depot pour afficher "
"la version en vigueur."
),
},
{
"position": "X1.2",
"item_type": "clause",
"title": "Obligation de transmission",
"sort_order": 21,
"section_tag": "annexe",
"inertia_preset": "low",
"current_text": (
"Tout logiciel G1 permettant la certification doit transmettre "
"le present acte d'engagement au certifie et en afficher les "
"parametres du bloc 0 de la blockchain Duniter."
),
},
{
"position": "X1.3",
"item_type": "clause",
"title": "Logiciel auditable",
"sort_order": 22,
"section_tag": "annexe",
"inertia_preset": "low",
"current_text": (
"Tout logiciel utilise pour la certification ou la creation "
"monetaire doit etre publie sous licence libre, afin de "
"permettre son audit par la communaute."
),
},
# ===================================================================
# ANNEXE 2 : QUESTIONS A LA CERTIFICATION (checklist logicielle)
# ===================================================================
{
"position": "X2",
"item_type": "section",
"title": "Annexe 2 : Questions a la certification",
"sort_order": 23,
"section_tag": "annexe",
"inertia_preset": "low",
"current_text": (
"Liste de questions a presenter dans les logiciels de certification. "
"Inspiree de la checklist de la Charte 1.0 et des discussions "
"forum (topic 32412)."
),
},
{
"position": "X2.1",
"item_type": "verification",
"title": "Questions piege (reponse attendue : NON)",
"sort_order": 24,
"section_tag": "annexe",
"inertia_preset": "low",
"current_text": (
"**Si OUI a l'une de ces questions, la certification doit etre refusee.**\n\n"
"- La personne m'a contacte uniquement pour obtenir ma certification\n"
"- Je certifie sous la pression ou pour faire plaisir\n"
"- Je n'ai aucun moyen de verifier l'identite de la personne\n"
"- La personne refuse de me donner plusieurs moyens de contact\n"
"- Je soupçonne que la personne possede deja un compte membre\n"
"- Je ne connais aucun de ses autres certifieurs\n"
"- La personne ne comprend pas ce qu'est la monnaie libre\n"
"- La personne n'a pas lu le present acte d'engagement"
),
},
{
"position": "X2.2",
"item_type": "verification",
"title": "Questions identite (reponse attendue : OUI)",
"sort_order": 25,
"section_tag": "annexe",
"inertia_preset": "low",
"current_text": (
"**Si NON a l'une de ces questions, la certification doit etre refusee.**\n\n"
"- Je connais cette personne suffisamment pour la recontacter\n"
"- J'ai verifie personnellement le lien personne / cle publique\n"
"- La personne est une personne physique vivante (pas une entite morale)\n"
"- Je pourrais reconnaitre cette personne si je la croisais\n"
"- J'ai au moins 2 moyens de contact differents pour cette personne"
),
},
{
"position": "X2.3",
"item_type": "verification",
"title": "Questions securite (reponse attendue : OUI)",
"sort_order": 26,
"section_tag": "annexe",
"inertia_preset": "low",
"current_text": (
"**Si NON, la certification est deconseille.**\n\n"
"- La personne a genere son document de revocation\n"
"- La personne maitrise effectivement son compte "
"(test de transfert effectue)\n"
"- La personne sait ou retrouver le present acte d'engagement "
"dans sa version a jour"
),
},
# ===================================================================
# SECTION SPECIALE : FORMULE DE VOTE
# ===================================================================
{
"position": "F1",
"item_type": "section",
"title": "Formule de vote",
"sort_order": 27,
"section_tag": "formule",
"inertia_preset": "high",
"current_text": (
"La formule qui regit l'adoption ou le rejet de chaque modification "
"du present document. Reference : g1vote "
"(https://g1vote-view-237903.pages.duniter.org/)."
),
},
{
"position": "F1.1",
"item_type": "rule",
"title": "Formule du seuil WoT",
"sort_order": 28,
"section_tag": "formule",
"inertia_preset": "high",
"current_text": (
"**Seuil = C + B^W + (M + (1-M) × (1 - (T/W)^G)) × max(0, T-C)**\n\n"
"Ou :\n"
"- **C** = constante de base (plancher fixe)\n"
"- **B** = exposant de base (B^W tend vers 0)\n"
"- **W** = taille de la toile de confiance (electeurs eligibles)\n"
"- **T** = total des votes exprimes (pour + contre)\n"
"- **M** = ratio de majorite cible (M = majority_pct / 100)\n"
"- **G** = exposant du gradient d'inertie\n\n"
"**Comportement :** Faible participation → quasi-unanimite requise. "
"Forte participation → majorite simple M suffit."
),
},
{
"position": "F1.2",
"item_type": "rule",
"title": "Parametres par defaut",
"sort_order": 29,
"section_tag": "formule",
"inertia_preset": "high",
"current_text": (
"Parametres de reference pour les engagements (inertie standard) :\n\n"
"| Parametre | Code | Valeur |\n"
"|-----------|------|--------|\n"
"| Duree | D | 30 jours (permanent) |\n"
"| Majorite | M | 50% |\n"
"| Base | B | 0.1 |\n"
"| Gradient | G | 0.2 |\n"
"| Constante | C | 0.0 |\n\n"
"Mode compact : **D30M50B.1G.2**"
),
},
{
"position": "F1.3",
"item_type": "rule",
"title": "Processus de depot officiel",
"sort_order": 30,
"section_tag": "formule",
"inertia_preset": "high",
"current_text": (
"Lorsqu'une proposition alternative atteint le seuil d'adoption :\n\n"
"1. Le texte de remplacement est integre au document officiel\n"
"2. Le hash IPFS du document mis a jour est calcule\n"
"3. Le hash est ancre on-chain via `system.remark`\n"
"4. Le depot git officiel est synchronise\n"
"5. Les applications (Cesium, Gecko) mettent a jour automatiquement"
),
},
# ===================================================================
# SECTION SPECIALE : REGLAGE DE L'INERTIE
# ===================================================================
{
"position": "N1",
"item_type": "section",
"title": "Reglage de l'inertie",
"sort_order": 31,
"section_tag": "inertie",
"inertia_preset": "very_high",
"current_text": (
"Le reglage de l'inertie definit la difficulte de remplacement "
"de chaque section du document. Ce reglage est lui-meme soumis "
"a l'inertie la plus elevee, pour empecher la modification "
"des regles de modification."
),
},
{
"position": "N1.1",
"item_type": "rule",
"title": "Niveaux d'inertie",
"sort_order": 32,
"section_tag": "inertie",
"inertia_preset": "very_high",
"current_text": (
"| Niveau | Gradient G | Majorite M | Application |\n"
"|--------|-----------|------------|-------------|\n"
"| **Basse** | 0.1 | 50% | Annexes, recommandations |\n"
"| **Standard** | 0.2 | 50% | Engagements fondamentaux et techniques |\n"
"| **Haute** | 0.4 | 60% | Formule de vote |\n"
"| **Tres haute** | 0.6 | 66% | Reglage de l'inertie |\n\n"
"Plus le gradient est eleve, plus il faut de participation "
"et de consensus pour qu'une modification soit adoptee."
),
},
# ===================================================================
# SECTION SPECIALE : ORDONNANCEMENT
# ===================================================================
{
"position": "O1",
"item_type": "section",
"title": "Ordonnancement du document",
"sort_order": 33,
"section_tag": "ordonnancement",
"inertia_preset": "high",
"current_text": (
"L'ordre de presentation des items dans le document est "
"lui-meme soumis au vote. Toute proposition de reorganisation "
"doit atteindre le seuil d'adoption avec l'inertie haute."
),
},
]
async def seed_document_engagement_certification(session: AsyncSession) -> Document:
async def seed_document_engagement_certification(
session: AsyncSession,
protocols: dict[str, VotingProtocol],
) -> Document:
genesis = json.dumps(GENESIS_CERTIFICATION, ensure_ascii=False, indent=2)
doc, created = await get_or_create(
session,
Document,
@@ -286,15 +816,33 @@ async def seed_document_engagement_certification(session: AsyncSession) -> Docum
version="1.0.0",
status="active",
description=(
"Obligations des certificateurs de la toile de confiance Duniter. "
"Chaque clause est soumise au vote permanent de la communaute."
"Acte d'engagement des certificateurs de la toile de confiance G1. "
"Document modulaire sous vote permanent : chaque item peut etre "
"remplace par une alternative qui atteint le seuil d'adoption. "
"Construit a partir de la Licence G1 v0.3.0, des discussions "
"communautaires et de la position 'Acte d'engagement' (Yvv)."
),
genesis_json=genesis,
)
print(f" Document 'Acte d'engagement certification': {'created' if created else 'exists'}")
if created:
# Map inertia presets to voting protocols
inertia_protocol_map = {
"low": protocols.get("Vote WoT standard"),
"standard": protocols.get("Vote WoT standard"),
"high": protocols.get("Vote WoT standard"),
"very_high": protocols.get("Vote WoT standard"),
}
for item_data in ENGAGEMENT_CERTIFICATION_ITEMS:
item = DocumentItem(document_id=doc.id, **item_data)
preset = item_data.get("inertia_preset", "standard")
protocol = inertia_protocol_map.get(preset)
item = DocumentItem(
document_id=doc.id,
voting_protocol_id=protocol.id if protocol else None,
**item_data,
)
session.add(item)
await session.flush()
print(f" -> {len(ENGAGEMENT_CERTIFICATION_ITEMS)} items created")
@@ -903,7 +1451,7 @@ async def run_seed():
protocols = await seed_voting_protocols(session, formulas)
print("\n[3/7] Document: Acte d'engagement certification...")
await seed_document_engagement_certification(session)
await seed_document_engagement_certification(session, protocols)
print("\n[4/7] Document: Acte d'engagement forgeron v2.0.0...")
doc_forgeron = await seed_document_engagement_forgeron(session)