forked from yvv/decision
v3 : relecture de a576b68 — les propositions retirées sortent de la médiane, les réglages montrent la vraie participation
La médiane de participation ne compte plus les propositions retirées (invisibles, votes non repris). Quand l'échelle ramène la participation dans ses bornes, les réglages disent la médiane mesurée (ou deux fois C) et, à part, la valeur sur laquelle les seuils se calculent. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
@@ -6,6 +6,7 @@
|
||||
import { api } from '$lib/api';
|
||||
import type { DocState } from '$lib/doc.svelte';
|
||||
import { i18n, t } from '$lib/i18n/index.svelte';
|
||||
import { usualShown } from '$lib/participation';
|
||||
import type { Inertia, LevelInfo } from '$lib/types';
|
||||
|
||||
let { doc, proposalId = null }: { doc: DocState; proposalId?: string | null } = $props();
|
||||
@@ -33,6 +34,7 @@
|
||||
|
||||
const view = $derived(doc.view);
|
||||
const p = $derived(view?.doc.participation);
|
||||
const shown = $derived(p && view ? usualShown(p, view.doc.electorate, view.doc.voteFloor) : null);
|
||||
const levels = $derived(version?.levels ?? view?.levels ?? []);
|
||||
const cast = $derived(levels[0]?.cast ?? 0);
|
||||
const current = $derived(version?.proposal.votedAtInertia ?? null);
|
||||
@@ -56,12 +58,12 @@
|
||||
<h4>{t('settings.usual')}</h4>
|
||||
<p>
|
||||
{#if p.source === 'median'}
|
||||
{i18n.plural('settings.usual.median', p.voters, { electorate: i18n.number(view.doc.electorate), pct: pct(p.ratio), sample: p.sample })}
|
||||
{i18n.plural('settings.usual.median', shown?.voters ?? p.voters, { electorate: i18n.number(view.doc.electorate), pct: pct(shown?.ratio ?? p.ratio), sample: p.sample })}
|
||||
{:else}
|
||||
{i18n.plural('settings.usual.reference', p.voters, { electorate: i18n.number(view.doc.electorate), pct: pct(p.ratio), min: p.minSample, sample: p.sample })}
|
||||
{i18n.plural('settings.usual.reference', shown?.voters ?? p.voters, { electorate: i18n.number(view.doc.electorate), pct: pct(shown?.ratio ?? p.ratio), min: p.minSample, sample: p.sample })}
|
||||
{/if}
|
||||
</p>
|
||||
{#if p.bounded}<p class="faint small">{t('settings.usual.bounded', { lo: pct(p.bounds[0]), hi: pct(p.bounds[1]) })}</p>{/if}
|
||||
{#if p.bounded}<p class="faint small">{i18n.plural('settings.usual.bounded', p.voters, { lo: pct(p.bounds[0]), hi: pct(p.bounds[1]), pct: pct(p.ratio) })}</p>{/if}
|
||||
<p class="faint small">{p.measuredAt ? t('settings.usual.when', { date: i18n.date(p.measuredAt) }) : t('settings.usual.never')}</p>
|
||||
</div>
|
||||
|
||||
|
||||
@@ -232,7 +232,8 @@ export const en: Messages = {
|
||||
'settings.usual.median.other': '{n} voters out of {electorate} ({pct}): the median of the {sample} proposals voted on over the past year.',
|
||||
'settings.usual.reference.one': '{n} voter out of {electorate} ({pct}), twice C: the reference turnout, until the group has voted on {min} proposals ({sample} so far).',
|
||||
'settings.usual.reference.other': '{n} voters out of {electorate} ({pct}), twice C: the reference turnout, until the group has voted on {min} proposals ({sample} so far).',
|
||||
'settings.usual.bounded': 'Kept between {lo} and {hi} of the electorate.',
|
||||
'settings.usual.bounded.one': 'Kept between {lo} and {hi} of the electorate: thresholds are worked out on {n} voter ({pct}).',
|
||||
'settings.usual.bounded.other': 'Kept between {lo} and {hi} of the electorate: thresholds are worked out on {n} voters ({pct}).',
|
||||
'settings.usual.when': 'Measured once a day, last on {date}.',
|
||||
'settings.usual.never': 'Measured once a day.',
|
||||
'settings.levels': 'The five levels',
|
||||
|
||||
@@ -232,7 +232,8 @@ export const es: Messages = {
|
||||
'settings.usual.median.other': '{n} votantes de {electorate} ({pct}): la mediana de las {sample} propuestas votadas en el último año.',
|
||||
'settings.usual.reference.one': '{n} votante de {electorate} ({pct}), dos veces C: la participación de referencia, hasta que el grupo haya votado {min} propuestas ({sample} por ahora).',
|
||||
'settings.usual.reference.other': '{n} votantes de {electorate} ({pct}), dos veces C: la participación de referencia, hasta que el grupo haya votado {min} propuestas ({sample} por ahora).',
|
||||
'settings.usual.bounded': 'Mantenida entre el {lo} y el {hi} del electorado.',
|
||||
'settings.usual.bounded.one': 'Mantenida entre el {lo} y el {hi} del electorado: los umbrales se calculan sobre {n} votante ({pct}).',
|
||||
'settings.usual.bounded.other': 'Mantenida entre el {lo} y el {hi} del electorado: los umbrales se calculan sobre {n} votantes ({pct}).',
|
||||
'settings.usual.when': 'Medida una vez al día, la última el {date}.',
|
||||
'settings.usual.never': 'Medida una vez al día.',
|
||||
'settings.levels': 'Los cinco niveles',
|
||||
|
||||
@@ -235,7 +235,8 @@ export const fr = {
|
||||
'settings.usual.median.other': '{n} votants sur {electorate} ({pct}) : la médiane des {sample} propositions votées depuis un an.',
|
||||
'settings.usual.reference.one': "{n} votant sur {electorate} ({pct}), deux fois C : la participation de référence, tant que le groupe n'a pas voté sur {min} propositions ({sample} pour l'instant).",
|
||||
'settings.usual.reference.other': "{n} votants sur {electorate} ({pct}), deux fois C : la participation de référence, tant que le groupe n'a pas voté sur {min} propositions ({sample} pour l'instant).",
|
||||
'settings.usual.bounded': "Ramenée entre {lo} et {hi} de l'électorat.",
|
||||
'settings.usual.bounded.one': "Ramenée entre {lo} et {hi} de l'électorat : les seuils se calculent sur {n} votant ({pct}).",
|
||||
'settings.usual.bounded.other': "Ramenée entre {lo} et {hi} de l'électorat : les seuils se calculent sur {n} votants ({pct}).",
|
||||
'settings.usual.when': 'Mesurée une fois par jour, la dernière fois le {date}.',
|
||||
'settings.usual.never': 'Mesurée une fois par jour.',
|
||||
'settings.levels': 'Les cinq crans',
|
||||
|
||||
@@ -0,0 +1,12 @@
|
||||
import type { ParticipationInfo } from './types';
|
||||
|
||||
/**
|
||||
* The usual participation as the settings tell it: the measured median, or the
|
||||
* reference (twice C). When the scale brings it back within its bounds, the
|
||||
* bounded value is what the formula uses, and is said apart.
|
||||
*/
|
||||
export function usualShown(p: ParticipationInfo, electorate: number, floor: number): { voters: number; ratio: number } {
|
||||
if (!p.bounded || electorate <= 0) return { voters: p.voters, ratio: p.ratio };
|
||||
const voters = p.source === 'median' && p.median !== null ? Math.round(p.median) : Math.round(2 * floor);
|
||||
return { voters, ratio: voters / electorate };
|
||||
}
|
||||
@@ -0,0 +1,37 @@
|
||||
// What the formula settings say about the usual participation (relecture of a576b68):
|
||||
// the measured median, or twice C, even when the scale brings it back within its bounds.
|
||||
import { describe, expect, it } from 'vitest';
|
||||
import { usualShown } from '../../src/lib/participation';
|
||||
import type { ParticipationInfo } from '../../src/lib/types';
|
||||
|
||||
const base: ParticipationInfo = {
|
||||
ratio: 0.3,
|
||||
source: 'median',
|
||||
sample: 5,
|
||||
median: 3,
|
||||
bounded: false,
|
||||
voters: 3,
|
||||
minSample: 5,
|
||||
windowDays: 365,
|
||||
everyHours: 24,
|
||||
bounds: [0.01, 0.5],
|
||||
measuredAt: null,
|
||||
};
|
||||
|
||||
describe('usual participation as shown', () => {
|
||||
it('is the scale itself when nothing was bounded', () => {
|
||||
expect(usualShown(base, 10, 1)).toEqual({ voters: 3, ratio: 0.3 });
|
||||
});
|
||||
it('is the real median when the scale raised it to its floor', () => {
|
||||
const p = { ...base, median: 1, ratio: 0.01, voters: 57, bounded: true };
|
||||
expect(usualShown(p, 5745, 50)).toEqual({ voters: 1, ratio: 1 / 5745 });
|
||||
});
|
||||
it('is twice C for the reference, even when the scale lowered it to its ceiling', () => {
|
||||
const p = { ...base, source: 'reference' as const, median: null, sample: 0, ratio: 0.5, voters: 1, bounded: true };
|
||||
expect(usualShown(p, 2, 1)).toEqual({ voters: 2, ratio: 1 });
|
||||
});
|
||||
it('rounds a median between two numbers of voters', () => {
|
||||
const p = { ...base, median: 2.5, ratio: 0.01, voters: 57, bounded: true };
|
||||
expect(usualShown(p, 5745, 50).voters).toBe(3);
|
||||
});
|
||||
});
|
||||
Reference in New Issue
Block a user