# libreDecision v2 — Blueprint définitif _Généré par la ronde de conception ultracode du 2026-08-11 : panel de 4 visions + 3 juges, corpus doctrinal (« Mon nom est personne », « Une économie du don », SejeteralO), 4 critiques d'intégration, architecte final, 3 vérificateurs adversariaux, réparations intégrées._ ## Manifeste Personne n'a jamais vécu en démocratie — alors nous la rêvons de jour, et nous la commençons à notre échelle. libreDecision attrape chaque décision en une phrase et propose le chemin le plus court : décide seul et trace-le, décide sous mandat, écoute puis décide, ou décidez ensemble — jamais plus lourd que l'enjeu. Ici on ne délègue pas, on mandate, et on reprend ; on n'est pas consulté, on s'instruit, puis on se prononce ; on ne s'affronte pas en deux camps, on règle des curseurs — et la position de chacun reste visible dans le faisceau, la médiane n'écrase personne, la dernière main est toujours humaine. Les concernés en premier lieu ont voix par construction, chacun voit pourquoi ; lever la main « ça me concerne » est un droit, pas une demande. Chaque décision dit ce qu'elle engage, ce qu'elle cherche à changer, et repasse l'épreuve du réel : rien n'est définitif, toute décision en vigueur garde sa poignée, se tromper est une donnée qu'on consigne. Les règles du jeu elles-mêmes — le Pacte — s'écrivent au fil de l'eau, par ceux qu'elles gouvernent, sous les boussoles Autonomie, Équilibre, Liaison. Du trio d'amis à la toile Ğ1 : le même geste, dix secondes, et l'observatoire qui apprend de nous. La ville change, le puits demeure. ## Delta vs blueprint v1 (chaque changement justifié par la doctrine) ### Δ1 **Changement.** CollectiveSettings.protocolByRange.inertialBinary renommé 'large' (Id résolu par le Pacte, le nom ne présume plus la méthode). Gabarits blank/informal/association/cooperative/commune/symmetric : 'large' pointe le protocole nuancé 6 niveaux (nuancedMinParticipants/nuancedThresholdPct existants). SEULS free-currency et les seeds Ğ1 pointent le binaire inertiel. R5 >50 hors clause : défaut nuancé ; R3 (clause visée) garde clauseByInertia — héritage Ğ1 (33+59 clauses, D30M50B.1G.2) intact, à sa place. **Raison doctrinale.** « Le clivage binaire est un fléau contre la réflexion, un ennemi fatal : il la tue » ; « proscrire le binaire oui/non comme format par défaut » ; le binaire n'est légitime que « remis à sa place dans la boîte à outils » — jamais destination naturelle des grands corpus (le RIC disqualifié : « tir à la corde »). ### Δ2 **Changement.** VoteMethod += 'parametric' (UI « Réglage collectif / décider au curseur »). Decision.paramSpec { params ≤7, constraint 'none'|'sum100', impactAttrKey? } ; ParamDef { key, label métier obligatoire, kind 'slider'|'share', min/max/step, unit?, baseline?, derived? } ; Vote.values?: number[] ; engine/parametric.ts (validateVote, resolveDerived, medianByElement, computeMyImpact, detectBimodality, crystallize). SPECS VERROUILLÉES (réparations) : médiane BASSE par élément (nombre pair ⇒ élément central inférieur — chaque valeur médiane est une valeur effectivement votée, donc conforme au step par construction, testée vitest) ; sum100 ⇒ EXACTEMENT une part 'derived' exigée à la création du paramSpec ; au vote, la géométrie clampe dynamiquement les parts votées pour que le derived reste dans ses bornes ET validateVote rejette sinon ; à la cristallisation, le derived n'est jamais agrégé : il est résolu depuis la médiane des parts votées, et s'il sort de ses bornes ⇒ clamp à la borne + renormalisation proportionnelle des parts non-derived (somme 100 restaurée, spec testée). Dégénérescences : 0 vote ⇒ baseline, jamais d'écran vide. Jamais dans le chemin 10 s : alternative « C'est un réglage » + suggérée quand la phrase contient nombre/%/montant. **Raison doctrinale.** « Raisonner curseur / table de mixage » est LE geste central des deux livres ; leçons SejeteralO « voter = régler une forme, pas choisir un camp », « médiane élément par élément » avec l'invariant « le résultat est lui-même une position que chacun aurait pu proposer » — invariant qui EXIGE la médiane basse et la résolution sous contrainte ; « robustesse numérique de série : dégénérescences spécifiées ». ### Δ3 **Changement.** RÉPARATION — Cristallisation = geste humain daté : la clôture paramétrique passe par VoteSession.status 'frozen' à closesAt (votes figés, médiane figée affichée) puis le GARANT (stewardIds, à défaut l'auteur) fait le geste « Cristalliser » → 'closed' + crystallizedById/crystallizedAt, la médiane devient position adoptée (ou rejected si quorum parametricMinParticipants non atteint — constaté au même geste). Relance au Fil du garant s'il tarde. Si detectBimodality positif, le geste affiche en évidence « Deux positions distinctes — cristalliser quand même / scinder / reformuler » : jamais de cristallisation automatique. Consent/nuancé/binaire gardent la clôture automatique (le moteur ne fait qu'y constater un seuil sur un contenu formulé par des humains) ; l'élection clôt automatiquement SAUF égalité (geste requis, cf. delta élection). **Raison doctrinale.** Tension du corpus explicitement tranchée : « l'agrégat éclaire une délibération, la cristallisation reste un geste humain distinct et daté » ; chez SejeteralO la publication est distincte de l'agrégation vivante ; un calcul qui produit un contenu adopté sans geste humain = « décision algorithmique », repoussoir absolu. ### Δ4 **Changement.** Matière : Decision.brief { context?, sources?, symptomsVsCauses?, effects: Effect[] } avec Effect { label, target?, measured? }. RÉPARATION — garde restreinte : ≥1 effet recherché exigé (state.ts, framing→voting / draft→voting) UNIQUEMENT pour les sessions collectives de poids binding/structural, gouverné par la clause de Pacte 'triage.requireEffects' ∈ 'none'|'structural'|'binding' (défaut 'binding' ; 'none' seedé dans blank ET informal) ; quand elle s'applique au structural, ≥1 effet doit porter une cible mesurable (target). Le consentement léger (weight light) et le trio n'y sont JAMAIS soumis ; le tunnel ne l'affiche jamais — la matière s'écrit en framing. L'épreuve du réel réutilise effects : tableau « recherché / cible / constaté » au-dessus des 3 boutons, mesures saisies par les measurerIds. **Raison doctrinale.** « Il n'est pas consulté, il est instruit » ; « aucun vote sans matière » — mais « jamais plus lourd que l'enjeu » (manifeste) : le collectif règle sa propre exigence (couche méta), et la boucle « acquisition collective des expériences » est fermée par le même champ. ### Δ5 **Changement.** RÉPARATION — Bloc « S'instruire » condensé : en salle de vote et fiche (framing/voting), un RÉSUMÉ COMPACT toujours visible avant les boutons (titre, effets recherchés, « Ce que ça engage ») avec versions+diff, avis/objections et provenance en DÉPLIABLES internes ; le bloc entier se replie automatiquement aux visites suivantes de la même personne (préférence locale par décision) — voter sur un titre nu reste impossible, re-voter reste léger. **Raison doctrinale.** « Aucun vote sans matière » concilié avec la leçon SejeteralO « agir d'abord, comprendre ensuite » : pas de mur de scroll mobile à chaque re-vote d'un vote révisable. ### Δ6 **Changement.** Ressources : Decision.resources { note, amount?, unit 'heures'|'€'|'DU'|string } + Decision.measurerIds à côté de stewardIds. Huile/eau : DU et € JAMAIS convertis ni additionnés (Observatoire : lignes par unité). RÉPARATION — localisation de la garde : la ligne « Ce que ça engage » est SUGGÉRÉE-dépliée dans le tunnel (toujours facultative, ne bloque jamais) ; l'exigence (weight != 'light' hors solo) vit UNIQUEMENT dans la garde d'ouverture de fenêtre/session de state.ts, même mécanique que brief.effects — le tunnel n'affiche jamais un champ obligatoire qui ne change pas le chemin. **Raison doctrinale.** « Chaque décision implique une allocation de ressources, donc une décision connexe incontournable » (MNP p.89) ; « des équipes pour réaliser et des équipes pour mesurer » ; l'huile et l'eau ne se mélangent jamais ; et la métrique produit « 2 gestes / 10 s » reste intacte pour le cas nominal. ### Δ7 **Changement.** Suppression de toute jauge de confiance sur les mandats. Bloc « Exercice du mandat » : faits comptés jamais synthétisés (« 12 décisions tracées · 1 objection · 2/2 rapports », listes cliquables). Le flux public devient « Feux de la rampe » (« toutes les décisions prises sous ce mandat — contestables »). Rendu seulement, zéro champ. **Raison doctrinale.** « On peut évaluer des choses ; mais les personnes ? Alerte rouge » ; « la confiance exclut le contrôle » — une jauge de CONFIANCE sur un pouvoir contrôlé est un oxymore ; « Feux de la rampe » est le mot doctrinal exact. ### Δ8 **Changement.** Protocol.ballot: 'open' | 'secret' (défaut 'open'), gouverné par le Pacte. Mode secret v2 : décomptes agrégés et commentaires anonymisés seuls, étiquette « secret d'affichage — démo » ; crypto réelle avec la synchro (v3, noté au contrat des stores). **Raison doctrinale.** « Modalité de vote secret vs ouvert comme paramètre de chaque décision » (leçon fouloscopie) — « l'outil doit savoir faire les deux, et le périmètre en décide » ; même honnêteté d'étiquetage que la gravure. ### Δ9 **Changement.** RÉPARATION — Historique des re-votes jamais opposable : la chaîne supersedesVoteId n'est JAMAIS affichée publiquement sous le nom d'un votant — visible du seul auteur du vote ; même en ballot 'open', seul le DERNIER vote actif d'une personne apparaît sous son nom, et le décompte agrégé est recalculé. Libellé : « Ton vote est remplaçable — ton historique n'est visible que de toi. » Invariant écrit au modèle + test. **Raison doctrinale.** Tension « Mémoire vive vs droit à l'erreur » tranchée par le corpus : « archiver les mandats, pardonner les positions ; l'historique des votes révisés n'est jamais opposable à une personne » — sinon contrôle des personnes entre elles, le glas doctrinal. ### Δ10 **Changement.** Gabarit 'blank' « Page blanche — observatoire d'abord » en tête de /creer : Pacte d'une seule clause (« nous consignons nos décisions ; le reste s'écrira au fil de l'eau ») + clause A1 finalité. RÉPARATION — cohérence settings : blank seede AU MINIMUM le protocole « Consentement » ; protocolByRange.consent est OBLIGATOIRE (invariant : tout collectif a un protocole de consentement, validé à l'import), les autres clés optionnelles ; resolveSettings spécifie le REPLI : toute clé non résolue retombe sur consent ; si consent introuvable (bundle corrompu), le triage route 'advice' avec bannière « Aucun protocole — crée-le ou décide sur avis » — jamais un crash. Les 5 gabarits existants réétiquetés « point de départ — tout est amendable par décision ». **Raison doctrinale.** « L'observatoire des décisions AVANT de protocoliser » ; contrat social « écrit au fil de l'eau, sans préfigurer » ; « une chorégraphie du don ne se télécharge pas en .ods » — et la robustesse spécifiée (« jamais d'écran vide ») fait partie de la leçon SejeteralO. ### Δ11 **Changement.** Gabarit 'symmetric' « Institution symétrique » : Pacte en transparence totale, TextDoc reference « Déclaration de symétrie », première décision « Déclarer notre symétrie », 2 mandats suggérés Ambassadeur et Négociateur. Données pures templates.ts. **Raison doctrinale.** « Tu ne veux pas — Ô Institution — tant pis, je crée une symétrie » (chapitre entier de MNP) ; le poids = le volume des personnes qui l'habitent ; représentants « ambassadeurs et négociateurs, jamais décideurs ». ### Δ12 **Changement.** DecisionRoute += 'record' + Decision.decidedHow. Alternative permanente « Déjà tranché — je le consigne » → adopted immédiat, zéro fenêtre (2 gestes). /decisions/memoire → /decisions/observatoire « L'Observatoire » ; ratio consigné/outillé = maturité ; maturation (famille R6, jamais bloquante) : ≥3 consignations partageant ≥2 tags ⇒ « Cette pratique est mûre — protocolise-la en quelques phrases » pré-remplissant une clause de Pacte. **Raison doctrinale.** « Consigner comment elles se prennent dans les faits, avant de protocoliser » puis « traduire en protocoles de quelques phrases quand c'est mûr » — le flux consigner→observer→protocoliser devient le chemin ordinaire ; l'inversion des noms (Mémoire/Observatoire) est corrigée. ### Δ13 **Changement.** chainKind += 'element' + Concern.priority?: 0|1|2|3. « Découper en micro-décisions » sur toute décision structural en framing ; onglet « Éléments » + « Cartographie de clôture » auto-générée. RÉPARATION — clôture du dossier : nouvelle transition framing→closed du parent, gardée par « tous les éléments dans un état terminal » ; jamais automatique : quand la garde est vraie, carte au Fil du garant « Le dossier est complet — clore et publier la cartographie de clôture » ; le geste clôt, la cartographie devient le PV du dossier. Libellé UI : « décision incrémentielle » réservé à CE mode. **Raison doctrinale.** La « décision incrémentielle » est le nom PROPOSÉ PAR L'AUTEUR (modèle Taïwan) : « chacun navigue dans les points qui le concernent, pondère ses préférences » ; « cartographie de clôture visible de tous » — et la clôture est un geste humain, cohérent avec la cristallisation. ### Δ14 **Changement.** Decision.baselineNote?: string (« Aujourd'hui : … ») suggéré routes advice/collective (jamais solo). Fiche : « Aujourd'hui → Proposé » ; ParamDef.baseline = marqueur « actuel » ; l'épreuve du réel relit l'écart. Les clauses gardent leur diff (qui EST leur baseline). **Raison doctrinale.** Leçon SejeteralO : « la baseline : toujours afficher l'existant — une décision se lit comme un écart au statu quo, mesurable ». ### Δ15 **Changement.** Person.attributes?: Record (déclarés, édités dans /donnees, jamais affichés à autrui ni agrégés) + ParamSpec.impactAttrKey. RÉPARATION — computeMyImpact 'linear-share' SPÉCIFIÉ : ne s'applique QUE si constraint='sum100' ET resources.amount présent ET impactAttrKey présent ; pour chaque part p (derived inclus) : montant(p) = resources.amount × p/100 ; ma quote-part(p) = montant(p) × attr(moi) / Σ attr(déclarants du corpus) ; résultat par curseur + total, calculé aux trois positions (la mienne / médiane / baseline). attr(moi) absent ou Σ=0 ⇒ null (jamais un chiffre inventé — la carte montre alors seulement l'écart collectif en valeurs de curseurs). L'exemple seedé « budget d'ateliers 1 200 € × 'heures/mois' » devient calculable. Étiquette « estimation sur données déclarées ». **Raison doctrinale.** Principe produit n°5 « qu'est-ce que ça change pour moi » ; SejeteralO « Mon prix au m³ » et son triptyque ma-position/médiane/référence — version local-first honnête, bornée, et désormais calculable ; le moteur sur données réelles importées reste v3. ### Δ16 **Changement.** Composant Faisceau : nuancé → histogramme des 6 niveaux sous la jauge + commentaires en liste — jamais un simple adopté/rejeté ; paramétrique → strip-plot par curseur (points translucides anonymes, médiane trait épais, baseline marqueur creux). detectBimodality ⇒ bannière non bloquante « Deux positions distinctes se dessinent sur X — scinder la question ou changer de référentiel ? » ouvrant le découpage ou une reformulation. **Raison doctrinale.** « La diversité reste visible : le faisceau » ; « la médiane peut masquer une distribution bimodale » ; le « changement de référentiel » doctrinal devient un geste produit. ### Δ17 **Changement.** Garde d'affluence dans state.ts : concernEscalateRatio atteint ⇒ la fenêtre/session NE PEUT PAS se clore sans traitement — élargir d'un cran (1 tap, re-triage journalisé) ou maintenir avec Decision.scopeKeptNote motivée publique, affichée en évidence. **Raison doctrinale.** La montée d'échelle est DÉCIDÉE (« on en change quand le peuple le décide ») — l'asymétrie de dérogation appliquée au périmètre, LE lieu doctrinal de la subsidiarité. ### Δ18 **Changement.** Circle.kind?: 'place'|'theme'|'team' — iconographie, groupement, ordre des suggestions seulement, jamais un droit. Hint non bloquant si 'team' > 12. Gabarits typent leurs cercles. **Raison doctrinale.** Les 3 vecteurs du périmètre : le topologique gagne une existence déclarative sans machinerie géo ; « au-delà de douze, les complications commencent ». ### Δ19 **Changement.** Collective.lineage?: { sourceSlug, exportedAt, sha256 } posé à l'import d'un bundle étranger (« essaimé de … »). PAS de parentCollectiveId ; pattern v3 documenté : une grappe = un collectif ordinaire dont les membres sont des mandataires d'autres collectifs. **Raison doctrinale.** La « scission féconde » exige la mémoire d'origine ; le corpus proscrit la fédération dans le modèle (« représentation, voix unique ») — composition pure. ### Δ20 **Changement.** Clause « A1 — Notre finalité » seedée dans chaque gabarit (texte sous vote permanent, défaut portant les boussoles), affichée sous le nom du collectif ; préambule de Pacte proposé et modifiable portant Autonomie–Équilibre–Liaison. **Raison doctrinale.** « Chaque groupe doit se donner une finalité » ; « boussoles proposées, jamais imposées » ; coexistence « sans être concurrents ». ### Δ21 **Changement.** Passerelles hors-écran : (1) CSS print A4 + « Imprimer » sur fiche (PV) et salle (affiche de session) ; (2) « agir en tant que » requalifié « mode atelier » via recordedById?: Id sur Vote/Advice/Objection/Assent (« saisi par X pour Y — atelier du ») ; (3) micro-copy « à trancher en présence ? » sur structural. **Raison doctrinale.** « Toute décision numérique doit être praticable sans écran » ; « intermédiation humaine pour les démunis du numérique » ; « plus le numérique prend de place, plus il faut en donner à la relation humaine ». ### Δ22 **Changement.** frontend/app/lexicon.ts : source UNIQUE des libellés français + test vitest anti-lexique (déléguer/délégation, dette, retard, en souffrance, corpus, snapshot, CONTRE, verdict, triage, oligarchie, peuple adulte…). Trois règles de ton : (1) tutoyer la personne dans ses gestes ; (2) actes collectifs à l'infinitif (« Adopter notre Pacte ») ; (3) sujet grammatical des phrases générées = le collectif ou la légitimité, jamais la formule/le système. **Raison doctrinale.** « L'auteur voudra retrouver ses mots exacts » ; « politiquement explicable » : c'est la légitimité qui exige, pas les maths — l'algorithme au service, jamais souverain. ### Δ23 **Changement.** Renommages UI (types inchangés) : carte /decider « Le chemin » (explanation seule, code R* au dépliable/PV/journal) ; « Concerné·e en premier lieu / en second lieu » (pastille pleine / main levée) ; chip « Concernés » ; panneau « Périmètre » ; « Mandats — les pouvoirs confiés » ; Fil « À toi de décider » compteur nu ; « Qui vote : 11 personnes — liste arrêtée le 12/08 » (W/T/M/B/G/C à l'Atelier seulement) ; échelle nuancée « Pas du tout · Plutôt non · Réservé · Plutôt oui · Oui · Tout à fait » ; revoyure « L'épreuve du réel » / « Le réel a-t-il suivi ? » / « Ça tient / À revoir / À révoquer » ; « C'est urgent » + badge « Décidé en urgence — le collectif ratifie » ; « Révoquées — ce qu'on en a appris » ; routes à la première personne ; sous-titre du Pacte « Notre contrat social — sacralisé, jamais immuable » ; fenêtre framing « N jours pour s'instruire et formuler des contre-propositions ». **Raison doctrinale.** « On ne délègue pas, on abandonne » ; « périmètre » est LE concept pivot ; le registre dette/peur est le couple de l'asservissement ; « le verdict n'est jamais un juge » ; « toute étiquette évacue la moitié de la population ». ### Δ24 **Changement.** Bouton « Explorer » en salle paramétrique : sandbox de la médiane, curseurs libres, dérivés + « Pour moi » recalculés en live, « Partir de la médiane / du statu quo / de ma position », « En faire ma position », étiquette « exploration — ne compte pas ». Rétro-manipulation résultat→contrainte : v3. **Raison doctrinale.** Leçon SejeteralO « manipulation de l'agrégat pour explorer » ; « déplacer, évaluer, ajuster, recommencer » ; abaisse le coût psychologique du premier vote. ### Δ25 **Changement.** Dépersonnalisation d'affichage : contenu et diff d'abord, auteur replié (visible au tap) dans le bloc formulation et la salle. Pas de mode anonyme réel en v2 mono-poste. **Raison doctrinale.** « On débat du contenu, pas de l'auteur » (@personne) — anti ad-hominem, anti-sauveur. ### Δ26 **Changement.** Désirabilité : tampon 井 incliné -10° « Décidé » (translateY 0.12s) + « C'est décidé — et révisable, comme tout ici » ; /creer se signe « Osons, nous verrons » ; manifeste public sans vocabulaire de livraison, clos sur « La ville change, le puits demeure » ; termes-diagnostics réservés à la page-manifeste. **Raison doctrinale.** « Rendre désirable plutôt que convaincre » exige que décider soit beau ; le couple plaisir+rêve. ### Δ27 **Changement.** RÉPARATION — Silence-vaut-accord résolu par l'entité Assent : « Ça me va » est stocké (Assent { decisionId, personId, recordedById? }, append-only, dans le Bundle). Règle unique des fenêtres d'objection : à échéance sans objection ouverte — reversibility 'easy' ⇒ adopted (silence vaut accord) ; costly/irreversible ⇒ adopted SEULEMENT si ≥1 Assent d'un concerné autre que l'auteur, sinon la fenêtre se PROLONGE d'un cran (windowEndsAt + objectionWindowHours, relance au Fil des concernés) — jamais d'adoption par pur silence hors easy. La contradiction v1 est levée, le comportement à échéance est défini. **Raison doctrinale.** « Il ne cède pas un consentement, il négocie — chaque virage » : hors du réversible, l'accord est un geste, pas une absence ; et le silence-vaut-accord réservé au réversible était déjà l'engagement du blueprint — désormais tenu mécaniquement. ### Δ28 **Changement.** RÉPARATION — Élection codable : Vote.choicePersonId?: Id (invariant : EXACTEMENT un de value / values / choicePersonId selon la méthode, validé par le store). Vote déposé sans choicePersonId = blanc (compte pour la participation, pas pour la désignation). engine/threshold.ts += electionResult(votes, corpus) : quorum optionnel electionMinParticipants (FormulaParams) sinon rejected ; désignation à la PLURALITÉ simple des derniers votes actifs ; ÉGALITÉ ⇒ résultat 'tie' avec exAequoIds — l'outil ne départage JAMAIS : la clôture propose une session de départage chaînée restreinte aux ex æquo (pré-remplie), ou le tirage au sort entre ex æquo si le protocole du Pacte l'a prévu d'avance. Salle élection : désignation par avatar, bouton « Vote blanc », règle affichée en une phrase. **Raison doctrinale.** L'élection « remise à sa place dans la boîte à outils » doit être réellement outillée pour les mandats ; « l'outil représente, agrège et éclaire — il ne décide jamais » : une égalité n'est pas tranchée par un algorithme, et le tirage au sort n'est légitime que décidé d'avance par le Pacte. ### Δ29 **Changement.** RÉPARATION — canTransition étendu : engine/state.ts expose canTransition(decision, to, ctx: { concerns: Concern[], settings: CollectiveSettings, session?: VoteSession, children?: Decision[], assents?: Assent[], objections?: Objection[] }) — les gardes d'affluence (|déclarés| vs |calculés|), de matière (requireEffects), de ressources, de frontière (windowSuspendedAt), d'Assent et de clôture de dossier (children terminaux) ont leurs entrées dans la signature ; le contexte est assemblé par le store, la fonction reste pure et testable. **Raison doctrinale.** Machine à états UNIQUE réellement implémentable : toute mutation passe par canTransition, et les gardes doctrinales (subsidiarité, instruction, consentement) sont du code testé, pas des intentions. ### Δ30 **Changement.** Verdict enrichi : parametricHint (nombre/%/montant détecté), alternatives permanentes « C'est un réglage — décidez au curseur », « Déjà tranché — je le consigne », binaire avec son coût (« deux camps, un perdant ») ; TriageContext.similarRecordedCount ; suggestion.kind += 'protocolize'. **Raison doctrinale.** « L'outil représente, agrège et éclaire — il ne décide jamais » : les modalités doctrinales sont proposées, jamais imposées. ## Modèle de domaine ```ts // ───────────────────────────────────────────────────────────── // libreDecision v2 — noyau de domaine DÉFINITIF (frontend/app/types/domain.ts) // Local-first, prêt-synchro. Identifiants anglais, UI française via app/lexicon.ts. // INVARIANT 1 : LA DÉCISION EST L'OBJET PIVOT — mandats, clauses, révocations, // ratifications, éléments de dossier en sont des spécialisations chaînées. // INVARIANT 2 : l'unification est un fait d'architecture, JAMAIS un vocabulaire d'UI. // INVARIANT 3 : aucun agrégat/score sur une personne, nulle part — on évalue des choses. // INVARIANT 4 : aucun calcul ne produit un contenu adopté sans geste humain daté // (cristallisation paramétrique, départage d'élection, clôture de dossier). // ───────────────────────────────────────────────────────────── type Id = string // UUIDv7 — triable par temps, prêt pour la synchro type ISODate = string // ISO 8601 UTC type Json = string | number | boolean | null | Json[] | { [k: string]: Json } // Toute entité : scoping collectif + horloge de synchro + soft-delete. // Prêt-synchro : jamais de suppression physique (archivedAt) ; // Vote/Advice/Objection/Assent append-only (merge trivial) ; le reste LWW par updatedAt. interface Entity { id: Id collectiveId: Id createdAt: ISODate updatedAt: ISODate archivedAt?: ISODate } // ── Le tenant ──────────────────────────────────────────────── type CollectiveTemplate = | 'blank' // « Page blanche — observatoire d'abord » : Pacte 1 clause + A1, protocole Consentement SEUL | 'informal' | 'association' | 'cooperative' | 'commune' | 'free-currency' // héritage Ğ1 — SEUL gabarit où protocolByRange.large = binaire inertiel | 'symmetric' // « Institution symétrique » — le geste fondateur militant (MNP) interface Collective { id: Id slug: string name: string color: string // hex accent icon: string // i-lucide-* template: CollectiveTemplate isTransparent: boolean pactDocId: Id // TextDoc role='pact' — les réglages EN document voté rootCircleId: Id lineage?: { // essaimage : posé auto à l'import d'un bundle d'un autre collectif sourceSlug: string; exportedAt: ISODate; sha256: string } // PAS de parentCollectiveId — la fédération n'est jamais une table createdAt: ISODate updatedAt: ISODate } // ── Les gens ───────────────────────────────────────────────── interface Person extends Entity { displayName: string isMe: boolean // profil local (v2 mono-poste ; « mode atelier » pour la saisie en présence) attributes?: Record // attributs DÉCLARÉS par la personne (clés libres : 'heures/mois'…), // édités dans /donnees — servent UNIQUEMENT la carte « Pour moi » ; // jamais affichés à autrui, jamais agrégés (invariant 3) duniterAddress?: string // SS58 — réservé auth Duniter (hors scope v2) wotStatus?: 'member' | 'smith' } interface Circle extends Entity { name: string purpose: string kind?: 'place' | 'theme' | 'team' // lieu / thème / équipe — iconographie, groupement des sélecteurs, // ordre des suggestions SEULEMENT, jamais un droit ; // hint non bloquant si 'team' > 12 (« au-delà de douze… ») memberIds: Id[] // v2 : liste nominative = SEULE règle d'appartenance (auditable) parentCircleId?: Id // emboîtement (couches d'oignon) — racine = rootCircle domains: string[] // tags — SUGGESTION/découverte uniquement, jamais un droit de vote } // Corpus d'une décision = union CALCULABLE : membres des cercles du scope // ∪ personnes nommées ∪ titulaires des mandats dont le domaine intersecte. // Chaque inclusion garde sa raison (Concern.reason) — auditable en un tap. // ── LA DÉCISION (pivot) ────────────────────────────────────── type Reversibility = 'easy' | 'costly' | 'irreversible' type Weight = 'light' | 'binding' | 'structural' type DecisionRoute = | 'solo' // « Je décide » (trace facultative hors mandat) | 'mandate' // « Je décide, sous mandat » (trace obligatoire + fenêtre d'objection) | 'transmit' // « Je transmets » — le mandat d'un autre couvre | 'advice' // « J'écoute, puis je décide » | 'collective' // « Nous décidons » (modalité du protocole) | 'record' // « Déjà tranché — je le consigne » : l'observatoire en un geste, adopted immédiat type DecisionStatus = | 'draft' | 'advice' | 'objection' | 'framing' | 'voting' | 'adopted' | 'rejected' | 'revoked' | 'transmitted' | 'closed' type TriageRule = 'R-U' | 'R0a' | 'R0b' | 'R0c' | 'R2' | 'R3' | 'R4' | 'R5' | 'R6' // La matière à réflexion — « il n'est pas consulté, il est instruit » interface Effect { label: string // effet recherché, une ligne target?: string // cible mesurable optionnelle (« ≤ 400 € », « +5 membres ») measured?: { note: string; at: ISODate; byId: Id } // constaté — saisi par les measurerIds à la revoyure } interface Brief { context?: string sources?: { label: string; url: string }[] symptomsVsCauses?: string // qualification doctrinale du sujet effects: Effect[] // GARDE (state.ts, ouverture de session collective UNIQUEMENT) : // exigé si weight ∈ requireEffects du Pacte ('binding' couvre binding+structural) ; // structural sous garde ⇒ ≥1 effet avec target. JAMAIS pour weight 'light', // JAMAIS dans le tunnel, JAMAIS en solo/record. } // La décision connexe de ressources — « chaque décision implique une allocation » interface Resources { note: string // « Ce que ça engage » en une phrase amount?: number unit?: 'heures' | '€' | 'DU' | string // huile/eau : unités JAMAIS converties ni additionnées entre elles } // Le réglage collectif — « raisonner curseur / table de mixage » type ParamKind = 'slider' | 'share' // 'curve' réservé v3 (SejeteralO complet) interface ParamDef { key: string label: string // libellé métier OBLIGATOIRE — jamais de a, b, c bruts kind: ParamKind min: number; max: number; step: number unit?: string baseline?: number // statu quo — marqueur creux toujours affiché derived?: boolean // résolu par la contrainte, jamais voté — étiquette « calculé » } interface ParamSpec { params: ParamDef[] // ≤ 7 (leçon SejeteralO : petit espace manipulable) constraint: 'none' | 'sum100' // sum100 : les 'share' totalisent 100 ; EXACTEMENT UNE part 'derived' // exigée (validé à la création du spec) — la variable d'absorption ; // résolue linéairement (100 − Σ autres) impactAttrKey?: string // clé de Person.attributes → carte « Pour moi » ('linear-share') } interface Decision extends Entity { authorId: Id title: string // LA phrase de capture — seul champ obligatoire body?: string // progressive disclosure brief?: Brief // matière — cf. garde d'ouverture ci-dessus baselineNote?: string // « Aujourd'hui : … » — suggéré routes advice/collective, jamais solo resources?: Resources // SUGGÉRÉ-déplié au tunnel (jamais bloquant) ; EXIGÉ à la garde // d'ouverture de fenêtre/session (state.ts) si weight != 'light' hors solo tags: string[] // découverte + récurrence — JAMAIS un corpus // — verdict de triage (pré-rempli par le moteur, ajustable) — reversibility: Reversibility weight: Weight urgent: boolean scope: { selfOnly: boolean circleIds: Id[] // plancher : élargir libre, JAMAIS restreindre sous le calcul personIds: Id[] } route: DecisionRoute triageRule: TriageRule // relégué au dépliable « pourquoi ? », PV, journal — jamais en carte routeOverridden: boolean overrideNote?: string // OBLIGATOIRE si allègement (asymétrie de dérogation) scopeKeptNote?: string // affluence atteinte + périmètre maintenu ⇒ note motivée PUBLIQUE obligatoire // — spécialisations chaînées (le pliage génératif) — underMandateId?: Id // décidée SOUS ce mandat → feux de la rampe du mandat createsMandate?: MandateDraft amendsClauseId?: Id protocolId?: Id // résolu par le Pacte, ajustable en alourdissant paramSpec?: ParamSpec // si modalité paramétrique (« Réglage collectif ») parentDecisionId?: Id chainKind?: 'ratification' | 'revision' | 'revocation' | 'element' // 'element' : micro-décision d'un dossier découpé (« décision incrémentielle »). // Parent d'éléments : transition framing→closed gardée par // « tous les enfants element en état terminal » — GESTE du garant // (carte au Fil « Le dossier est complet — clore »), jamais automatique ; // la cartographie de clôture devient le PV du dossier. decidedHow?: string // route 'record' : « comment ça s'est décidé », une phrase // — temps & fenêtres — status: DecisionStatus windowEndsAt?: ISODate windowSuspendedAt?: ISODate // objection de frontière → compte à rebours SUSPENDU (visible) decidedAt?: ISODate review?: Review // obligatoire si irreversible || structural sunsetAt?: ISODate stewardIds: Id[] // garants — RÉALISENT (et cristallisent le paramétrique, clôturent le dossier) measurerIds: Id[] // mesureurs — CONSTATENT (saisissent Effect.measured) : la paire doctrinale // — preuve & visibilité — visibility: 'private' | 'scope' | 'collective' // anti-flicage : trace maîtrisée hors mandat engraving?: Engraving } interface Review { dueAt: ISODate verdict?: 'confirmed' | 'revise' | 'revoke' // UI : « Ça tient / À revoir / À révoquer » note?: string decidedAt?: ISODate } interface Engraving { sha256: string engravedAt: ISODate proofLevel: 'local' // v2 : UNIQUEMENT 'local' — « empreinte locale — démo » ipfsCid?: string // réservé v3 — jamais affiché tant que non réel chainRef?: string } // ── Inclusion & fenêtres ───────────────────────────────────── interface Concern extends Entity { decisionId: Id personId: Id origin: 'computed' | 'declared' // UI : « concerné·e en premier lieu » / « en second lieu » reason: string // « membre du cercle Forgerons » — affichée au tap declaredNote?: string beforeSnapshot: boolean // avant liste arrêtée ⇒ vote ; après ⇒ voix consultative priority?: 0 | 1 | 2 | 3 // « pondère tes enjeux » — par élément d'un dossier ; // nourrit la cartographie de clôture, jamais le droit de vote } interface Assent extends Entity { // « Ça me va » STOCKÉ — l'accord explicite des fenêtres d'objection decisionId: Id personId: Id recordedById?: Id // mode atelier } // RÈGLE DES FENÊTRES D'OBJECTION (state.ts) : à échéance sans objection ouverte — // easy ⇒ adopted (silence vaut accord) ; costly/irreversible ⇒ adopted SEULEMENT si // ≥1 Assent d'un concerné ≠ auteur, sinon PROLONGATION d'un cran (+objectionWindowHours, // relance au Fil) — jamais d'adoption par pur silence hors easy. interface Objection extends Entity { decisionId: Id personId: Id kind: 'content' | 'boundary' // boundary SUSPEND la fenêtre — la frontière prime sur le fond argument: string status: 'open' | 'withdrawn' | 'integrated' | 'escalated' resolutionNote?: string recordedById?: Id // mode atelier : « saisi par X pour Y — atelier du » } interface Advice extends Entity { decisionId: Id personId: Id position: 'favorable' | 'reserved' | 'unfavorable' note?: string recordedById?: Id // mode atelier } // ── Le pouvoir ─────────────────────────────────────────────── interface Mandate extends Entity { title: string holderId: Id originDecisionId: Id // le mandat EST né d'une décision — cliquable domain: { circleIds: Id[]; tags: string[] } startsAt: ISODate endsAt: ISODate // toujours borné electorCircleId: Id // corpus d'élection = corpus de révocation nominationMethod: 'ratified-self' | 'election-no-candidate' | 'nuanced-vote' | 'consent' | 'draw' | 'rotation' reports: MandateReport[] status: 'proposed' | 'active' | 'expired' | 'revoked' // AUCUN agrégat/jauge : la fiche affiche des faits comptés (« Exercice du mandat »), // jamais synthétisés ; le flux public = « Feux de la rampe » } interface MandateReport { dueAt: ISODate; deliveredAt?: ISODate; content?: string } interface MandateDraft { title: string domainCircleIds: Id[] domainTags: string[] durationDays: number reportEveryDays?: number } // ── Les textes ─────────────────────────────────────────────── interface TextDoc extends Entity { slug: string title: string role: 'pact' | 'reference' description: string // Pacte seedé : « Notre contrat social — sacralisé, jamais immuable » provenance?: Provenance } interface Provenance { sources: { title: string; url: string; date?: string; version?: string }[] voteRecord?: { url: string; modeParams: string; period: string result: { for: number; against: number; invalid?: number; wotSize: number; thresholdRequired: number; status: string } } contributors?: string[] notes?: string // typos des textes votés : SIGNALÉES, jamais corrigées sans vote } type InertiaPreset = 'low' | 'standard' | 'high' | 'max' // Câblage RÉEL : low={M:50,G:0.1} standard={M:50,G:0.2} high={M:60,G:0.4} max={M:66,G:0.6} (B=0.1, C=0) interface Clause extends Entity { docId: Id section: string position: number code: string title: string inertia: InertiaPreset currentVersionId?: Id settingKey?: string // clauses du Pacte : ex. 'triage.smallGroupMax' } interface ClauseVersion extends Entity { clauseId: Id decisionId: Id // TOUTE version naît d'une décision (y compris fondatrice seedée) versionLabel: string content: string settingValue?: Json status: 'current' | 'proposed' | 'superseded' | 'rejected' adoptedAt?: ISODate } // ── Modalités & vote ───────────────────────────────────────── type VoteMethod = 'consent' | 'binary' | 'nuanced' | 'parametric' | 'election' // UI : consentement · pour/contre (outil de dernier recours) · nuancé · // « Réglage collectif » (au curseur) · élection interface Protocol extends Entity { name: string method: VoteMethod description: string durationDays: number ballot: 'open' | 'secret' // décidé par le Pacte — défaut 'open' (feux de la rampe). // v2 mono-poste : « secret d'affichage — démo » (décomptes agrégés // et commentaires anonymisés seuls) ; crypto réelle avec la synchro (v3) formula: FormulaParams modeParams: string // DSL DÉRIVÉ affiché : 'D30M50B.1G.2S.1' — jamais édité à la main pactClauseId?: Id // référencé par le Pacte ⇒ le modifier = amender le Pacte } interface FormulaParams { majorityPct: number // M baseExponent: number // B (défaut 0.1) gradientExponent: number // G — l'inertie constantBase: number // C (défaut 0) smithExponent?: number techcommExponent?: number nuancedMinParticipants?: number nuancedThresholdPct?: number parametricMinParticipants?: number // quorum du réglage collectif — non atteint ⇒ rejected au geste electionMinParticipants?: number // quorum de l'élection — non atteint ⇒ rejected tieBreak?: 'runoff' | 'draw' // départage d'élection DÉCIDÉ D'AVANCE par le Pacte // (défaut 'runoff' : session de départage chaînée entre ex æquo ; // 'draw' : tirage au sort entre ex æquo — jamais choisi par le moteur) } interface VoteSession extends Entity { decisionId: Id protocolId: Id corpusPersonIds: Id[] // SNAPSHOT à l'ouverture — UI : « liste arrêtée le … » corpusSize: number // W — plus jamais 0 (lettre réservée à l'Atelier) opensAt: ISODate closesAt: ISODate status: 'open' | 'frozen' | 'closed' // 'frozen' : PARAMÉTRIQUE uniquement — à closesAt les votes sont figés, la médiane figée est affichée, // et la session ATTEND le geste humain du garant (relance au Fil s'il tarde). crystallizedById?: Id // le geste « Cristalliser » : qui, quand — daté et signé crystallizedAt?: ISODate outcome?: 'adopted' | 'rejected' | 'tie' // 'tie' : élection à égalité — l'outil ne départage JAMAIS : session de départage chaînée // (restreinte aux ex æquo) ou tirage au sort SI le protocole l'a prévu (tieBreak). // Consent/nuancé/binaire : open→closed automatique à closesAt (le moteur constate un seuil // sur un contenu formulé par des humains). Paramétrique : open→frozen→closed (geste). // INVARIANT : tallies, histogrammes ET médianes TOUJOURS recalculés depuis Vote[] — jamais dénormalisés. } interface Vote extends Entity { sessionId: Id voterId: Id value?: 'for' | 'against' | 0 | 1 | 2 | 3 | 4 | 5 // nuancé UI : 0 Pas du tout · 1 Plutôt non · 2 Réservé · 3 Plutôt oui · 4 Oui · 5 Tout à fait values?: number[] // paramétrique — ordre de paramSpec.params HORS derived choicePersonId?: Id // élection — désignation ; vote déposé sans choicePersonId = BLANC // (compte pour la participation, pas pour la désignation) // INVARIANT : EXACTEMENT UN de value / values / choicePersonId selon la méthode (validé par le store) — // sauf blanc d'élection (aucun des trois, méthode 'election' seulement) comment?: string // OBLIGATOIRE si négatif (against, 0, 1) supersedesVoteId?: Id // re-vote audité — PRIVACY : la chaîne n'est JAMAIS affichée // publiquement sous le nom d'un votant ; visible du SEUL auteur ; // même en ballot 'open', seul le DERNIER vote actif apparaît sous un nom, // le décompte agrégé est recalculé (« pardonner les positions ») recordedById?: Id // mode atelier } // ── Réglages résolus du Pacte (fonction pure — PAS une table settings) ── interface CollectiveSettings { // resolveSettings(pactClauses, versions) triage: { smallGroupMax: number // défaut 5 collectiveMin: number // défaut 50 consentMax: number // défaut 7 objectionWindowHours: number // défaut 48 adviceWindowHours: number // défaut 72 framingDays: number // défaut 14 — « s'instruire et formuler des contre-propositions » concernEscalateRatio: number // défaut 0.5 — atteint ⇒ traitement OBLIGATOIRE (garde state.ts) recurrenceThreshold: number // défaut 3 reviewDelayDays: number // défaut 90 requireEffects: 'none' | 'structural' | 'binding' // clé 'triage.requireEffects' — gouverne la garde matière des sessions COLLECTIVES : // 'binding' = binding ET structural (défaut association/cooperative/commune/free-currency/symmetric) ; // 'structural' = structural seul ; 'none' seedé dans blank et informal. // Sous garde, structural ⇒ ≥1 effet avec cible mesurable (target). } protocolByRange: { consent: Id // OBLIGATOIRE — invariant : tout collectif a un protocole Consentement // (tout gabarit le seede, l'import le valide) nuanced?: Id large?: Id // ex-inertialBinary : le nom ne présume plus la méthode. // Gabarits standard → nuancé ; free-currency → binaire inertiel parametric?: Id // « Réglage collectif » election?: Id clauseByInertia?: Record // l'héritage Ğ1 vit ici, intact } // REPLI SPÉCIFIÉ (resolveSettings) : toute clé optionnelle non résolue retombe sur consent ; // consent introuvable (bundle corrompu) ⇒ le triage route 'advice' avec bannière // « Aucun protocole — crée-le ou décide sur avis » — JAMAIS un crash. } // ── Moteurs purs (frontend/app/engine/ — implémentation UNIQUE, vitest) ── // threshold.ts : wotThreshold(W,T,{M,B,G,C}) — port exact de threshold.py (ceil) ; // + smithThreshold, techcommThreshold, nuancedResult (histogramme 6 niveaux exposé) ; // + electionResult(votes, corpus, formula) → { winnerId } | { outcome:'tie', exAequoIds } // | { outcome:'rejected' } — pluralité simple des derniers votes actifs, blancs comptés // en participation, quorum electionMinParticipants, JAMAIS de départage moteur. // SPEC EXÉCUTABLE : cas Forgeron W=7224 T=120 M50 B.1 G.2 ⇒ 94. // parametric.ts : validateVote(spec, values) — bornes/step/clamp dynamique sum100, sanitize NaN/inf ; // resolveDerived(spec, values) — sum100 linéaire (100 − Σ autres), étiquette « calculé » ; // medianByElement(votes) — MÉDIANE BASSE par curseur (pair ⇒ élément central inférieur : // chaque valeur médiane est une valeur effectivement votée ⇒ step respecté par // construction — « une position que chacun aurait pu proposer », testé) ; // crystallize(spec, votes) — médiane basse des parts votées PUIS resolveDerived ; // derived hors bornes ⇒ clamp à la borne + renormalisation proportionnelle des parts // non-derived (somme 100 restaurée) — spec testée ; // computeMyImpact(spec, resources, values, myAttr, corpusAttrs) — 'linear-share' : // UNIQUEMENT si constraint='sum100' && resources.amount && impactAttrKey ; // montant(p) = amount × p/100 ; maPart(p) = montant(p) × myAttr / Σ corpusAttrs ; // par curseur + total, aux trois positions (mienne/médiane/baseline) ; // myAttr absent ou Σ=0 ⇒ null — JAMAIS un chiffre inventé ; // detectBimodality(values[]) — plus grand écart entre valeurs triées vs dispersion, // jamais bloquant. Dégénérescences : 0 vote ⇒ baseline, jamais d'écran vide. // triage.ts : triage(input, ctx, settings) → Verdict (règles ci-dessous) // modeParams.ts : parse/format du DSL // settings.ts : resolveSettings(clauses, versions) → CollectiveSettings (défauts + replis spécifiés) // state.ts : canTransition(decision, to, ctx: { concerns: Concern[], settings: CollectiveSettings, // session?: VoteSession, children?: Decision[], assents?: Assent[], // objections?: Objection[] }) — machine à états UNIQUE, gardes : // windowSuspendedAt (frontière) ; affluence (ratio ⇒ élargir ou scopeKeptNote) ; // matière (requireEffects) ; ressources (weight != light hors solo) ; // Assent (fenêtres non-easy) ; dossier (framing→closed si children terminaux, geste) ; // cristallisation (paramétrique : closed exige crystallizedById). // impact.ts : computeConcerned(scope, circles, mandates) → { personId, reason }[] // app/lexicon.ts : source UNIQUE des libellés français + test vitest anti-lexique // (déléguer, délégation, dette, retard, en souffrance, corpus, snapshot, // CONTRE, verdict, triage, oligarchie, peuple adulte…). // Règles de ton : (1) tutoyer la personne dans ses gestes ; // (2) actes collectifs à l'infinitif (« Adopter notre Pacte ») ; // (3) sujet des phrases générées = personnes/collectif, JAMAIS la formule. interface TriageInput { title: string; tags: string[] scope: Decision['scope'] reversibility: Reversibility weight: Weight urgent: boolean amendsClauseId?: Id } interface TriageContext { // assemblé par le store, consommé pur — testable sans I/O myActiveMandates: Mandate[] otherActiveMandates: Mandate[] matchingClauses: Clause[] // index Q0 « déjà décidé ? » — le MÊME index que Cmd+K similarRecentCount: number // décisions adoptées partageant ≥2 tags sur 90 j similarRecordedCount: number // consignations 'record' partageant ≥2 tags — maturation computedConcernedIds: Id[] } interface Verdict { route: DecisionRoute rule: TriageRule explanation: string // UNE phrase française — affichée SEULE, sans code de règle protocolId?: Id windowHours?: number framingDays?: number reviewRequired: boolean engravingSuggested: boolean conservatoryChain?: boolean parametricHint?: boolean // nombre/%/montant détecté ⇒ « C'est un réglage » mis en avant alternatives: { route: DecisionRoute; label: string; cost: string }[] // toujours présentes : « C'est un réglage — décidez au curseur » (parametric) ; // « Déjà tranché — je le consigne » (record) ; le binaire avec son coût (« deux camps, un perdant ») suggestion?: { kind: 'claim-mandate' | 'create-rule' | 'protocolize'; prefill: Json } } // ── Persistance locale & synchro future ────────────────────── interface Bundle { // export/import ET seeds — le MÊME chemin de code schemaVersion: 2 exportedAt: ISODate collective: Collective people: Person[]; circles: Circle[] decisions: Decision[]; concerns: Concern[]; objections: Objection[]; advices: Advice[] assents: Assent[] mandates: Mandate[] docs: TextDoc[]; clauses: Clause[]; versions: ClauseVersion[] protocols: Protocol[]; sessions: VoteSession[]; votes: Vote[] } // data/persistence.ts : IndexedDB (idb-keyval), clé `ld2:`, débounce 500 ms. // importBundle() valide protocolByRange.consent + pose Collective.lineage si bundle étranger. // Prêt-synchro : UUIDv7, updatedAt (LWW), archivedAt, Vote/Advice/Objection/Assent append-only. // Contrat des stores Pinia inchangé — l'adaptateur FastAPI futur ne change AUCUN écran. // NOTES contrat : ballot 'secret' devra devenir cryptographique côté serveur (v3) ; // la privacy des chaînes supersedesVoteId (visibles du seul auteur) est un invariant du contrat. ``` ## Cycle de vie ÉMERGENCE — la capture : une phrase dans « Qu'est-ce que tu décides ? » (Fil ou FAB). Crée Decision{status:'draft'}. Dix secondes visées, aucun autre champ obligatoire. Alternative permanente : « Déjà tranché — je le consigne » (route 'record') → adopted immédiat avec decidedHow, zéro fenêtre — l'observatoire en un geste, 2 gestes comme le solo. TRIAGE — le chemin : triage() pur recalcule à chaque geste ; valider fait passer draft → l'état de départ de la route. Toujours expliqué (une phrase française, jamais de code), toujours contournable (alourdir libre 1 tap ; alléger = note obligatoire + fenêtre d'objection imposée — asymétrie journalisée). La ligne « Ce que ça engage » se DÉPLIE en suggestion si weight binding/structural hors solo mais ne bloque JAMAIS le tunnel ; « Aujourd'hui : … » suggéré sur advice/collective. FORMULATION (route collective, poids binding/structural) : status 'framing' — « N jours pour s'instruire et formuler des contre-propositions » (framingDays, défaut 14). La matière (brief) s'édite ICI ; contre-propositions bornées (ClauseVersions ou variantes de body avec diff, contenu d'abord, auteur replié). Sur toute décision structural en framing : « Découper en micro-décisions » — chaque élément part en /decider?parent=&chain=element avec son propre triage/état/modalité ; les concernés pondèrent leurs enjeux (Concern.priority). GARDES D'OUVERTURE (framing→voting ou draft→voting, state.ts) : (a) matière — ≥1 effet recherché exigé si weight ∈ requireEffects du Pacte ('binding' couvre binding+structural ; 'none' dans blank/informal) ; structural sous garde ⇒ ≥1 effet mesurable (target) ; (b) ressources — resources.note exigé si weight != 'light' hors solo. Les deux gardes vivent à l'ouverture, jamais au tunnel. DÉLIBÉRATION — selon la route : - 'solo' selfOnly : draft → adopted immédiat (2 gestes). Trace facultative, visibility 'private' par défaut. - 'record' : draft → adopted immédiat, decidedHow posé, trace pure. - 'mandate' et solo-avec-tiers-dérogatoire : draft → objection (fenêtre 48 h, concernés notifiés au Fil, « Ça me va / J'objecte » — le « Ça me va » crée un Assent). À échéance sans objection ouverte : easy ⇒ adopted (silence vaut accord) ; costly/irreversible ⇒ adopted SEULEMENT si ≥1 Assent d'un concerné ≠ auteur, sinon la fenêtre se PROLONGE d'un cran (+objectionWindowHours, relance au Fil) — jamais d'adoption par pur silence hors easy. Objection 'content' maintenue → escalade framing/voting. Objection 'boundary' → windowSuspendedAt, compte à rebours SUSPENDU. - 'advice' : draft → advice (72 h) ; avis déposés ; l'auteur décide → adopted (avis annexés). Objection formelle → escalade collective/consent. - 'collective' : framing? → voting : VoteSession créée, liste arrêtée (union calculée + déclarés avant arrêt), W fixé. Modalités : consentement (zéro objection maintenue) ; nuancé (nuancedResult, histogramme visible en cours) ; binaire inertiel (votesFor ≥ wotThreshold) ; PARAMÉTRIQUE : curseurs nommés + statu quo + « calculé » + faisceau + médiane vivante + « Pour moi » + Explorer — values[] révisable jusqu'à closesAt (supersedesVoteId, historique visible du seul auteur) ; élection (désignation par avatar, blanc possible). CLÔTURE : consent/nuancé/binaire → automatique à closesAt (le moteur constate un seuil sur un contenu formulé par des humains). PARAMÉTRIQUE → à closesAt la session passe 'frozen' (votes figés, médiane figée affichée) puis le GARANT cristallise (« Cristalliser » → 'closed', crystallizedById/At, médiane basse = position adoptée ; quorum parametricMinParticipants non atteint ⇒ rejected constaté au même geste ; relance au Fil s'il tarde ; bimodalité ⇒ le geste affiche « Deux positions distinctes — cristalliser quand même / scinder / reformuler », jamais d'automatisme). ÉLECTION → automatique (pluralité, quorum electionMinParticipants) SAUF égalité : outcome 'tie', l'outil ne départage jamais — session de départage chaînée entre ex æquo, ou tirage au sort si le Pacte l'a prévu (tieBreak). GARDE D'AFFLUENCE (transversale, state.ts) : si |déclarés| ≥ concernEscalateRatio × |calculés|, la fenêtre/session NE PEUT PAS se clore sans traitement — élargir d'un cran (1 tap, re-triage journalisé) OU scopeKeptNote motivée publique. ADOPTION : decidedAt posé. Micro-célébration : tampon 井 « Décidé » + « C'est décidé — et révisable, comme tout ici ». amendsClauseId → ClauseVersion 'current' automatique. createsMandate → Mandate 'active'. structural/irreversible → review.dueAt + gravure proposée. sunsetAt optionnel. Mode secret : décomptes agrégés seuls (« secret d'affichage — démo »). RÉALISATION / ÉVALUATION : stewardIds réalisent ; measurerIds constatent (Effect.measured). À review.dueAt : « L'ÉPREUVE DU RÉEL » — « Le réel a-t-il suivi ? », tableau recherché/cible/constaté AU-DESSUS des 3 boutons « Ça tient / À revoir / À révoquer » ; écart à baselineNote relu ; ressources réexaminées. 'confirmed' : review close (one-shot → 'closed') ; 'revise'/'revoke' : décision enfant chaînée sous protocole et inertie D'ORIGINE. DOSSIER DÉCOUPÉ : quand tous les éléments sont en état terminal, carte au Fil du garant « Le dossier est complet — clore et publier la cartographie de clôture » ; le geste fait framing→closed du parent, la cartographie devient le PV du dossier. Jamais automatique. RÉVISION / RÉVOCATION : toute décision adoptée porte « Remettre en question » — /decider pré-rempli, protocole et inertie d'origine affichés. Enfant 'revocation' adoptée → parent 'revoked' (« Révoquées — ce qu'on en a appris »). URGENCE : « C'est urgent » — si non irréversible, voie la plus légère MAINTENANT (badge « Décidé en urgence — le collectif ratifie », fenêtre ×2) + ratification chaînée automatique. Irréversible ⇒ refusé : « Irréversible : l'urgence ne peut pas contourner le collectif ». TRANSMISSION : 'transmit' → 'transmitted' (terminal pour l'auteur) ; le mandataire reprend ou l'auteur conteste le mandat. MACHINE À ÉTATS UNIQUE (engine/state.ts) : draft→{advice,objection,framing,voting,adopted,transmitted} ; advice→{adopted,voting} ; objection→{adopted,framing,voting} ; framing→{voting,closed} (closed : dossier complet, geste) ; voting→{adopted,rejected} ; adopted→{revoked,closed} ; + gardes windowSuspendedAt, affluence, matière, ressources, Assent, cristallisation. Toute mutation passe par canTransition(decision, to, ctx). ## Algorithme de triage MOTEUR : engine/triage.ts — fonction PURE triage(input, ctx, settings) → Verdict. Tous les seuils viennent des clauses du Pacte (resolveSettings, replis spécifiés → consent) — le triage est gouverné par ceux qu'il gouverne. « Triage » et « verdict » ne sortent JAMAIS du code : l'UI dit « Le chemin ». La carte affiche l'explanation SEULE (code R* au dépliable « pourquoi ? », au PV et au journal de dérogation). Sujet grammatical : toujours le collectif ou la légitimité, jamais la formule. ENTRÉES EXPLICITES (3 chips max) : 1. Concernés → scope (pré-calculé tags×domains, corrigeable, plancher non restrictible). 2. Réversible ? → easy/costly/irreversible. 3. Ça engage quoi ? → light/binding/structural — si binding/structural hors solo, la ligne « Ce que ça engage » (resources.note + montant/unité) se DÉPLIE en suggestion, jamais bloquante (l'exigence vit à la garde d'ouverture de state.ts). ENTRÉES INFÉRÉES : mandats couvrants, clauses qui matchent (index Q0 = Cmd+K), récurrence, consignations similaires, « C'est urgent », clause visée, nombre/%/montant dans la phrase ⇒ parametricHint. RÈGLES, DANS L'ORDRE — première qui matche (libellés français FINAUX) : - R-U URGENCE (overlay) : urgent && !irreversible ⇒ voie la plus légère MAINTENANT (badge « Décidé en urgence — le collectif ratifie », fenêtre ×2) + ratification chaînée auto. urgent && irreversible ⇒ REFUS : « Irréversible : l'urgence ne peut pas contourner le collectif. » - R0a DÉJÀ DÉCIDÉ : clause en vigueur couvre ⇒ « C'est déjà décidé (E9, Acte Forgeron) — agis. » avec lien, OU « Conteste la règle » ⇒ R3 avec l'inertie de la clause. - R0b MON MANDAT : ⇒ 'mandate' : « Ton mandat Modération couvre — décide, c'est tracé. » Trace obligatoire aux feux de la rampe + fenêtre d'objection 48 h. - R0c MANDAT D'UN AUTRE : ⇒ 'transmit' : « Le mandat de Cgeek couvre — transmets-lui. » Alternative : « Conteste ce mandat ». - R2 MOI SEUL : selfOnly ⇒ 'solo' : « Personne d'autre n'est concerné — décide. » Zéro fenêtre ; si irréversible, revoyure pré-cochée retirable (sur soi l'outil ne s'interpose pas). - R3 CLAUSE VISÉE : amendsClauseId ⇒ 'collective', protocole = clauseByInertia[clause.inertia] (repli → consent si absent) : « Tu proposes une version de E9 — son inertie s'applique : vote de ceux qu'elle gouverne. » L'héritage Ğ1 (binaire inertiel des clauses) survit ICI, intact. - R4 PETIT CERCLE RÉVERSIBLE : easy && |concernés| ≤ smallGroupMax(5) ⇒ 'advice' : « Réversible et 3 personnes concernées — demande leur avis puis décide. » 72 h ; objection formelle ⇒ escalade R5/consent. - R5 COLLECTIF (défaut de l'escalade) : sinon ⇒ 'collective', modalité par taille : ≤ consentMax(7) → consentement (« Vous êtes 6 — un tour d'accord suffit : sans objection, c'est adopté. ») ; ≤ collectiveMin(50) → nuancé (« Vous êtes 23 — vote nuancé : chacun se prononce en nuances, pas en camps. ») ; > collectiveMin → protocole protocolByRange.large résolu par le Pacte (repli → consent) — gabarits standard : « Vous êtes plus de 50 — vote nuancé, la modalité que votre Pacte a choisie. » ; free-currency/Ğ1 : binaire inertiel hérité (« … la formule d'inertie que votre communauté a adoptée »). structural ⇒ + framing + matière selon requireEffects + revoyure + gravure suggérée + inertie haute ; irreversible ⇒ revoyure obligatoire. Si parametricHint : la bascule « régler plutôt que trancher » proposée sous le chemin. - R6 RÉCURRENCE & MATURATION (overlay, jamais bloquant) : similarRecentCount ≥ 3 ⇒ « 3e fois — réclame un mandat » (createsMandate pré-rempli) ou « crée une règle » ; similarRecordedCount ≥ 3 (≥2 tags partagés) ⇒ « Cette pratique est mûre — protocolise-la en quelques phrases » (pré-remplit une clause de Pacte depuis les traces réelles). ALTERNATIVES PERMANENTES (« Je choisis autrement ») : « C'est un réglage (montant, taux, répartition) — décidez au curseur » (parametric, mise en avant si parametricHint) ; « Déjà tranché — je le consigne » (record) ; le binaire pour/contre avec son coût affiché (« deux camps, un perdant ») ; chaque alternative avec son coût. DÉROGATION ASYMÉTRIQUE : ALOURDIR libre — 1 tap journalisé. ALLÉGER = overrideNote obligatoire + fenêtre d'objection 48 h imposée, affiché en évidence. MÊME ASYMÉTRIE AU PÉRIMÈTRE : affluence atteinte ⇒ élargir (1 tap) ou scopeKeptNote motivée publique — jamais d'évaporation silencieuse. Le chemin n'est jamais un juge : il recommande, explique, et laisse faire. MÉTRIQUE PRODUIT : chemin nominal solo = phrase + Entrée + bouton = 2 gestes, < 10 secondes ; le tunnel n'affiche JAMAIS un champ obligatoire qui ne change pas le chemin (les gardes de matière et de ressources vivent à l'ouverture de fenêtre/session, pas au tunnel) ; brief et curseurs vivent APRÈS le tunnel. ## Modalités CINQ MODALITÉS, UNE BOÎTE À OUTILS HIÉRARCHISÉE PAR LA DOCTRINE (chaque protocole est un Protocol nommé, référencé par une clause du Pacte — le modifier = amender le Pacte ; Protocol.ballot open/secret décidé par le Pacte, défaut open « feux de la rampe », secret v2 = « secret d'affichage — démo » ; dans TOUTES les modalités, l'historique de re-vote supersedesVoteId n'est visible que de son auteur — seul le dernier vote actif apparaît sous un nom) : 1. CONSENTEMENT (« Ça me va / J'objecte ») — proposé par R5 pour ≤ consentMax(7), par les escalades d'objection, et REPLI universel de protocolByRange (tout collectif en a un — invariant). Zéro vote : le « Ça me va » est stocké (Assent), tour d'objections argumentées, zéro objection maintenue = adopté. Hors du réversible, ≥1 Assent est requis à l'échéance (sinon prolongation) — l'accord est un geste, pas une absence. 2. NUANCÉ 6 NIVEAUX — proposé par R5 pour 8..collectiveMin(50) ET défaut des grands corpus (protocolByRange.large des gabarits standard). Libellés : 0 « Pas du tout » · 1 « Plutôt non » · 2 « Réservé » · 3 « Plutôt oui » · 4 « Oui » · 5 « Tout à fait » — jamais « CONTRE ». Commentaire OBLIGATOIRE sur 0-1. Histogramme des 6 niveaux visible en cours et à la clôture + commentaires en liste — jamais un simple adopté/rejeté. Valeurs 0-5 et résultats Ğ1 intacts. Clôture automatique à closesAt. 3. PARAMÉTRIQUE — « Réglage collectif » / décider au curseur. JAMAIS routé d'office : proposé dans « Je choisis autrement », mis en avant si parametricHint. paramSpec : ≤7 curseurs à libellés métier ('slider' borné ou 'share' répartition), contrainte 'sum100' avec EXACTEMENT une part 'derived' (variable d'absorption, résolue 100 − Σ autres) — étiquettes « contrainte / calculé ». Salle : curseurs + statu quo + bloc calculé non éditable + faisceau translucide + médiane trait épais + carte « Pour moi » (linear-share spécifié : quote-parts de resources.amount au prorata de l'attribut déclaré — sans attribut, jamais de chiffre inventé) + « Explorer » (sandbox « exploration — ne compte pas »). Vote values[] révisable jusqu'à la clôture. Agrégation NOMMÉE : « Le collectif retient la médiane de chaque curseur — robuste aux extrêmes, et c'est une position que chacun aurait pu proposer. » (médiane BASSE : l'invariant est vrai par construction, step respecté). À closesAt : session 'frozen' — puis CRISTALLISATION = GESTE HUMAIN DATÉ du garant (« Cristalliser », crystallizedById/At ; quorum parametricMinParticipants sinon rejected ; relance au Fil ; bimodalité affichée en évidence au moment du geste : « cristalliser quand même / scinder / reformuler » — jamais d'automatisme). Pour les DOSSIERS complexes : le découpage en micro-décisions (chainKind 'element', « décision incrémentielle ») combine plusieurs modalités élément par élément, avec pondération (Concern.priority) et cartographie de clôture publiée par le geste de clôture du garant. 4. ÉLECTION — reléguée aux seules problématiques d'échelle et de mandats : la nomination EST une décision createsMandate (6 méthodes : auto-désignation ratifiée, élection sans candidat, nuancé, consentement, tirage au sort, rotation). Jamais proposée pour une question de fond. CODÉE : Vote.choicePersonId désigne une personne du corpus ; vote déposé sans désignation = BLANC (participation, pas désignation) ; clôture automatique à closesAt : quorum electionMinParticipants sinon rejected, désignation à la PLURALITÉ simple des derniers votes actifs ; ÉGALITÉ ⇒ outcome 'tie' — l'outil ne départage JAMAIS : session de départage chaînée entre ex æquo (pré-remplie), ou tirage au sort entre ex æquo UNIQUEMENT si le protocole du Pacte l'a prévu d'avance (tieBreak:'draw'). Règle affichée en une phrase dans la salle. 5. BINAIRE INERTIEL (pour/contre + Seuil = C + B^W + (M + (1−M)(1−(T/W)^G))·max(0,T−C)) — HÉRITAGE REMIS À SA PLACE : proposé par R3 pour l'amendement des clauses Ğ1 (clauseByInertia — les 59 Forgeron votées ainsi, D30M50B.1G.2 intact) et par R5 >50 UNIQUEMENT dans free-currency. Partout ailleurs : disponible dans « Je choisis autrement » avec son coût (« deux camps, un perdant ») ; description seedée : « l'outil de dernier recours des très grands corps — remis à sa place dans la boîte à outils ». L'Atelier des formules reste son école (seul lieu des lettres W/T/M/B/G/C et de KaTeX). RÉSOLUTION : protocolByRange { consent (obligatoire), nuanced?, large?, parametric?, election?, clauseByInertia? } — Ids résolus par le Pacte, repli spécifié → consent, ajustables en alourdissant. L'adoption applique automatiquement (clause current, mandat créé) — zéro bouton d'acceptation manuel ; tallies/médianes toujours recalculés depuis Vote[]. ## Périmètres et inclusion LE MOT INSTALLÉ : « Périmètre » = qui est concerné par CETTE décision (panneau de la fiche, frise du chemin) ; « Cercle » = groupe durable de personnes (entité Circle, listes nominatives auditables). Les 3 vecteurs doctrinaux : ÉCHELLE D'ENJEU portée par weight/urgent/reversibility ; THÉMATIQUE par tags/domains (suggestion, jamais un droit) ; TOPOLOGIQUE déclaratif via Circle.kind 'place'|'theme'|'team' (iconographie, groupement, ordre des suggestions — jamais un droit ; hint non bloquant à 12 membres pour les 'team'). Le renommage réserve la place des vecteurs calculés (géo/WoT, v3) sans casser un libellé. DEUX PORTES, UNE LISTE, CHAQUE ENTRÉE SOURCÉE (Concern horodaté) : - CONCERNÉS EN PREMIER LIEU (origin 'computed', pastille pleine) : à la validation du chemin, engine/impact.ts calcule l'union CALCULABLE (membres des cercles du scope ∪ personnes nommées ∪ titulaires des mandats intersectants). Chaque inclusion porte sa raison en clair — auditable en un tap, jamais « la machine t'a désigné ». PLANCHER ANTI-EXCLUSION : élargir libre, JAMAIS restreindre sous le calcul. - CONCERNÉS EN SECOND LIEU (origin 'declared', main levée) : bouton « Ça me concerne » sur toute décision visible, SANS justification — un droit, pas une demande ; motif optionnel public. Déclaré AVANT la liste arrêtée ⇒ vote ; APRÈS ⇒ voix consultative — règle affichée en compte à rebours. OBJECTION DE FRONTIÈRE (suspensive — la contestation des frontières prime sur le fond) : « J'ai été oublié / Untel manque » ⇒ windowSuspendedAt, compte à rebours SUSPENDU (pastille pause, « compte à rebours suspendu — frontière contestée »), priorité maximale au Fil de l'auteur, jusqu'à intégration ou réponse motivée. MONTÉE D'ÉCHELLE — DÉCIDÉE, JAMAIS ÉVAPORÉE : si |déclarés| ≥ concernEscalateRatio(0.5) × |calculés|, bannière « Le périmètre déborde — élargis d'un cran » ET garde dans state.ts : la fenêtre/session ne peut pas se clore sans traitement — élargissement au cercle parent (couches d'oignon, 1 tap, re-triage journalisé — chemin nominal), ou maintien avec scopeKeptNote motivée PUBLIQUE, affichée en évidence comme un allègement. L'asymétrie de dérogation appliquée au lieu doctrinal de la subsidiarité. GRADIENT D'ENGAGEMENT (affiché sur la fiche) : observateur (lecture) < concerné (avis, objection, « Ça me va ») < lié (vote — liste arrêtée) < garant/mesureur (stewardIds réalisent et cristallisent, measurerIds constatent). PONDÉRATION PERSONNELLE DES ENJEUX : sur un dossier découpé, chaque concerné pose Concern.priority 0-3 (« pondère tes enjeux ») depuis le Fil ou la fiche — nourrit la hiérarchie des enjeux de la cartographie de clôture, jamais le droit de vote. ANTI-BRIGADING PAR CONSTRUCTION : déclarations publiques + liste arrêtée + entrée tardive consultative + escalade non-ignorable — et la formule inertielle absorbe l'afflux (gonfler W sans que T suive fait MONTER le seuil). ANTI-FLICAGE (ligne rouge) : hors mandat, trace facultative et visibility choisie ('private' par défaut en solo) ; sous mandat, trace obligatoire visible du cercle électeur — la redevabilité s'applique au pouvoir, jamais aux personnes ; Person.attributes jamais affichés à autrui ni agrégés ; l'historique des re-votes n'est jamais opposable à une personne (visible du seul auteur). FRACTALITÉ : Collective.lineage (« essaimé de … ») mémorise l'essaimage par bundle ; AUCUNE structure fédérale dans le modèle (choix doctrinal documenté) — pattern v3 : une grappe = un collectif ordinaire dont les membres sont des mandataires d'autres collectifs, la fédération = échange de bundles/PV, jamais une table. ## Instruction et évaluation LE PRINCIPE : « Il n'est pas consulté, il est instruit » — pas de vote collectif engageant sans matière, et la même matière sert l'évaluation : la boucle d'« acquisition collective des expériences » est fermée par construction, sans jamais devenir plus lourde que l'enjeu. LA MATIÈRE (Decision.brief) : contexte, sources {label,url}, symptômes vs causes (la qualification doctrinale du sujet), et effects — les EFFETS RECHERCHÉS { label une ligne, target cible mesurable optionnelle, measured constaté }. GARDE DÉFINITIVE (state.ts, ouverture de session collective UNIQUEMENT — framing→voting / draft→voting) : ≥1 effet recherché exigé si weight ∈ clause de Pacte 'triage.requireEffects' ('binding' = binding et structural, défaut des gabarits structurés ; 'structural' ; 'none' seedé dans blank ET informal — le collectif règle sa propre exigence) ; sous garde, structural ⇒ ≥1 effet avec cible mesurable. Le weight 'light' (le trio, « on part le 12 ») n'y est JAMAIS soumis ; le chemin solo/record ne voit JAMAIS ces champs — 2 gestes / 10 s préservés ; la matière s'écrit en framing, pas dans le tunnel. LE BLOC « S'INSTRUIRE » (condensé — réparation intégrée) : en tête de la salle de vote et de la fiche (framing/voting) — un RÉSUMÉ COMPACT toujours visible avant les boutons : titre, effets recherchés, « Ce que ça engage » ; en DÉPLIABLES internes : body, versions + diff (contenu d'abord, auteur replié), avis et objections déposés, provenance (cas Ğ1 : voteRecord). Le bloc entier se replie automatiquement aux visites suivantes de la même personne (préférence locale par décision) — voter sur un titre nu reste structurellement impossible en collectif, re-voter reste léger (« agir d'abord, comprendre ensuite »). La phrase de fenêtre : « 14 jours pour s'instruire et formuler des contre-propositions ». LE STATU QUO (double ancre SejeteralO) : Decision.baselineNote (« Aujourd'hui : … ») suggéré routes advice/collective — en-tête de fiche « Aujourd'hui → Proposé » ; ParamDef.baseline = marqueur « actuel » sur chaque curseur + colonne de la carte « Pour moi » ; les clauses gardent leur diff (qui EST leur baseline). Une décision se lit comme un écart au statu quo, mesurable. LA DÉCISION CONNEXE (Decision.resources) : « Ce que ça engage » — note + montant/unité ('heures'|'€'|'DU'|libre). SUGGÉRÉE-dépliée au tunnel (jamais bloquante), EXIGÉE à la garde d'ouverture de fenêtre/session si weight != 'light' hors solo (même mécanique que la matière). Affichée fiche + résumé S'instruire + PV, réexaminée à l'épreuve du réel. Huile/eau : DU et € jamais convertis ni additionnés — agrégats de l'Observatoire par unité, lignes séparées. La paire doctrinale : stewardIds RÉALISENT (et cristallisent), measurerIds MESURENT. resources.amount est aussi le multiplicande de la carte « Pour moi » (linear-share). L'ÉPREUVE DU RÉEL (Review) : à review.dueAt — « Le réel a-t-il suivi ? », tableau effet recherché / cible / constaté (Effect.measured saisi par les measurerIds) AU-DESSUS des 3 boutons « Ça tient / À revoir / À révoquer » ; écart à la baseline relu ; ressources confrontées. Jamais un jugement dans le vide : « évaluer les expériences avec la curiosité du chercheur », le droit de se tromper est une donnée. L'OBSERVATOIRE (/decisions/observatoire) : comment nous décidons, DANS LES FAITS. Stats d'autonomie (ratio seul/mandat/avis/collectif/consigné, temps médians, participation, dérogations alourdies/allégées/périmètres maintenus, ressources engagées par unité) ; épreuves du réel rendues et dues ; « Révoquées — ce qu'on en a appris » ; élagage suggéré (protocole jamais invoqué, mandat sans trace). LA CONSIGNATION (route 'record') : « Déjà tranché — je le consigne » + decidedHow — consigner AVANT de protocoliser ; ratio consigné/outillé = maturité ; MATURATION (famille R6, jamais bloquante) : ≥3 consignations partageant ≥2 tags ⇒ « Cette pratique est mûre — protocolise-la en quelques phrases » pré-remplissant une clause de Pacte depuis les traces réelles. Le flux consigner→observer→protocoliser est le chemin ordinaire du produit, symétrique de R6 : le contrat social s'écrit au fil de l'eau, depuis la pratique. ## Navigation SHELL : layouts/default.vue. Header : logo-stamp (icône puits, rotation -10°) + « libreDecision » ; WorkspaceSelector (collectifs locaux + finalité A1 en une ligne + « Créer un collectif ») ; recherche globale Cmd+K (index unique clauses/décisions/mandats = le MÊME index que Q0) ; MoodSwitcher ; bouton « Décider » (desktop). FAB « Décider » 56 px mobile, au-dessus du sceau. Sceau hexagramme #48 Tsing 井 fixe bas-droite (géométrie SVG canonique). layouts/bare.vue pour /creer. SIDEBAR — 4 ENTRÉES, pas une de plus : 1. Aujourd'hui (/) — le Fil + la capture. À 3 personnes, c'est tout l'outil. 2. Décisions (/decisions) — le registre + l'Observatoire. 3. Textes (/textes) — les documents sous vote permanent, Pacte épinglé. 4. Mandats (/mandats) — les pouvoirs confiés. DISSOLUTIONS CONSERVÉES : protocoles dans le Pacte + étape modalité du chemin ; Atelier des formules = /textes/formules (lié depuis CHAQUE seuil, seule maison des lettres W/T/M/B/G/C) ; Sanctuaire = badge 井 + fiche de preuve + filtre ; pas de page réglages (les réglages SONT le Pacte) ; préférences locales = /donnees (mood, export/import, identité, attributs personnels, mode atelier). ROUTES : / — Aujourd'hui · /decider — Le chemin (pré-remplissable ?clause= ?parent=&chain= ?mandat=) · /decisions — registre · /decisions/observatoire — L'Observatoire · /decisions/[id] — fiche décision (URL permanente) · /decisions/[id]/vote — salle de vote · /textes — bibliothèque · /textes/formules — Atelier des formules · /textes/[slug] — document vivant · /mandats — liste · /mandats/nouveau — wizard · /mandats/[id] — fiche mandat · /creer — onboarding (bare) · /donnees — données locales. COUCHES CODE : app/types/domain.ts (noyau) ; app/lexicon.ts (source unique des libellés FR + test anti-lexique) ; app/engine/ (threshold avec electionResult, parametric avec crystallize, triage, modeParams, settings, state avec ctx, impact — purs, vitest) ; app/data/ (persistence.ts IndexedDB + seeds/*.bundle.json + templates.ts 7 gabarits) ; app/stores/ (contrat commun prêt adaptateur FastAPI — invariants privacy inclus) ; app/composables/ (useMood, useSettings, useFeed, useSearch) ; app/components/ par domaine (chemin/, decisions/, votes/ dont Faisceau et Curseurs, texts/, mandates/, circles/, common/). Le Fil est un SÉLECTEUR PUR — zéro table notification (il dérive : fenêtres, votes, épreuves dues, rapports dus, frontières, affluences, cristallisations en attente, dossiers complets, suggestions R6/maturation). Budget 400 lignes max par page. CSS print A4 (PV + affiche de session). ## Écrans ### `/creer` — Créer un collectif _Onboarding en 3 écrans — le premier usage EST le tutoriel ; s'ouvre sur le rêve_ Ouverture : « Une démocratie qui n'a jamais existé — à votre échelle. » Écran 1 : nom, couleur, mood. Écran 2 : gabarits en 7 cartes qui TRADUISENT — « Page blanche — observatoire d'abord » EN TÊTE (Pacte : clause « nous consignons nos décisions ; le reste s'écrira au fil de l'eau » + A1 finalité, protocole Consentement SEUL installé, routes solo/consignation/avis/consentement) ; puis Informel / Association / Coopérative / Commune / Communauté monnaie libre réétiquetés « point de départ — tout est amendable par décision » ; et « Institution symétrique » (Déclaration de symétrie, mandats Ambassadeur/Négociateur suggérés, première décision « Déclarer notre symétrie »). Chaque gabarit installe Pacte pré-rempli (préambule Autonomie–Équilibre–Liaison proposé et modifiable, clause A1, clauses settingKey dont requireEffects) + protocoles (au minimum Consentement — invariant) + cercle racine typé. Langage concret (« qui doit être d'accord ? »). Écran 3 : moi + membres initiaux. Imports « Explorer Duniter Ğ1 » / « Explorer l'Atelier du Canal » par le MÊME chemin qu'un import utilisateur. Atterrissage sur / avec la première décision proposée : « Adopter notre Pacte » (collective, consentement). Signature finale « Osons, nous verrons ». Réussite < 10 minutes, testée avec des non-théoriciens. ### `/` — Aujourd'hui _L'écran quotidien unique : capture + Fil personnel — la boîte de réception de la démocratie_ Barre de capture sticky « Qu'est-ce que tu décides ? » (Entrée → /decider). Header « À toi de décider » avec compteur nu (jamais de rouge — interdits : dette, retard, en souffrance). Fil trié par échéance, sections vides masquées : fenêtres d'objection (« Ça me va / J'objecte » inline — le Ça me va crée un Assent ; compte à rebours ; pastille pause si frontière contestée ; mention « il manque un accord explicite » si fenêtre prolongée) ; avis demandés (3 boutons inline) ; votes ouverts (jauge miniature, lien salle) ; À CRISTALLISER (garant d'un réglage collectif figé : « Les votes sont figés — cristallise la médiane », relance persistante) ; DOSSIER COMPLET (garant : « Le dossier est complet — clore et publier la cartographie de clôture ») ; égalité d'élection à départager (session chaînée proposée) ; épreuves du réel dues (« Ça tient / À revoir / À révoquer » inline) ; rapports de mandat dus ; objections de frontière à traiter (priorité haute) ; périmètre débordant (élargir / maintenir motivé) ; pondération d'enjeux demandée ; suggestions de la boucle apprenante (« 3e fois — réclame ce mandat », « Cette pratique est mûre — protocolise-la », « ce protocole n'a jamais servi — élague »). Ensuite l'activité du collectif (selon visibility). Tout est sélecteur Pinia pur. Mobile-first absolu. ### `/decider` — Le chemin (tunnel) _Une phrase → un chemin exécutable en un tap — 10 s pour le routinier, 3 min pour le stratégique_ Phrase en haut (pré-remplie par capture ou query clause/parent/chain/mandat). Résultats Q0 « déjà décidé ? » inline dès la frappe. 3 chips : Concernés (avatars pré-calculés, plancher non restrictible), Réversible ?, Ça engage quoi ? — si binding/structural hors solo, la ligne « Ce que ça engage » se DÉPLIE en suggestion (note + montant/unité, jamais € et DU additionnés) mais ne bloque JAMAIS la validation (l'exigence vit à l'ouverture de fenêtre/session) ; « Aujourd'hui : … » suggéré sur avis/collectif. Toggle « C'est urgent » discret. Carte LE CHEMIN live : grande icône de route, l'explication en une phrase SEULE (aucun code R*), frise le périmètre / combien de temps / quel seuil, revoyure et gravure pré-cochées si exigées, UN bouton principal. « Je choisis autrement » toujours visible : alternatives avec coût, dont « C'est un réglage — décidez au curseur » (mise en avant si nombre/%/montant détecté), « Déjà tranché — je le consigne » (→ adopted immédiat + « comment ça s'est décidé »), binaire avec « deux camps, un perdant ». Alourdir 1 tap journalisé ; alléger = note + fenêtre imposée. « Pourquoi ? » dépliable (le code de règle y vit). Suggestions R6/maturation sous le chemin. Valider crée la Decision structurée dans le bon état. ### `/decisions` — Registre des décisions _Toutes les décisions par état — SectionLayout conservé_ Pills d'état en français courant (préparation / avis / objection / formulation / vote / figé / en vigueur / clos / rejeté / révoqué) aux couleurs du cycle. Filtres : cercle (groupés par kind lieu/thème/équipe), tag, « me concerne », poids, gravées 井, consignées. Formes courtes des routes en pills (seul / sous mandat / transmis / sur avis / ensemble / consigné). Cartes : titre, icône de route, poids, échéance, jauge miniature, badge 井, badge « Décidé en urgence — le collectif ratifie ». Lien vers l'Observatoire. Zéro création ici — on crée par la capture. ### `/decisions/[id]` — Fiche décision _URL permanente de l'objet pivot — progressive disclosure par état_ En-tête : titre, « Aujourd'hui → Proposé » si baselineNote, route en français, poids, badges (urgence, allègement avec note, périmètre maintenu avec scopeKeptNote en évidence, 井). Timeline verticale du cycle. Panneau PÉRIMÈTRE : concernés en premier lieu (pastille pleine, tap → raison) et en second lieu (main levée, note publique), « Ça me concerne », compte à rebours de la liste arrêtée, bannière d'affluence NON-IGNORABLE (élargir 1 tap / maintenir motivé), objection de frontière (pastille pause). Bloc S'INSTRUIRE (framing/voting) : résumé compact toujours visible (titre, effets, ce que ça engage) + dépliables (body, versions/diff auteur replié, avis/objections, provenance) — auto-replié aux visites suivantes. Selon l'état : bloc fenêtre (boutons inline, silence-vaut-accord affiché seulement si réversible, sinon « un accord explicite est requis » avec compteur d'Assents) ; bloc formulation (« N jours pour s'instruire… », « Découper en micro-décisions » sur structural) ; onglet ÉLÉMENTS si dossier (filtre « me concernent », états, échéances, pondération 0-3) + CARTOGRAPHIE DE CLÔTURE auto-générée + carte « Le dossier est complet — clore » quand tous terminaux (geste du garant) ; bloc session (lien salle, résultat, « Qui vote : N personnes — liste arrêtée le … », bandeau « Votes figés — en attente de cristallisation » si frozen) ; bloc vigueur (garants, mesureurs, ressources, sunset, épreuve du réel due : tableau recherché/constaté au-dessus des 3 boutons) ; chaînage cliquable. Poignée « Remettre en question » sur tout adopté (protocole et inertie D'ORIGINE affichés). Actions : Imprimer (PV A4), graver (« empreinte locale — démo »), micro-copy « à trancher en présence ? » sur structural. Budget 400 lignes. ### `/decisions/[id]/vote` — Salle de vote _Le geste démocratique central — instruit, puis prononcé_ Bloc S'INSTRUIRE condensé en tête : résumé compact toujours visible avant les boutons (titre, effets recherchés, ce que ça engage) + dépliables (texte/diff, avis et objections, provenance) — replié automatiquement aux visites suivantes. « Qui vote : 11 personnes — liste arrêtée le 12/08 » (avatars). Selon la méthode : CONSENTEMENT (« Ça me va » stocké / « J'objecte » argumentée) ; NUANCÉ 6 niveaux (« Pas du tout » → « Tout à fait », commentaire obligatoire inline sur 0-1, HISTOGRAMME sous la jauge) ; BINAIRE hérité (jauge inertielle : arc animé, seuil qui descend quand la participation monte, phrase sujet-collectif : « 120 votants sur 7 224 : à si faible participation, il faut presque l'unanimité — 94 pour. Plus de monde vote, plus le seuil descend. », lien « comprendre ce seuil » → Atelier pré-réglé) ; PARAMÉTRIQUE « Réglage collectif » : un curseur par paramètre (libellé métier, marqueur statu quo creux, alternative clavier + champ numérique), bloc « calculé » non éditable (étiquettes contrainte/calculé), FAISCEAU strip-plot (points translucides anonymes, médiane basse trait épais), carte « POUR MOI » (ma position / médiane / statu quo — quote-parts de « ce que ça engage » au prorata de mon attribut déclaré, « estimation sur données déclarées », jamais de chiffre inventé), « EXPLORER » (sandbox « exploration — ne compte pas », partir de la médiane/du statu quo/de ma position, « En faire ma position »), phrase d'agrégation « Le collectif retient la médiane de chaque curseur — robuste aux extrêmes, et c'est une position que chacun aurait pu proposer », bannière bimodalité non bloquante ; à closesAt bandeau « Votes figés — le garant cristallise » puis bouton « CRISTALLISER » (garant seul, quorum vérifié, bimodalité rappelée : « cristalliser quand même / scinder / reformuler ») ; ÉLECTION (désignation par avatar, bouton « Vote blanc », règle en une phrase : « La personne la plus désignée est nommée ; en cas d'égalité, vous départagez — jamais l'outil » ; égalité ⇒ session de départage chaînée ou tirage au sort si le Pacte l'a prévu). Mode secret : décomptes agrégés et commentaires anonymisés seuls, « secret d'affichage — démo ». Mon vote remplaçable — « ton historique n'est visible que de toi » (chaîne supersedes jamais publique, dernier vote seul affiché sous un nom en ballot open). Bouton « Imprimer » : affiche de session A4. Clôture : distribution complète + arguments — jamais un simple adopté/rejeté ; adoption ⇒ application automatique + tampon 井 « C'est décidé — et révisable, comme tout ici ». ### `/decisions/observatoire` — L'Observatoire _Comment nous décidons, dans les faits — le miroir et l'apprentissage_ Titre « L'Observatoire », sous-titre « comment nous décidons, dans les faits ». Stats d'autonomie : ratio seul/mandat/avis/collectif/CONSIGNÉ (consigné/outillé = maturité), temps médians par route, taux d'objection, participation, dérogations (alourdies/allégées/périmètres maintenus), ressources engagées PAR UNITÉ (heures / € / DU — lignes séparées, jamais additionnées). Épreuves du réel : dues, rendues (tenues/à revoir/révoquées). « Révoquées — ce qu'on en a appris » : chaque révoquée avec sa chaîne — curiosité du chercheur, pas de lugubre. Consignations : liste des « déjà tranché » avec decidedHow ; maturation : ≥3 consignations partageant ≥2 tags ⇒ carte « Cette pratique est mûre — protocolise-la en quelques phrases » (pré-remplit une clause de Pacte). Élagage : protocole jamais invoqué, mandat sans trace 6 mois → revue suggérée. Décisions jamais revues : relance puis archivage proposé. Filtres personne/cercle/tag/période. Graphiques sobres (skill dataviz). ### `/textes` — Textes _La bibliothèque des documents sous vote permanent_ Pacte épinglé en tête : badge « les règles du jeu » + sous-titre « Notre contrat social — sacralisé, jamais immuable ». Cartes documents : titre, rôle, clauses, sessions en cours (mini-jauges), provenance Ğ1 (Certification 33 clauses, Forgeron 59 v2.0.0-fr, Comité Technique). « Déclaration de symétrie » pour les collectifs symmetric. Lien Atelier des formules. Filtre gravées. ### `/textes/[slug]` — Document vivant _Clauses versionnées, boucle vote⇒texte fermée_ Sections repliables + scroll-spy. Chaque clause : code, titre, pastille d'inertie CÂBLÉE au protocole d'amendement, mini-jauge sur session réelle, statut. Tap → détail : version courante, propositions avec diff (contenu d'abord, auteur replié), décision fondatrice et amendements chaînés. « Proposer une version » → /decider?clause= (R3, inertie de la clause). Vue projetée conservée. InertiaSlider pédagogique → Atelier pré-réglé. Provenance/GenesisBlock (sources, voteRecord 97/23/19, notes — typos signalées jamais corrigées). Spécifique Pacte : clauses settingKey en clair (« Petit groupe : jusqu'à 5 personnes », « Matière exigée : décisions engageantes et structurantes »), effet IMMÉDIAT à l'adoption (resolveSettings), clause d'inertie protégée par l'inertie maximale ; clause A1 — Notre finalité en tête ; préambule Autonomie–Équilibre–Liaison. ### `/textes/formules` — Atelier des formules _La pédagogie du seuil — seule maison des lettres_ FormulaEditor : sliders M/B/G/C (+Smith/ComTech), KaTeX de la formule inertielle, table de participation, presets d'inertie comparés. Branché sur engine/threshold.ts UNIQUE. Accessible depuis chaque seuil affiché, pré-réglé (« pourquoi 94 ? »). Cas Forgeron 2026 en un clic (W=7224, T=120 ⇒ 94). Le binaire présenté comme outil d'exception (« l'outil de dernier recours des très grands corps »). Section « Réglage collectif » : la médiane basse par curseur expliquée (robuste aux extrêmes, une position que chacun aurait pu proposer), mini-démo interactive, et la règle de cristallisation (« l'agrégat éclaire, le geste cristallise »). ### `/mandats` — Mandats _La carte des pouvoirs confiés : qui peut décider quoi, jusqu'à quand_ Cartes par statut (proposé/actif/expiré/révoqué) : titulaire, domaine (cercles + tags), échéance, prochain rapport dû, COMPTEURS BRUTS (« 12 décisions tracées · 1 objection · 2/2 rapports ») — AUCUNE jauge, aucun agrégat. Bouton « Réclamer un mandat » → wizard (souvent pré-rempli par R6). ### `/mandats/[id]` — Fiche mandat _Le pouvoir confié, visible et reprenable_ Titulaire, origine (la décision créatrice — cliquable), domaine explicite, période, cercle électeur. Bloc « EXERCICE DU MANDAT » : faits comptés jamais synthétisés — n décisions tracées, objections ouvertes/intégrées/escaladées (liste cliquable), rapports rendus/dus. Bloc « FEUX DE LA RAMPE » (sous-titre « toutes les décisions prises sous ce mandat — contestables ») : flux des décisions sous mandat, chacune avec sa fenêtre d'objection. Rapports de redevabilité. « Demander la révocation » en un geste : /decider chaîné (revocation) au protocole de nomination D'ORIGINE, cercle électeur comme périmètre — jamais improvisée, jamais plus coûteuse que l'élection. ### `/mandats/nouveau` — Wizard mandat _Le meilleur flux v1, conservé et branché sur le pivot_ 3 étapes : (1) rôle et domaine (titre, cercles, tags, mission en une phrase) ; (2) modalité de nomination parmi 6 (auto-désignation ratifiée, élection sans candidat — avec sa règle de clôture affichée : pluralité, blanc, départage par vous, jamais par l'outil —, nuancé, consentement, tirage au sort, rotation) avec pros/cons pédagogiques ; (3) durée bornée + cadence de rapports + cercle électeur. Sortie : une Decision createsMandate routée collective — la nomination EST une décision. ### `/donnees` — Données locales _Local-first assumé : tes données, ton fichier, ta machine_ Export bundle JSON (schemaVersion 2), import avec validation (protocole Consentement requis, collisions) + pose de lineage (« essaimé de … »), réinitialisation par collectif. Seeds (Duniter Ğ1, Atelier du Canal). Identité locale (displayName, isMe) + MES ATTRIBUTS (Person.attributes, clés libres : 'heures/mois'… — « servent uniquement ta carte Pour moi, jamais montrés aux autres »). MODE ATELIER (ex-« agir en tant que ») : saisie assistée en présence — chaque saisie porte « saisi par X pour Y — atelier du » ; l'étiquette démo reste pour les personnages seedés. Niveaux de preuve honnêtes (empreinte locale / IPFS / chaîne — jamais affichés tant que non réels). Note synchro : « un serveur pourra se brancher plus tard, tes données ne changent pas de forme ». ## Vocabulaire UI | Contexte | Terme final | Remplace | |---|---|---| | Carte centrale de /decider et titre du tunnel — le type TS Verdict reste en code ; « verdict » et « triage » ne sortent jamais du code | Le chemin | Le Verdict | | Popover/panneau Périmètre — pastille pleine ; « la machine t'a désigné » est banni | Concerné·e en premier lieu | calculé (glyphe calculator) | | Popover/panneau — la main levée reste ; « Ça me concerne » inchangé | Concerné·e en second lieu — s'est déclaré·e | déclaré | | Chip du tunnel /decider | Concernés | Touchés | | Panneau de la fiche + frise du chemin ; « Cercle » = groupe durable seulement ; « scope » reste code | Périmètre | Cercles (panneau) / « qui est convoqué » | | Sidebar + rôle de /mandats/[id] ; tout dérivé de « déléguer » banni de l'UI (test anti-lexique) | Mandats — les pouvoirs confiés | les pouvoirs délégués | | Header du Fil, compteur nu — interdits : dette, retard, en souffrance ; « dette décisionnelle » survit en métrique interne dev | À toi de décider | dette décisionnelle | | Fiche et cartes mandat — faits comptés, jamais synthétisés ; « confiance » banni des agrégats | Exercice du mandat | Jauge de confiance | | Flux public des décisions prises sous un mandat — contestables | Feux de la rampe | Observatoire (bloc fiche mandat) | | /decisions/observatoire — « comment nous décidons, dans les faits » | L'Observatoire | Mémoire | | Salle et fiche ; W/T/M/B/G/C vivent uniquement à l'Atelier des formules | Qui vote : 11 personnes — liste arrêtée le 12/08 | corpus visible : W, T / snapshot | | Échelle nuancée — valeurs 0-5 et commentaire obligatoire 0-1 inchangés, résultats Ğ1 intacts | Pas du tout · Plutôt non · Réservé · Plutôt oui · Oui · Tout à fait | 0=CONTRE … 5=TOUT À FAIT | | Bloc revoyure — fiche et Fil | L'épreuve du réel / « Le réel a-t-il suivi ? » | Verdict de réalité | | 3 boutons de l'épreuve du réel (Review.verdict inchangé en code) | Ça tient / À revoir / À révoquer | confirmée / réviser / révoquer | | Toggle du tunnel + badge ; « conservatoire » survit dans le PV et la doc | C'est urgent / « Décidé en urgence — le collectif ratifie » | décision conservatoire | | Protocole et mode de la salle — « raisonner curseur / table de mixage » | Réglage collectif / décider au curseur | —(nouveau : VoteMethod 'parametric') | | Clôture paramétrique : « Les votes sont figés — cristallise la médiane » ; « l'agrégat éclaire, le geste cristallise » — jamais automatique | Cristalliser | —(nouveau : geste du garant) | | Bandeau de la salle/fiche entre closesAt et le geste du garant | Votes figés — en attente de cristallisation | —(nouveau : status 'frozen') | | Découpage d'un dossier en micro-décisions — le nom de l'auteur réservé à CE mode (Taïwan) | Décision incrémentielle | —(nouveau : chainKind 'element') | | Section auto-générée du dossier découpé ; publiée par le geste « clore » du garant, devient le PV du dossier | Cartographie de clôture | —(nouveau) | | Étiquettes du paramétrique : cadre en lecture seule vs part dérivée — le votant sait ce qu'il contrôle | contrainte / calculé | —(nouveau) | | Carte d'impact (ma position / médiane / statu quo) — « estimation sur données déclarées », jamais de chiffre inventé | Pour moi | —(nouveau) | | Bloc de tête salle/fiche : résumé compact toujours visible + dépliables, auto-replié aux visites suivantes | S'instruire | —(nouveau, regroupe l'existant) | | Ligne suggérée du tunnel + bloc fiche/PV — la décision connexe de ressources ; exigée à l'ouverture, jamais au tunnel | Ce que ça engage | —(nouveau : resources) | | Alternative permanente du tunnel — l'observatoire en un geste | Déjà tranché — je le consigne | —(nouveau : route 'record') | | Statu quo en en-tête de fiche ; marqueur « actuel » sur chaque curseur | Aujourd'hui : … / Aujourd'hui → Proposé | —(nouveau : baselineNote) | | Libellés des routes (lexicon.ts) — le chemin est un geste, pas une catégorie ; formes courtes en pills de filtres | Je décide · Je décide, sous mandat · Je transmets · J'écoute, puis je décide · Nous décidons | Solo / Mandat / Transmettre / Avis / Collectif | | Salle de vote : la chaîne supersedes n'est jamais publique sous un nom ; seul le dernier vote actif apparaît en ballot open | Ton vote est remplaçable — ton historique n'est visible que de toi | re-vote audité — l'historique reste (indéterminé) | | Élection : vote déposé sans désignation — compte pour la participation, pas pour la désignation | Vote blanc | —(nouveau : élection) | | Règle d'élection affichée en salle ; départage = session chaînée entre ex æquo ou tirage au sort si le Pacte l'a prévu | En cas d'égalité, vous départagez — jamais l'outil | —(nouveau : outcome 'tie') | | Fenêtre d'objection non réversible prolongée : ≥1 « Ça me va » requis — le silence ne vaut accord que pour le réversible | Il manque un accord explicite | —(nouveau : Assent) | | Description seedée du protocole binaire + Atelier ; libellé Ğ1 : « héritage Toile de Confiance » | pour/contre — « l'outil de dernier recours des très grands corps » | vote binaire (neutre) | | Première décision proposée — actes collectifs à l'infinitif (règle de ton n°2) | Adopter notre Pacte | Adoptez votre Pacte | | Section de l'Observatoire — droit à l'erreur, curiosité du chercheur | Révoquées — ce qu'on en a appris | Cimetière des révoquées | | /donnees — saisie assistée en présence, passerelle hors-écran | mode atelier — « saisi par X pour Y — atelier du » | agir en tant que (pur démo) | | Étiquette du sandbox Explorer de la salle paramétrique | exploration — ne compte pas | —(nouveau) | | Métadonnée d'affichage d'un collectif né d'un bundle d'un autre | essaimé de … | —(nouveau : lineage) | | Pastille pause de l'objection de frontière | compte à rebours suspendu — frontière contestée | (conservé v1 — il est juste) | ## Seeds EXTRACTION — script backend/scripts/export_seed_bundle.py (venv existant) : importe seed.py (33 items Certification, 59 Forgeron, GENESIS, VOTER_NAMES ×11, mandates ×3, protocoles) et émet frontend/app/data/seeds/duniter-g1.bundle.json au schéma Bundle v2 (avec assents:[]). TEST DE NON-PERTE (vitest, bloquant) : 33+59 clauses, presets d'inertie conservés, provenance.voteRecord == {for:97, against:23, invalid:19, wotSize:7224, thresholdRequired:97, modeParams:'D30M50B.1G.2S.1'}, 11 personnes dont 5 smiths, 3 mandats, protocoles complets. Diff exigé AVANT dépréciation de seed.py. Typos des textes votés : Provenance.notes, JAMAIS corrigées. MAPPING Ğ1 (v1 conservé, amendé) : Collective{template:'free-currency', isTransparent:true} ; 11 Person (5 smiths) ; Circles typés kind — « Toile de confiance » (racine), « Forgerons » (team), « Comité Technique » (team) ; TextDocs Certification (33 clauses, presets câblés), Forgeron (59 clauses v2.0.0-fr, voteRecord complet), Comité Technique ; pacte-duniter-g1 avec clauses settingKey (smallGroupMax=5, collectiveMin=50, consentMax=7, fenêtres 48/72, framingDays=14, concernEscalateRatio=0.5, recurrenceThreshold=3, reviewDelayDays=90, requireEffects='binding', clause A1 « Notre finalité » adaptée à la toile), clause d'inertie en preset 'max', description du Pacte « Notre contrat social — sacralisé, jamais immuable ». protocolByRange : consent → « Consentement » (D7, OBLIGATOIRE partout), large → « Vote WoT standard » (binaire inertiel D30M50B.1G.2, description « l'outil de dernier recours des très grands corps — héritage Toile de Confiance ») — L'HÉRITAGE À SA PLACE ; clauseByInertia mappé sur les 4 presets ; + « Réglage collectif » (parametric, D14, parametricMinParticipants), « Vote nuancé » (D30), « Vote forgeron Smith » (S.1), « Vote ComTech » (T.1), « Élection sans candidat » (D14, electionMinParticipants, tieBreak:'runoff') — tous ballot:'open'. Chaque clause courante reçoit sa DÉCISION FONDATRICE. 3 Mandates (ComTech Cgeek active + rapport dû ; Administrateur Forgerons proposed EN VOTE nuancé ; Modération Forum active). Décisions historiques : Runtime Upgrade 1100 (adopted, structural, gravée, revoyure posée + brief.effects rétro-documentés), Évolution licence v0.4.0 (framing avec versions). DEUXIÈME COLLECTIF — atelier-du-canal.bundle.json (test permanent de marque blanche) : association fictive 12 membres, Pacte à seuils DIFFÉRENTS (smallGroupMax=4, fenêtres courtes, requireEffects='binding'), protocolByRange.large → NUANCÉ (la démonstration anti-binaire), Règlement intérieur 8 clauses, cercles typés Bureau (team) / Ateliers (theme) / Tous (racine), mandat Trésorerie (rapport dû), Person.attributes seedés ('heures/mois'). Décisions à TOUS les états : draft, advice en fenêtre, objection SUSPENDUE par frontière, objection non-easy avec 1 Assent posé (démonstration « accord explicite »), framing avec 2 versions et diff, voting nuancé en cours (histogramme vivant), adopted avec épreuve du réel due (brief.effects + measurerIds + resources posés — boucle complète), revoked (« ce qu'on en a appris »), conservatoire + ratification chaînée, UNE CONSIGNATION 'record' (« Le marché du samedi est reconduit — décidé au café, comme d'habitude ») et UN DOSSIER DÉCOUPÉ (2 éléments dont 1 terminal, priorités posées, cartographie de clôture en construction) ; et LE PARAMÉTRIQUE D'EXEMPLE : « Répartir le budget d'ateliers 2026 » en voting — resources { note:'budget annuel ateliers', amount:1200, unit:'€' }, paramSpec sum100 avec 3 parts nommées + EXACTEMENT 1 part 'derived' « Réserve (calculé) », baselines posées, impactAttrKey 'heures/mois', 5-6 votes seedés → faisceau, médiane basse et « Pour moi » calculables et vivants à l'ouverture ; une SECONDE session paramétrique 'frozen' (closesAt passé) avec la carte « À cristalliser » au Fil du garant — la cristallisation-geste démontrée. Tout contenu Ğ1 en dur dans le code est structurellement impossible. GABARITS (/creer, app/data/templates.ts) — SEPT : blank « Page blanche — observatoire d'abord » (Pacte : clause consignation + A1, protocole Consentement SEUL — l'invariant protocolByRange.consent satisfait, toutes les autres clés en repli → consent, requireEffects='none') ; informal (requireEffects='none') / association / cooperative / commune réétiquetés « point de départ — tout est amendable par décision », protocolByRange.large → nuancé partout, requireEffects='binding' ; free-currency (mapping Ğ1, large → binaire inertiel, unité DU par défaut dans resources) ; symmetric « Institution symétrique » (Pacte transparence totale, TextDoc « Déclaration de symétrie », première décision « Déclarer notre symétrie », mandats suggérés Ambassadeur et Négociateur). Chaque gabarit : préambule Autonomie–Équilibre–Liaison proposé et modifiable + clause A1 (défaut : boussoles vitalité/émancipation) + cercles typés kind + protocole Consentement au minimum. Les seeds s'importent par le MÊME chemin que l'import utilisateur ; lineage posé si bundle d'origine étrangère ; l'import valide l'invariant consent. ## Directives de design ICONOGRAPHIE DES ROUTES (vocabulaire visuel fixe) : solo = i-lucide-zap ; sous mandat = i-lucide-key-round ; transmettre = i-lucide-send ; avis = i-lucide-message-circle ; collectif = i-lucide-users ; consignation = i-lucide-notebook-pen ; urgence = i-lucide-siren ; déjà décidé = i-lucide-book-open-check ; récurrence→mandat = i-lucide-repeat ; réglage collectif = i-lucide-sliders-horizontal ; cristallisation = i-lucide-stamp (le geste). Carte Le chemin : icon-container 14 px, nom de route en 700 À LA PREMIÈRE PERSONNE, l'explication en une phrase dessous (jamais de code R*), frise périmètre/durée/seuil, bouton principal pill 20 px plein accent, alternatives en pills fantômes. Teintes déclinées des custom properties du mood. PÉRIMÈTRE : stacks d'avatars (initiales, teinte déterministe de l'id), débord -8 px, « +N ». Premier lieu = pastille pleine en coin (glyphe calculator SUPPRIMÉ) ; second lieu = main levée + fond légèrement teinté. Tap → popover chaîne d'inclusion. Plancher verrouillé visuellement (pas de croix de retrait sur les premiers-lieu). Cercles emboîtés en chips imbriquées ; icône par kind (lieu/thème/équipe). CYCLE DE VIE : timeline verticale à pastilles pleines reliées (pas de bordure) — draft neutre, avis/objection ambre + compte à rebours, vote bleu + mini-jauge, FIGÉ bleu-gris avec icône tampon en attente (« votes figés — en attente de cristallisation »), en vigueur vert, épreuve du réel violette, révoqué terre cuite, clos gris, rejeté barré. SUSPENSION : pastille pause + fond strié + « compte à rebours suspendu — frontière contestée ». Fenêtre prolongée (Assent manquant) : ambre soutenu + « il manque un accord explicite ». Un seul mapping état→couleur. JAUGE INERTIELLE (signature, héritage) : arc 270°, seuil qui DESCEND quand la participation monte, chiffres clairs, phrase générée sujet-collectif. KaTeX réservé à l'Atelier. NUANCÉ : 6 segments en gradient sémantique construit depuis la palette du mood (skill dataviz, jamais rouge/vert crus) ; HISTOGRAMME des 6 niveaux sous la jauge (la distribution, pas seulement le résultat) ; commentaire obligatoire inline sous 0-1. CURSEURS (Réglage collectif) : poignées tactiles ≥ 2.25 rem AVEC alternative clavier + champ numérique (correction SejeteralO) ; libellé métier au-dessus, unité, valeur courante en 700 ; marqueur statu quo = losange creux sur le rail ; part « calculé » = rail estompé non saisissable + étiquette « calculé » ; étiquette « contrainte » sur le cadre ; clamp dynamique visible (le rail se raccourcit quand la réserve dérivée approche de ses bornes). FAISCEAU : strip-plot par curseur — chaque position = point translucide anonyme (opacity ~0.25), médiane = trait épais accent, baseline = marqueur creux ; « transparence des agrégats, discrétion des personnes ». Carte « Pour moi » : fond légèrement teinté accent, trois colonnes ma position / médiane / statu quo, mention « estimation sur données déclarées ». Sandbox Explorer : bandeau « exploration — ne compte pas », curseurs en teinte neutre. CRISTALLISATION : bouton-tampon réservé au garant, confirmation avec rappel de bimodalité le cas échéant — le geste est solennel mais léger (un tap + confirmation), jamais une cérémonie. MICRO-CÉLÉBRATION D'ADOPTION : le tampon 井 incliné -10° s'appose « Décidé » (translateY du système, 0.12s ease, aucune fanfare) + « C'est décidé — et révisable, comme tout ici ». GRAVURE ET PREUVE : badge 井 tampon incliné sur objets gravés ; fiche de preuve sha256 mono tronqué copiable + « empreinte locale — démo ». Sceau hexagramme #48 Tsing : géométrie SVG canonique (viewBox 112×105, 6 traits, trait 1 en bas = dernier rect, opacity ~0.28, drop-shadow CSS), fixe bas-droite, jamais recouvert ; FAB au-dessus avec décalage. PRINT A4 : feuille CSS print pour le PV (/decisions/[id]) et l'affiche de session (/decisions/[id]/vote) — titre, texte, qui vote, seuil, échéance, comment participer ; noir sur blanc, sans moods. La cartographie de clôture d'un dossier s'imprime comme PV. MOODS v2 (champ lexical du puits, 2 light + 2 dark) : Source (light bleu d'eau), Margelle (light sable/pierre), Nappe (dark bleu profond), Minuit (dark encre). Socle : borderless (background + box-shadow), arrondis 16/12/20/14, hover cards translateY(-3px) 0.12s, mobile-first clamp(), breakpoints 480/768/1024, touch ≥ 2.25 rem. useMood.ts conservé. ## Hors scope v2 - Décision paramétrique COMPLÈTE : équation de réalité pluggable (viabilité auto-calculée type p0 non linéaire), éditeur de courbes 'curve' (Bézier, ParamKind réservé), impact sur données réelles importées du périmètre, rétro-manipulation résultat→contrainte — v2 livre curseurs bornés + répartition sum100 (un derived, clamp/renormalisation spécifiés) + médiane basse + faisceau + baseline + impact linear-share sur attribut déclaré ; le solveur et le registre importé en v3 - Builder d'indicateurs de l'observatoire (indicateurs propres définis par le collectif) — construire l'éditeur avant d'avoir observé la pratique contredirait l'observatoire lui-même ; v2 = stats fixes + effets recherchés/constatés + consignations - Vecteur topologique calculé (bassin de vie, commune pivot, géo) et règles d'appartenance WoT — v2 : listes nominatives + Circle.kind déclaratif ; enum de règle extensible sans migration - Vote secret cryptographique et pseudonymat certifié @personne (deux identités découplées) — v2 : ballot 'secret' en secret d'affichage honnête + dépersonnalisation d'ordre d'affichage ; la crypto arrive avec la synchro et l'auth Duniter - Économie du don outillée : allocation en DU effective, budget de gratitude, caisses fléchées, coefficients relatifs, rétribution des mandats pilotée par le collectif — v2 se limite à l'unité 'DU' descriptive dans resources (gabarit free-currency) ; l'intégration exige Ğ1/GrateWizard - Grappes et fédération inter-collectifs opérationnelles — v2 pose lineage + le pattern documenté « une grappe = un collectif ordinaire dont les membres sont des mandataires d'autres collectifs ; la fédération = échange de bundles, jamais une table » ; jamais de parentCollectiveId - Engagements fermes à seuil critique (crowdaction : recueillir, ne déclencher qu'au quota) — nouveau type d'objet et de cycle de vie, backlog v3 - Cartographie thématique vectorielle (liaisons, interdépendances, symptômes/causes visualisés) — v2 : tags plats + champ symptomsVsCauses du brief ; la carte manipulable est un produit en soi - Événements de brassage générés par l'outil et multi-postes simultanés pour ateliers physiques — v2 livre l'imprimable A4 + le mode atelier mono-poste (intermédiation humaine, doctrinalement acceptable) - Délégation liquide / procuration — si elle arrive en v3, la nommer « mandater son vote » (jamais « déléguer » — le test anti-lexique l'attrapera) - IA repositionnée sur la recherche des biais décisionnels (seul usage autorisé par la doctrine) — exige corpus réel + backend ; jamais de suggestion prescriptive - Synchronisation backend / adaptateur FastAPI — contrat des stores et Bundle prêts (invariants privacy des re-votes et ballot secret notés au contrat) ; brancher l'API ne change aucun écran - Auth Duniter challenge-réponse Ed25519 — identités locales v2, duniterAddress réservé - Notifications sortantes (email, digest) et WebSocket temps réel — tout est in-app dans le Fil ; silence-vaut-accord réservé au réversible en conséquence, et l'Assent couvre le reste - IPFS et ancrage on-chain — proofLevel 'local' uniquement, champs réservés jamais affichés - Jugement majoritaire, catalogue 18 modalités × 9 nominations, ProcessTemplate opérationnels, exports juridiques signés — bibliothèque documentaire ; le PV markdown/A4 reste « registre de légitimité, jamais substitut légal » - Passerelles hors-écran complètes (relais humains institués, restitutions événementielles) et horizon des institutions symétriques réelles — consignés dans la page-manifeste/README comme horizon nommé, pas comme dette ## Plan d'implémentation 1. 1. SOCLE, LEXIQUE ET MOTEURS — branche v2, shell vers layouts/, moods 4 ambiances, types/domain.ts complet (ci-dessus, avec Assent, frozen, choicePersonId), app/lexicon.ts (source unique + test vitest anti-lexique + 3 règles de ton) DÈS CE SPRINT, engine/ TS pur (threshold avec electionResult, nuanced, parametric avec crystallize, modeParams, settings avec replis, triage, state avec canTransition(decision,to,ctx), impact) avec vitest portant test_threshold/test_qualifier/test_nuanced/test_mode_params + specs parametric (médiane BASSE step-safe ; sum100 exactement-un-derived + clamp/renormalisation ; computeMyImpact linear-share ; detectBimodality ; dégénérescences 0-vote) + specs election (pluralité, blanc, quorum, tie) + specs state (Assent, affluence, matière, dossier) — le cas Forgeron W=7224 T=120 ⇒ 94 vert AVANT tout écran 2. 2. PERSISTANCE ET SEEDS — data/persistence.ts (IndexedDB, export/import, validation consent obligatoire, lineage à l'import), export_seed_bundle.py, bundles duniter-g1 + atelier-du-canal (paramétrique d'exemple calculable avec resources.amount, session frozen à cristalliser, consignation, dossier découpé, attributs, Assent démontré), tests de non-perte bloquants (33/59 clauses, 97/23/19/7224, 11 personnes, 3 mandats, protocoles), templates.ts 7 gabarits (blank en tête avec Consentement seul, large→nuancé partout sauf free-currency, requireEffects par gabarit) 3. 3. SHELL ET ONBOARDING — header (WorkspaceSelector + finalité A1, Cmd+K, MoodSwitcher, Décider), FAB, sceau 井 canonique, /creer 3 écrans (phrase du rêve, 7 gabarits, « Adopter notre Pacte », signature « Osons, nous verrons »), /donnees (export/import/reset, identité, attributs, mode atelier) 4. 4. LE GESTE — /decider complet (Q0 inline, 3 chips, ligne « Ce que ça engage » suggérée jamais bloquante, baselineNote suggéré, carte Le chemin sans code de règle, C'est urgent, dérogation asymétrique, alternatives permanentes réglage/consignation/binaire-avec-coût, suggestions R6+maturation, création structurée) + / Aujourd'hui (capture sticky, Fil sélecteurs purs incluant cartes À cristalliser / Dossier complet / accord explicite manquant, « À toi de décider » compteur nu, boutons inline) — MESURER : 2 gestes < 10 s, et la consignation aussi 5. 5. CYCLE DE VIE — /decisions (registre) + /decisions/[id] (timeline avec état figé, panneau Périmètre premier/second lieu auditable, Ça me concerne, objection de frontière suspensive, garde d'affluence non-ignorable + scopeKeptNote, bloc S'instruire condensé auto-repliable, fenêtres : silence-vaut-accord easy seulement + Assent + prolongation, gardes d'ouverture matière/ressources, chaînage, Remettre en question au protocole d'origine, PV + print A4, gravure honnête) 6. 6. LE VOTE — /decisions/[id]/vote : consentement (Assent stocké), nuancé (libellés définitifs, histogramme, commentaire 0-1), binaire hérité (jauge inertielle, phrase sujet-collectif, lien Atelier), PARAMÉTRIQUE (curseurs + clavier, statu quo, contrainte/calculé, clamp dynamique, faisceau, médiane basse expliquée, Pour moi, Explorer, frozen + geste Cristalliser du garant + quorum + bimodalité), ÉLECTION (désignation, blanc, pluralité, tie → départage humain), ballot secret d'affichage, liste arrêtée, re-vote à historique privé, mode atelier (recordedById), affiche A4, adoption ⇒ application automatique + micro-célébration 井 7. 7. LES TEXTES — /textes + document vivant (clauses, versions/diff auteur replié, vue projetée, inertie câblée, Provenance/GenesisBlock, Pacte effectif : resolveSettings lu par le triage avec replis, A1 finalité, préambule boussoles, sous-titre, clause requireEffects en clair) + /textes/formules (FormulaEditor sur moteur unique + section médiane/cristallisation du Réglage collectif + binaire repositionné en outil d'exception) 8. 8. LES MANDATS — /mandats (compteurs bruts, AUCUNE jauge), fiche (Exercice du mandat, Feux de la rampe, rapports, révocation chaînée au protocole d'origine), wizard 3 étapes pré-rempli par R6 (règle d'élection affichée) 9. 9. L'OBSERVATOIRE ET LA BOUCLE APPRENANTE — /decisions/observatoire (stats + consigné/outillé, ressources par unité huile/eau, épreuves du réel, Révoquées — ce qu'on en a appris, élagage), l'épreuve du réel complète (tableau recherché/constaté, measurerIds saisissent), suggestions du Fil (récurrence⇒mandat, maturation⇒protocolisation, sunset, élagage) — le système se simplifie lui-même 10. 10. DÉCISION INCRÉMENTIELLE — découpage en micro-décisions (chainKind element), onglet Éléments, pondération des enjeux (Concern.priority), cartographie de clôture auto-générée, clôture du dossier par le geste du garant (framing→closed gardée) — livrée après le socle car elle compose des primitives déjà construites 11. 11. FINITION LIVRABLE — QA mobile+desktop zéro régression (480/768/1024, touch 2.25 rem), parcours complets sur les 2 seeds ET un collectif Page blanche (« Adopter notre Pacte » < 10 min avec un non-théoricien ; consigner→observer→protocoliser déroulé ; cristallisation et départage d'élection déroulés), test anti-lexique vert, a11y clavier (curseurs inclus)/contraste, print A4 vérifié, README + CONTRIBUTING + page-manifeste publique (sans vocabulaire de livraison, close sur « La ville change, le puits demeure »), npm run build zéro erreur, screenshots