Sprint 3 : protocoles de vote et boite a outils

Backend:
- Sessions de vote : list, close, tally, threshold details, auto-expiration
- Protocoles : update, simulate, meta-gouvernance, formulas CRUD
- Service vote enrichi : close_session, get_threshold_details, nuanced breakdown
- Schemas : ThresholdDetailOut, VoteResultOut, FormulaSimulationRequest/Result
- WebSocket broadcast sur chaque vote + fermeture session
- 25 nouveaux tests (threshold details, close, nuanced, simulation)

Frontend:
- 5 composants vote : VoteBinary, VoteNuanced, ThresholdGauge, FormulaDisplay, VoteHistory
- 3 composants protocoles : ProtocolPicker, FormulaEditor, ModeParamsDisplay
- Simulateur de formules interactif (page /protocols/formulas)
- Page detail protocole (/protocols/[id])
- Composable useWebSocket (live updates)
- Composable useVoteFormula (calcul client-side reactif)
- Integration KaTeX pour rendu LaTeX des formules

Documentation:
- API reference : 8 nouveaux endpoints documentes
- Formules : tables d'inertie, parametres detailles, simulation API
- Guide vote : vote binaire/nuance, jauge, historique, simulateur, meta-gouvernance

55 tests passes (+ 1 skipped), 126 fichiers total.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
Yvv
2026-02-28 13:29:31 +01:00
parent 2bdc731639
commit cede2a585f
25 changed files with 3964 additions and 188 deletions

View File

@@ -0,0 +1,98 @@
/**
* Composable for real-time vote formula computation.
*
* Re-exports and wraps the threshold utility functions for reactive use
* in Vue components. Provides convenient methods for threshold calculations,
* inertia factor, required ratio, and adoption checks.
*/
import { wotThreshold, smithThreshold, techcommThreshold } from '~/utils/threshold'
export interface FormulaParams {
majority_pct: number
base_exponent: number
gradient_exponent: number
constant_base: number
}
export function useVoteFormula() {
/**
* Compute the WoT threshold for a given set of parameters.
*/
function computeThreshold(wotSize: number, totalVotes: number, params: FormulaParams): number {
return wotThreshold(
wotSize,
totalVotes,
params.majority_pct,
params.base_exponent,
params.gradient_exponent,
params.constant_base,
)
}
/**
* Compute the inertia factor: 1 - (T/W)^G
* Ranges from ~1 (low participation) to ~0 (full participation).
*/
function computeInertiaFactor(
totalVotes: number,
wotSize: number,
gradientExponent: number,
): number {
if (wotSize <= 0 || totalVotes <= 0) return 1.0
const participationRatio = totalVotes / wotSize
return 1.0 - Math.pow(participationRatio, gradientExponent)
}
/**
* Compute the required ratio of "pour" votes at a given participation level.
* requiredRatio = M + (1 - M) * inertiaFactor
*/
function computeRequiredRatio(
totalVotes: number,
wotSize: number,
majorityPct: number,
gradientExponent: number,
): number {
const M = majorityPct / 100
const inertia = computeInertiaFactor(totalVotes, wotSize, gradientExponent)
return M + (1.0 - M) * inertia
}
/**
* Check whether a vote is adopted given all criteria.
* A vote is adopted when it passes the WoT threshold AND
* any applicable Smith/TechComm criteria.
*/
function isAdopted(
votesFor: number,
threshold: number,
smithVotesFor?: number,
smithThresholdVal?: number,
techcommVotesFor?: number,
techcommThresholdVal?: number,
): boolean {
// Main WoT criterion
if (votesFor < threshold) return false
// Smith criterion (if applicable)
if (smithThresholdVal !== undefined && smithThresholdVal > 0) {
if ((smithVotesFor ?? 0) < smithThresholdVal) return false
}
// TechComm criterion (if applicable)
if (techcommThresholdVal !== undefined && techcommThresholdVal > 0) {
if ((techcommVotesFor ?? 0) < techcommThresholdVal) return false
}
return true
}
return {
computeThreshold,
computeInertiaFactor,
computeRequiredRatio,
isAdopted,
smithThreshold,
techcommThreshold,
}
}