forked from yvv/decision
Lot U3c : les tests d'abord, rouges sur le code de d66823b
- ld-engine inertia::when_everyone_votes_the_share_asked_is_m_on_every_electorate : pour tout W de 1 à 10 000 000, les cinq crans, G aux deux bornes de la participation habituelle, les quorums 1, 2 et W : quand les W votent, la part exigée des T′ = max(W, Q) votants est M, exactement ; la phrase d'avant (« la majorité M suffit », lue ⌈M·W⌉ « pour ») fausse sur 17 couples (W, cran), tous W ≤ 15, une voix de plus (B^W) ; vert sur le moteur inchangé, ses dents vues rouges par trois mutations (le plafond de la participation retiré, B^W mis dans la part, B^W retiré de R). - web/tests/unit/rules.test.ts : formula.reading épinglée en fr, en, es (« la part exigée est la majorité M ») ; aucune chaîne des catalogues ni du texte des composants ne dit que la majorité suffit ; la liste fermée de ce que l'écran dit de la pleine participation (formula.M, formula.reading, settings.reading) ; inertia.test.ts suit. 5 tests rouges sur 116. - tests/amorce.rs the_queue_names_the_starter_proposals_as_the_screen_does : les quatre raisons « Proposition d'amorce réécrite / ajoutée » (I1, E1, E2, E12), dans les constantes et dans les cinq lignes de file que T4 écrit sur une base comme la production après M8 ; celles de M6 inchangées. Rouge sur les constantes, et sur la file quand les constantes sont sautées. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
@@ -38,8 +38,9 @@ describe('five levels of inertia', () => {
|
||||
expect(fr['inertia.explain']).toBe(
|
||||
"Plus l'inertie est haute, plus il faut de voix pour changer ce texte. Sous le quorum de l'article, les votants qui manquent comptent comme « non » ; au-delà, la part exigée baisse quand la participation monte.",
|
||||
);
|
||||
// Lot U3c: « la part exigée est la majorité M », no longer « la majorité M suffit » (rules.test.ts).
|
||||
expect(fr['formula.reading']).toBe(
|
||||
"Sous le quorum Q de l'article, les votants qui manquent comptent comme « non » : il faut autant de « pour » que si Q personnes avaient voté. Au-delà, la part de « pour » demandée, la plus haute au quorum, baisse quand la participation monte ; quand tout le monde vote, la majorité M suffit.",
|
||||
"Sous le quorum Q de l'article, les votants qui manquent comptent comme « non » : il faut autant de « pour » que si Q personnes avaient voté. Au-delà, la part de « pour » demandée, la plus haute au quorum, baisse quand la participation monte ; quand tout le monde vote, la part exigée est la majorité M.",
|
||||
);
|
||||
expect(fr['quorum.error.voted']).toBe("Quelqu'un a déjà voté sur cet article : son quorum ne change pas.");
|
||||
});
|
||||
|
||||
@@ -4,6 +4,8 @@
|
||||
// (docs/chantiers/acte-certification/t3c-liste-fermee.md) on the texts of M8, kept in
|
||||
// crates/ld-server/tests/fixtures/seed-m8/. The inventory of where each lives:
|
||||
// docs/chantiers/acte-certification/U3-informations.md.
|
||||
import { readdirSync, readFileSync, statSync } from 'node:fs';
|
||||
import { join } from 'node:path';
|
||||
import { describe, expect, it } from 'vitest';
|
||||
import { en } from '../../src/lib/i18n/en';
|
||||
import { es } from '../../src/lib/i18n/es';
|
||||
@@ -65,11 +67,13 @@ describe('the rules the screen says, true for every W and every quorum (lots T3
|
||||
// Each phrase, and the test that proves it (crates/ld-server/tests/…).
|
||||
const PROVEN: [keyof typeof fr, string, string][] = [
|
||||
// seed_quorum_texts.rs under_the_quorum_it_takes_as_many_for_as_if_the_quorum_had_voted (N1.1 2, F1.2 12);
|
||||
// the_share_asked_falls_beyond_the_article_s_quorum_down_to_m (N1.1 3).
|
||||
// the_share_asked_falls_beyond_the_article_s_quorum_down_to_m (N1.1 3); ld-engine
|
||||
// inertia::when_everyone_votes_the_share_asked_is_m_on_every_electorate (« la part exigée est la
|
||||
// majorité M », W from 1 to 10 000 000, lot U3c).
|
||||
[
|
||||
'formula.reading',
|
||||
"Sous le quorum Q de l'article, les votants qui manquent comptent comme « non » : il faut autant de « pour » que si Q personnes avaient voté. Au-delà, la part de « pour » demandée, la plus haute au quorum, baisse quand la participation monte ; quand tout le monde vote, la majorité M suffit.",
|
||||
'under_the_quorum_… · the_share_asked_falls_…',
|
||||
"Sous le quorum Q de l'article, les votants qui manquent comptent comme « non » : il faut autant de « pour » que si Q personnes avaient voté. Au-delà, la part de « pour » demandée, la plus haute au quorum, baisse quand la participation monte ; quand tout le monde vote, la part exigée est la majorité M.",
|
||||
'under_the_quorum_… · the_share_asked_falls_… · ld-engine inertia::when_everyone_votes_…',
|
||||
],
|
||||
// the_formulas_of_the_texts_are_those_the_engine_computes (T' = max(T, Q), F1.1, N1.1 4).
|
||||
['formula.Tprime', "T′ — votants retenus : {n}, T ou Q s'il en manque", 'the_formulas_…'],
|
||||
@@ -139,3 +143,84 @@ describe('the rules the screen says, true for every W and every quorum (lots T3
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
// Lot U3c (review of d66823b): « quand tout le monde vote, la majorité M suffit » was false on a small
|
||||
// electorate. When the W vote, R = B^W + M·W; when M·W is a whole number, B^W adds one « pour » on
|
||||
// every W up to 15 (W 4, level 2: 3 « pour » of 4, not 2; W 5, level 4: 4 of 5, not 3). What holds for
|
||||
// every W and every quorum is the share asked: M at T′ = W — ld-engine
|
||||
// inertia::when_everyone_votes_the_share_asked_is_m_on_every_electorate, W from 1 to 10 000 000.
|
||||
// B^W is said apart, in the web of trust only (`formula.B.wot`).
|
||||
describe('when everyone votes, the share asked is M — never « M suffices » (lot U3c)', () => {
|
||||
it('the reading of the formula says it, in the three languages', () => {
|
||||
expect(fr['formula.reading']).toBe(
|
||||
"Sous le quorum Q de l'article, les votants qui manquent comptent comme « non » : il faut autant de « pour » que si Q personnes avaient voté. Au-delà, la part de « pour » demandée, la plus haute au quorum, baisse quand la participation monte ; quand tout le monde vote, la part exigée est la majorité M.",
|
||||
);
|
||||
expect(en['formula.reading']).toBe(
|
||||
"Below the article's quorum Q, the missing voters count as against: it takes as many votes in favour as if Q people had voted. Beyond it, the share of votes in favour asked for, highest at the quorum, falls as turnout rises; when everyone votes, the share asked is the majority M.",
|
||||
);
|
||||
expect(es['formula.reading']).toBe(
|
||||
'Por debajo del quórum Q del artículo, los votantes que faltan cuentan como «no»: hacen falta tantos votos a favor como si hubieran votado Q personas. Más allá, la proporción de votos a favor pedida, la más alta en el quórum, baja cuando sube la participación; cuando vota todo el mundo, la proporción exigida es la mayoría M.',
|
||||
);
|
||||
});
|
||||
|
||||
// « M suffit », « la majorité suffit », « majority M is enough », « basta la mayoría M »…: false for
|
||||
// W up to 15, so never said, in a catalogue or in the text of a component.
|
||||
const SUFFICES: Record<keyof typeof CATALOGS, RegExp> = {
|
||||
fr: /\bM suffi|majorit[ée][^.;:]*suffi|suffi[^.;:]*majorit[ée]/i,
|
||||
en: /majority[^.;:]*(enough|suffice|sufficient)|(enough|suffice|sufficient)[^.;:]*majority/i,
|
||||
es: /mayor[íi]a[^.;:]*(basta|suficiente|alcanza)|(basta|suficiente|alcanza con)[^.;:]*mayor[íi]a/i,
|
||||
};
|
||||
it('no string of the interface says the majority suffices', () => {
|
||||
for (const [lang, cat] of Object.entries(CATALOGS)) {
|
||||
for (const [k, v] of Object.entries(cat)) expect(v, `${lang} ${k}`).not.toMatch(SUFFICES[lang as keyof typeof CATALOGS]);
|
||||
}
|
||||
const svelte = (dir: string): string[] =>
|
||||
readdirSync(dir).flatMap((name) => {
|
||||
const p = join(dir, name);
|
||||
return statSync(p).isDirectory() ? svelte(p) : p.endsWith('.svelte') ? [p] : [];
|
||||
});
|
||||
for (const file of svelte(join(__dirname, '../../src'))) {
|
||||
const shown = readFileSync(file, 'utf8')
|
||||
.replace(/<script[\s\S]*?<\/script>/g, '')
|
||||
.replace(/<style[\s\S]*?<\/style>/g, '')
|
||||
.replace(/<!--[\s\S]*?-->/g, '')
|
||||
.replace(/<[^>]+>/g, ' ');
|
||||
for (const re of Object.values(SUFFICES)) expect(shown, file).not.toMatch(re);
|
||||
}
|
||||
});
|
||||
|
||||
// The closed list of what the screen says of full turnout, each judged against the engine: the
|
||||
// share asked, M — true for every W (the grid above). A new one fails here until it is judged.
|
||||
it('what the screen says of full turnout is the share asked, M', () => {
|
||||
const FULL: Record<keyof typeof CATALOGS, RegExp> = {
|
||||
fr: /tout le monde vote|pleine participation/,
|
||||
en: /everyone votes|full turnout/,
|
||||
es: /vota todo el mundo|participación plena/,
|
||||
};
|
||||
for (const [lang, cat] of Object.entries(CATALOGS)) {
|
||||
const told = Object.entries(cat)
|
||||
.filter(([, v]) => FULL[lang as keyof typeof CATALOGS].test(v))
|
||||
.map(([k]) => k);
|
||||
// formula.M names the letter, « M — majorité à pleine participation » (the share asked when the W
|
||||
// vote); formula.reading and settings.reading: « la part exigée … la majorité M ».
|
||||
expect(told, lang).toEqual(['formula.M', 'formula.reading', 'settings.reading']);
|
||||
}
|
||||
const SHARE = [
|
||||
[
|
||||
'formula.reading',
|
||||
{ fr: 'la part exigée est la majorité M', en: 'the share asked is the majority M', es: 'la proporción exigida es la mayoría M' },
|
||||
],
|
||||
[
|
||||
'settings.reading',
|
||||
{
|
||||
fr: "plus la part exigée baisse, jusqu'à la majorité M quand tout le monde vote",
|
||||
en: 'the lower the share asked gets, down to the majority M when everyone votes',
|
||||
es: 'más baja la proporción exigida, hasta la mayoría M cuando vota todo el mundo',
|
||||
},
|
||||
],
|
||||
] as const;
|
||||
for (const [k, share] of SHARE) {
|
||||
for (const [lang, cat] of Object.entries(CATALOGS)) expect(cat[k], `${lang} ${k}`).toContain(share[lang as keyof typeof CATALOGS]);
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
Reference in New Issue
Block a user