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

@@ -32,9 +32,52 @@ export interface VotingProtocol {
formula_config: FormulaConfig
}
export interface ProtocolCreate {
name: string
description: string | null
vote_type: string
formula_config_id: string
}
export interface FormulaCreate {
name: string
description?: string | null
duration_days: number
majority_pct: number
base_exponent: number
gradient_exponent: number
constant_base: number
smith_exponent?: number | null
techcomm_exponent?: number | null
nuanced_min_participants?: number | null
nuanced_threshold_pct?: number | null
}
export interface SimulateParams {
wot_size: number
total_votes: number
majority_pct: number
base_exponent: number
gradient_exponent: number
constant_base: number
smith_wot_size?: number
smith_exponent?: number
techcomm_size?: number
techcomm_exponent?: number
}
export interface SimulateResult {
threshold: number
smith_threshold: number | null
techcomm_threshold: number | null
inertia_factor: number
required_ratio: number
}
interface ProtocolsState {
protocols: VotingProtocol[]
formulas: FormulaConfig[]
currentProtocol: VotingProtocol | null
loading: boolean
error: string | null
}
@@ -43,6 +86,7 @@ export const useProtocolsStore = defineStore('protocols', {
state: (): ProtocolsState => ({
protocols: [],
formulas: [],
currentProtocol: null,
loading: false,
error: null,
}),
@@ -96,5 +140,89 @@ export const useProtocolsStore = defineStore('protocols', {
this.loading = false
}
},
/**
* Fetch a single protocol by ID.
*/
async fetchProtocolById(id: string) {
this.loading = true
this.error = null
try {
const { $api } = useApi()
this.currentProtocol = await $api<VotingProtocol>(`/protocols/${id}`)
} catch (err: any) {
this.error = err?.data?.detail || err?.message || 'Protocole introuvable'
} finally {
this.loading = false
}
},
/**
* Create a new voting protocol.
*/
async createProtocol(data: ProtocolCreate) {
this.loading = true
this.error = null
try {
const { $api } = useApi()
const protocol = await $api<VotingProtocol>('/protocols/', {
method: 'POST',
body: data,
})
this.protocols.push(protocol)
return protocol
} catch (err: any) {
this.error = err?.data?.detail || err?.message || 'Erreur lors de la creation du protocole'
throw err
} finally {
this.loading = false
}
},
/**
* Create a new formula configuration.
*/
async createFormula(data: FormulaCreate) {
this.loading = true
this.error = null
try {
const { $api } = useApi()
const formula = await $api<FormulaConfig>('/protocols/formulas', {
method: 'POST',
body: data,
})
this.formulas.push(formula)
return formula
} catch (err: any) {
this.error = err?.data?.detail || err?.message || 'Erreur lors de la creation de la formule'
throw err
} finally {
this.loading = false
}
},
/**
* Simulate formula computation on the backend.
*/
async simulate(params: SimulateParams) {
this.loading = true
this.error = null
try {
const { $api } = useApi()
return await $api<SimulateResult>('/protocols/simulate', {
method: 'POST',
body: params,
})
} catch (err: any) {
this.error = err?.data?.detail || err?.message || 'Erreur lors de la simulation'
throw err
} finally {
this.loading = false
}
},
},
})