Files
decision/maquette/backend/app/engine/threshold.py
T
YvvandClaude Opus 5.5 67ddee28b2 v3 : socle Rust (moteur pur, accès trustinWallet, serveur) ; maquette Nuxt rangée dans maquette/
- crates/ld-engine : formule inertielle (parité avec la maquette, garde C),
  coquille / changement de fond, assistant d'édition à règles, composition
  d'un document sous vote permanent (adoptions, aperçus, rivales).
- crates/trustin-access : qui voit, qui ouvre, qui gère les accès.
- crates/ld-server : API axum + SQLite, connexion Ğ1 (client OAuth2 de
  connect.monnaie-libre.fr), invitations, entrée en vigueur automatique,
  signalements de contradiction, traductions éditoriales, publication git,
  taille de la toile lue sur la chaîne.
- seeds/acte-engagement-certification.json : 33 articles, fr + en + es ;
  en vigueur : préambule, E1, E2 (seed a minima).
- maquette/ : frontend, backend et docker v2 déplacés tels quels.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-21 02:04:42 +02:00

86 lines
2.4 KiB
Python

"""WoT members threshold formula for binary votes.
Core formula:
Result = C + B^W + (M + (1-M) * (1 - (T/W)^G)) * max(0, T - C)
Where:
C = constant_base
B = base_exponent
W = wot_size (corpus of eligible voters)
T = total_votes (for + against)
M = majority_ratio (majority_pct / 100)
G = gradient_exponent
Inertia behaviour:
- Low participation (T << W) -> near-unanimity required
- High participation (T -> W) -> simple majority M suffices
Reference test case:
wot_size=7224, votes_for=97, votes_against=23 (total=120)
params M50 B.1 G.2 => threshold=94, adopted (97 >= 94)
"""
from __future__ import annotations
import math
def wot_threshold(
wot_size: int,
total_votes: int,
majority_pct: int = 50,
base_exponent: float = 0.1,
gradient_exponent: float = 0.2,
constant_base: float = 0.0,
) -> int:
"""Compute the minimum number of *for* votes required for adoption.
Parameters
----------
wot_size:
Size of the eligible voter corpus (WoT members).
total_votes:
Number of votes cast (for + against).
majority_pct:
Majority percentage (0-100). 50 = simple majority at full participation.
base_exponent:
B in the formula. ``B^W`` contributes a vanishingly small offset
when W is large (0 < B < 1).
gradient_exponent:
G controls how fast the required super-majority decays toward M as
participation increases.
constant_base:
C, a fixed additive floor on the threshold.
Returns
-------
int
The ceiling of the computed threshold. A vote passes when
``votes_for >= wot_threshold(...)``.
"""
if wot_size <= 0:
raise ValueError("wot_size doit etre strictement positif")
if total_votes < 0:
raise ValueError("total_votes ne peut pas etre negatif")
if not (0 <= majority_pct <= 100):
raise ValueError("majority_pct doit etre entre 0 et 100")
C = constant_base
B = base_exponent
W = wot_size
T = total_votes
M = majority_pct / 100.0
G = gradient_exponent
# Guard: if no votes, threshold is at least ceil(C + B^W)
if T == 0:
return math.ceil(C + B ** W)
# Core formula
participation_ratio = T / W
inertia_factor = 1.0 - participation_ratio ** G
required_ratio = M + (1.0 - M) * inertia_factor
result = C + B ** W + required_ratio * max(0.0, T - C)
return math.ceil(result)