// Lot U3 — « Info ouverture doc de réf. » (Yvv, 2026-11-03: « un petit chapitre qui explicite les // réglages initiaux de l'auteur, notamment Quorum et Inertie »): what the chapter says is read in // the data of the document, never written in. The level a module opened at is the one before any // change voted (a change of the seed's settings, an amendment, is the author's); a Proposition // d'amorce stays one once it has entered into force (`seedFeatured`). import { describe, expect, it } from 'vitest'; import { isAmorce, openedAt, openingLevels, quorumsOf } from '../../src/lib/opening'; import type { DocView, Inertia, InertiaChange, Proposal, Unit } from '../../src/lib/types'; function version(over: Partial = {}): Proposal { return { id: 'p', unitId: 'u', kind: 'text', inertiaTarget: null, title: 'Un article', body: '', status: 'open', origin: 'seed', label: null, author: null, mine: false, revision: 1, createdAt: '2026-11-03T00:00:00Z', updatedAt: '2026-11-03T00:00:00Z', submittedAt: null, enteredAt: null, confirmedAt: null, seedMinimal: false, seedProposal: false, seedFeatured: false, tally: { for: 0, against: 0 }, tallyPending: { for: 0, against: 0 }, tallySimulated: { for: 0, against: 0 }, evaluation: null, votedAtInertia: 3, blocked: false, votable: true, objections: 0, myVote: null, myVoteState: null, myVoteStale: false, myVoteChain: false, myBallot: null, translations: {}, ...over, }; } let n = 0; function unit(inertia: Inertia, over: Partial = {}, versions: Partial[] = [{}]): Unit { n += 1; return { id: `u${n}`, code: `X${n}`, section: 'technique', position: n, inertia, inertiaChanges: [], inForce: null, proposals: versions.map((v) => version({ id: `p${n}`, ...v })), ...over, }; } const change = (from: Inertia, to: Inertia, cause: InertiaChange['cause']): InertiaChange => ({ from, to, cause, at: '2026-11-03T00:00:00Z' }); describe('the level a module opened at', () => { it('is its level when nothing changed it', () => { expect(openedAt(unit(3))).toBe(3); }); it('is the author’s: a change of the seed’s settings (an amendment) is part of the opening', () => { expect(openedAt(unit(2, { inertiaChanges: [change(3, 2, 'amendment')] }))).toBe(2); }); it('is the one before the first change voted, whatever came after', () => { expect(openedAt(unit(4, { inertiaChanges: [change(2, 4, 'vote')] }))).toBe(2); expect(openedAt(unit(5, { inertiaChanges: [change(3, 2, 'amendment'), change(2, 4, 'vote'), change(4, 5, 'vote')] }))).toBe(2); }); }); describe('a Proposition d’amorce', () => { it('is the article the seed put forward, open or in force since', () => { expect(isAmorce(unit(2, {}, [{ seedProposal: true, seedFeatured: true }]))).toBe(true); expect(isAmorce(unit(2, { inForce: version({ status: 'in_force', seedFeatured: true, enteredAt: '2026-11-03T00:00:00Z' }) }, []))).toBe(true); expect(isAmorce(unit(3))).toBe(false); }); it('a server that does not say it yet makes no article an amorce', () => { const old = version(); delete (old as Partial).seedFeatured; expect(isAmorce(unit(3, { proposals: [old] }))).toBe(false); }); }); describe('the levels at the opening, by kind of module', () => { function view(units: Unit[], title: Unit | null, orders: Unit[]): Pick { return { units, modules: { title, orders } }; } it('the amorces, the title, the order of each section, the other articles of the seed', () => { const v = view( [ unit(2, {}, [{ seedProposal: true, seedFeatured: true }]), unit(3, { inertiaChanges: [change(2, 3, 'vote')], inForce: version({ status: 'in_force', seedFeatured: true }) }, []), unit(3), unit(4, { inertiaChanges: [change(3, 4, 'vote')] }), // A member's article is not a setting of the author. unit(5, {}, [{ origin: 'member' }]), ], unit(4, { kind: 'title' }), [unit(2, { kind: 'order', section: 'introduction' }), unit(3, { kind: 'order', section: 'technique', inertiaChanges: [change(2, 3, 'vote')] })], ); expect(openingLevels(v)).toEqual({ amorce: [2], title: [4], orders: [2], others: [3] }); }); it('several levels in one kind are all said, lowest first; a kind that is absent says none', () => { const v = view([unit(4), unit(3), unit(4)], null, []); expect(openingLevels(v)).toEqual({ amorce: [], title: [], orders: [], others: [3, 4] }); }); }); describe('the quorum of each level', () => { it('said once when every level has the same', () => { expect(quorumsOf([1, 1, 1, 1, 1])).toEqual({ same: 1, list: [1, 1, 1, 1, 1] }); }); it('listed from level 1 to level 5 otherwise', () => { expect(quorumsOf([12, 12, 50, 50, 50])).toEqual({ same: null, list: [12, 12, 50, 50, 50] }); }); it('nothing when the server does not say them', () => { expect(quorumsOf(undefined)).toBeNull(); expect(quorumsOf([])).toBeNull(); }); });