forked from yvv/decision
v2 : conception ultracode + moteur de formules porté en TS
- Blueprint définitif (docs/dev/BLUEPRINT-V2.md + JSON) : panel 4 visions + 3 juges, corpus doctrinal (Mon nom est personne, Une économie du don, SejeteralO), 4 critiques d'intégration, 3 vérificateurs, réparations - Corpus d'intention + lectures brutes archivés - Moteur porté Python→TS pur : threshold (inertie WoT, Smith, ComTech), nuancé 6 niveaux, DSL modeParams — 45 tests vitest, parité croisée vérifiée (Forgeron W=7224 T=120 ⇒ 94) - Contrat de domaine v2 (types/domain.ts) + lexique UI (lexicon.ts) - vitest + idb-keyval en dépendances Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
@@ -0,0 +1,110 @@
|
||||
/**
|
||||
* WoT members threshold formula for binary votes.
|
||||
*
|
||||
* Exact TypeScript port of backend/app/engine/threshold.py,
|
||||
* smith_threshold.py and techcomm_threshold.py (Python is the
|
||||
* reference implementation — same guards, same ceil rounding).
|
||||
*
|
||||
* Core formula:
|
||||
* Result = C + B^W + (M + (1-M) * (1 - (T/W)^G)) * max(0, T - C)
|
||||
*
|
||||
* Where:
|
||||
* C = constantBase
|
||||
* B = baseExponent
|
||||
* W = wotSize (corpus of eligible voters)
|
||||
* T = totalVotes (for + against)
|
||||
* M = majorityRatio (majorityPct / 100)
|
||||
* G = gradientExponent
|
||||
*
|
||||
* Inertia behaviour:
|
||||
* - Low participation (T << W) -> near-unanimity required
|
||||
* - High participation (T -> W) -> simple majority M suffices
|
||||
*
|
||||
* Reference test case:
|
||||
* wotSize=7224, votesFor=97, votesAgainst=23 (total=120)
|
||||
* params M50 B.1 G.2 => threshold=94, adopted (97 >= 94)
|
||||
*/
|
||||
|
||||
/**
|
||||
* Compute the minimum number of *for* votes required for adoption.
|
||||
*
|
||||
* A vote passes when `votesFor >= wotThreshold(...)`.
|
||||
*
|
||||
* @param wotSize - Size of the eligible voter corpus (WoT members)
|
||||
* @param totalVotes - Number of votes cast (for + against)
|
||||
* @param majorityPct - Majority percentage (0-100). 50 = simple majority at full participation
|
||||
* @param baseExponent - B in the formula; B^W is a vanishingly small offset when W is large
|
||||
* @param gradientExponent - G controls how fast the super-majority decays toward M
|
||||
* @param constantBase - C, a fixed additive floor on the threshold
|
||||
* @returns The ceiling of the computed threshold
|
||||
*/
|
||||
export function wotThreshold(
|
||||
wotSize: number,
|
||||
totalVotes: number,
|
||||
majorityPct: number = 50,
|
||||
baseExponent: number = 0.1,
|
||||
gradientExponent: number = 0.2,
|
||||
constantBase: number = 0.0,
|
||||
): number {
|
||||
if (wotSize <= 0) {
|
||||
throw new Error('wotSize doit etre strictement positif')
|
||||
}
|
||||
if (totalVotes < 0) {
|
||||
throw new Error('totalVotes ne peut pas etre negatif')
|
||||
}
|
||||
if (majorityPct < 0 || majorityPct > 100) {
|
||||
throw new Error('majorityPct doit etre entre 0 et 100')
|
||||
}
|
||||
|
||||
const C = constantBase
|
||||
const B = baseExponent
|
||||
const W = wotSize
|
||||
const T = totalVotes
|
||||
const M = majorityPct / 100.0
|
||||
const G = gradientExponent
|
||||
|
||||
// Guard: if no votes, threshold is at least ceil(C + B^W)
|
||||
if (T === 0) {
|
||||
return Math.ceil(C + B ** W)
|
||||
}
|
||||
|
||||
// Core formula
|
||||
const participationRatio = T / W
|
||||
const inertiaFactor = 1.0 - participationRatio ** G
|
||||
const requiredRatio = M + (1.0 - M) * inertiaFactor
|
||||
const result = C + B ** W + requiredRatio * Math.max(0.0, T - C)
|
||||
|
||||
return Math.ceil(result)
|
||||
}
|
||||
|
||||
/**
|
||||
* Smith sub-WoT threshold criterion.
|
||||
*
|
||||
* Formula: ceil(smithWotSize ^ S)
|
||||
*
|
||||
* @param smithWotSize - Number of active Smith members (forgerons)
|
||||
* @param exponent - S in the formula
|
||||
* @returns Minimum Smith votes required
|
||||
*/
|
||||
export function smithThreshold(smithWotSize: number, exponent: number = 0.1): number {
|
||||
if (smithWotSize <= 0) {
|
||||
throw new Error('smithWotSize doit etre strictement positif')
|
||||
}
|
||||
return Math.ceil(smithWotSize ** exponent)
|
||||
}
|
||||
|
||||
/**
|
||||
* Technical Committee threshold criterion.
|
||||
*
|
||||
* Formula: ceil(cotecSize ^ T)
|
||||
*
|
||||
* @param cotecSize - Number of Technical Committee members
|
||||
* @param exponent - T in the formula
|
||||
* @returns Minimum TechComm votes required
|
||||
*/
|
||||
export function techcommThreshold(cotecSize: number, exponent: number = 0.1): number {
|
||||
if (cotecSize <= 0) {
|
||||
throw new Error('cotecSize doit etre strictement positif')
|
||||
}
|
||||
return Math.ceil(cotecSize ** exponent)
|
||||
}
|
||||
Reference in New Issue
Block a user