{
  "summary": "Confronter le blueprint v1 à la doctrine des livres + SejeteralO et produire le blueprint définitif vérifié",
  "agentCount": 9,
  "logs": [
    "4/4 critiques rendues — synthèse finale",
    "Vérifications : reserves, reserves, reserves — 13 must-fix"
  ],
  "result": {
    "final": {
      "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_v1": [
        {
          "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 »)."
        },
        {
          "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 »."
        },
        {
          "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."
        },
        {
          "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."
        },
        {
          "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."
        },
        {
          "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."
        },
        {
          "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."
        },
        {
          "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."
        },
        {
          "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."
        },
        {
          "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."
        },
        {
          "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 »."
        },
        {
          "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."
        },
        {
          "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."
        },
        {
          "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 »."
        },
        {
          "changement": "Person.attributes?: Record<string, number> (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."
        },
        {
          "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."
        },
        {
          "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é."
        },
        {
          "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 »."
        },
        {
          "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."
        },
        {
          "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 »."
        },
        {
          "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 <date> ») ; (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 »."
        },
        {
          "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."
        },
        {
          "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 »."
        },
        {
          "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."
        },
        {
          "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."
        },
        {
          "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."
        },
        {
          "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."
        },
        {
          "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."
        },
        {
          "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."
        },
        {
          "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."
        }
      ],
      "modele_domaine": "// ─────────────────────────────────────────────────────────────\n// libreDecision v2 — noyau de domaine DÉFINITIF (frontend/app/types/domain.ts)\n// Local-first, prêt-synchro. Identifiants anglais, UI française via app/lexicon.ts.\n// INVARIANT 1 : LA DÉCISION EST L'OBJET PIVOT — mandats, clauses, révocations,\n//   ratifications, éléments de dossier en sont des spécialisations chaînées.\n// INVARIANT 2 : l'unification est un fait d'architecture, JAMAIS un vocabulaire d'UI.\n// INVARIANT 3 : aucun agrégat/score sur une personne, nulle part — on évalue des choses.\n// INVARIANT 4 : aucun calcul ne produit un contenu adopté sans geste humain daté\n//   (cristallisation paramétrique, départage d'élection, clôture de dossier).\n// ─────────────────────────────────────────────────────────────\n\ntype Id = string        // UUIDv7 — triable par temps, prêt pour la synchro\ntype ISODate = string   // ISO 8601 UTC\ntype Json = string | number | boolean | null | Json[] | { [k: string]: Json }\n\n// Toute entité : scoping collectif + horloge de synchro + soft-delete.\n// Prêt-synchro : jamais de suppression physique (archivedAt) ;\n// Vote/Advice/Objection/Assent append-only (merge trivial) ; le reste LWW par updatedAt.\ninterface Entity {\n  id: Id\n  collectiveId: Id\n  createdAt: ISODate\n  updatedAt: ISODate\n  archivedAt?: ISODate\n}\n\n// ── Le tenant ────────────────────────────────────────────────\ntype CollectiveTemplate =\n  | 'blank'          // « Page blanche — observatoire d'abord » : Pacte 1 clause + A1, protocole Consentement SEUL\n  | 'informal' | 'association' | 'cooperative' | 'commune'\n  | 'free-currency'  // héritage Ğ1 — SEUL gabarit où protocolByRange.large = binaire inertiel\n  | 'symmetric'      // « Institution symétrique » — le geste fondateur militant (MNP)\n\ninterface Collective {\n  id: Id\n  slug: string\n  name: string\n  color: string                    // hex accent\n  icon: string                     // i-lucide-*\n  template: CollectiveTemplate\n  isTransparent: boolean\n  pactDocId: Id                    // TextDoc role='pact' — les réglages EN document voté\n  rootCircleId: Id\n  lineage?: {                      // essaimage : posé auto à l'import d'un bundle d'un autre collectif\n    sourceSlug: string; exportedAt: ISODate; sha256: string\n  }                                // PAS de parentCollectiveId — la fédération n'est jamais une table\n  createdAt: ISODate\n  updatedAt: ISODate\n}\n\n// ── Les gens ─────────────────────────────────────────────────\ninterface Person extends Entity {\n  displayName: string\n  isMe: boolean                    // profil local (v2 mono-poste ; « mode atelier » pour la saisie en présence)\n  attributes?: Record<string, number>  // attributs DÉCLARÉS par la personne (clés libres : 'heures/mois'…),\n                                       // édités dans /donnees — servent UNIQUEMENT la carte « Pour moi » ;\n                                       // jamais affichés à autrui, jamais agrégés (invariant 3)\n  duniterAddress?: string          // SS58 — réservé auth Duniter (hors scope v2)\n  wotStatus?: 'member' | 'smith'\n}\n\ninterface Circle extends Entity {\n  name: string\n  purpose: string\n  kind?: 'place' | 'theme' | 'team'  // lieu / thème / équipe — iconographie, groupement des sélecteurs,\n                                     // ordre des suggestions SEULEMENT, jamais un droit ;\n                                     // hint non bloquant si 'team' > 12 (« au-delà de douze… »)\n  memberIds: Id[]                  // v2 : liste nominative = SEULE règle d'appartenance (auditable)\n  parentCircleId?: Id              // emboîtement (couches d'oignon) — racine = rootCircle\n  domains: string[]                // tags — SUGGESTION/découverte uniquement, jamais un droit de vote\n}\n// Corpus d'une décision = union CALCULABLE : membres des cercles du scope\n// ∪ personnes nommées ∪ titulaires des mandats dont le domaine intersecte.\n// Chaque inclusion garde sa raison (Concern.reason) — auditable en un tap.\n\n// ── LA DÉCISION (pivot) ──────────────────────────────────────\ntype Reversibility = 'easy' | 'costly' | 'irreversible'\ntype Weight = 'light' | 'binding' | 'structural'\n\ntype DecisionRoute =\n  | 'solo'        // « Je décide » (trace facultative hors mandat)\n  | 'mandate'     // « Je décide, sous mandat » (trace obligatoire + fenêtre d'objection)\n  | 'transmit'    // « Je transmets » — le mandat d'un autre couvre\n  | 'advice'      // « J'écoute, puis je décide »\n  | 'collective'  // « Nous décidons » (modalité du protocole)\n  | 'record'      // « Déjà tranché — je le consigne » : l'observatoire en un geste, adopted immédiat\n\ntype DecisionStatus =\n  | 'draft' | 'advice' | 'objection' | 'framing' | 'voting'\n  | 'adopted' | 'rejected' | 'revoked' | 'transmitted' | 'closed'\n\ntype TriageRule = 'R-U' | 'R0a' | 'R0b' | 'R0c' | 'R2' | 'R3' | 'R4' | 'R5' | 'R6'\n\n// La matière à réflexion — « il n'est pas consulté, il est instruit »\ninterface Effect {\n  label: string                    // effet recherché, une ligne\n  target?: string                  // cible mesurable optionnelle (« ≤ 400 € », « +5 membres »)\n  measured?: { note: string; at: ISODate; byId: Id }  // constaté — saisi par les measurerIds à la revoyure\n}\ninterface Brief {\n  context?: string\n  sources?: { label: string; url: string }[]\n  symptomsVsCauses?: string        // qualification doctrinale du sujet\n  effects: Effect[]                // GARDE (state.ts, ouverture de session collective UNIQUEMENT) :\n                                   // exigé si weight ∈ requireEffects du Pacte ('binding' couvre binding+structural) ;\n                                   // structural sous garde ⇒ ≥1 effet avec target. JAMAIS pour weight 'light',\n                                   // JAMAIS dans le tunnel, JAMAIS en solo/record.\n}\n\n// La décision connexe de ressources — « chaque décision implique une allocation »\ninterface Resources {\n  note: string                     // « Ce que ça engage » en une phrase\n  amount?: number\n  unit?: 'heures' | '€' | 'DU' | string  // huile/eau : unités JAMAIS converties ni additionnées entre elles\n}\n\n// Le réglage collectif — « raisonner curseur / table de mixage »\ntype ParamKind = 'slider' | 'share'      // 'curve' réservé v3 (SejeteralO complet)\ninterface ParamDef {\n  key: string\n  label: string                    // libellé métier OBLIGATOIRE — jamais de a, b, c bruts\n  kind: ParamKind\n  min: number; max: number; step: number\n  unit?: string\n  baseline?: number                // statu quo — marqueur creux toujours affiché\n  derived?: boolean                // résolu par la contrainte, jamais voté — étiquette « calculé »\n}\ninterface ParamSpec {\n  params: ParamDef[]               // ≤ 7 (leçon SejeteralO : petit espace manipulable)\n  constraint: 'none' | 'sum100'    // sum100 : les 'share' totalisent 100 ; EXACTEMENT UNE part 'derived'\n                                   // exigée (validé à la création du spec) — la variable d'absorption ;\n                                   // résolue linéairement (100 − Σ autres)\n  impactAttrKey?: string           // clé de Person.attributes → carte « Pour moi » ('linear-share')\n}\n\ninterface Decision extends Entity {\n  authorId: Id\n  title: string                    // LA phrase de capture — seul champ obligatoire\n  body?: string                    // progressive disclosure\n  brief?: Brief                    // matière — cf. garde d'ouverture ci-dessus\n  baselineNote?: string            // « Aujourd'hui : … » — suggéré routes advice/collective, jamais solo\n  resources?: Resources            // SUGGÉRÉ-déplié au tunnel (jamais bloquant) ; EXIGÉ à la garde\n                                   // d'ouverture de fenêtre/session (state.ts) si weight != 'light' hors solo\n  tags: string[]                   // découverte + récurrence — JAMAIS un corpus\n\n  // — verdict de triage (pré-rempli par le moteur, ajustable) —\n  reversibility: Reversibility\n  weight: Weight\n  urgent: boolean\n  scope: {\n    selfOnly: boolean\n    circleIds: Id[]                // plancher : élargir libre, JAMAIS restreindre sous le calcul\n    personIds: Id[]\n  }\n  route: DecisionRoute\n  triageRule: TriageRule           // relégué au dépliable « pourquoi ? », PV, journal — jamais en carte\n  routeOverridden: boolean\n  overrideNote?: string            // OBLIGATOIRE si allègement (asymétrie de dérogation)\n  scopeKeptNote?: string           // affluence atteinte + périmètre maintenu ⇒ note motivée PUBLIQUE obligatoire\n\n  // — spécialisations chaînées (le pliage génératif) —\n  underMandateId?: Id              // décidée SOUS ce mandat → feux de la rampe du mandat\n  createsMandate?: MandateDraft\n  amendsClauseId?: Id\n  protocolId?: Id                  // résolu par le Pacte, ajustable en alourdissant\n  paramSpec?: ParamSpec            // si modalité paramétrique (« Réglage collectif »)\n  parentDecisionId?: Id\n  chainKind?: 'ratification' | 'revision' | 'revocation' | 'element'\n                                   // 'element' : micro-décision d'un dossier découpé (« décision incrémentielle »).\n                                   // Parent d'éléments : transition framing→closed gardée par\n                                   // « tous les enfants element en état terminal » — GESTE du garant\n                                   // (carte au Fil « Le dossier est complet — clore »), jamais automatique ;\n                                   // la cartographie de clôture devient le PV du dossier.\n  decidedHow?: string              // route 'record' : « comment ça s'est décidé », une phrase\n\n  // — temps & fenêtres —\n  status: DecisionStatus\n  windowEndsAt?: ISODate\n  windowSuspendedAt?: ISODate      // objection de frontière → compte à rebours SUSPENDU (visible)\n  decidedAt?: ISODate\n  review?: Review                  // obligatoire si irreversible || structural\n  sunsetAt?: ISODate\n  stewardIds: Id[]                 // garants — RÉALISENT (et cristallisent le paramétrique, clôturent le dossier)\n  measurerIds: Id[]                // mesureurs — CONSTATENT (saisissent Effect.measured) : la paire doctrinale\n\n  // — preuve & visibilité —\n  visibility: 'private' | 'scope' | 'collective'   // anti-flicage : trace maîtrisée hors mandat\n  engraving?: Engraving\n}\n\ninterface Review {\n  dueAt: ISODate\n  verdict?: 'confirmed' | 'revise' | 'revoke'   // UI : « Ça tient / À revoir / À révoquer »\n  note?: string\n  decidedAt?: ISODate\n}\n\ninterface Engraving {\n  sha256: string\n  engravedAt: ISODate\n  proofLevel: 'local'              // v2 : UNIQUEMENT 'local' — « empreinte locale — démo »\n  ipfsCid?: string                 // réservé v3 — jamais affiché tant que non réel\n  chainRef?: string\n}\n\n// ── Inclusion & fenêtres ─────────────────────────────────────\ninterface Concern extends Entity {\n  decisionId: Id\n  personId: Id\n  origin: 'computed' | 'declared'  // UI : « concerné·e en premier lieu » / « en second lieu »\n  reason: string                   // « membre du cercle Forgerons » — affichée au tap\n  declaredNote?: string\n  beforeSnapshot: boolean          // avant liste arrêtée ⇒ vote ; après ⇒ voix consultative\n  priority?: 0 | 1 | 2 | 3         // « pondère tes enjeux » — par élément d'un dossier ;\n                                   // nourrit la cartographie de clôture, jamais le droit de vote\n}\n\ninterface Assent extends Entity {  // « Ça me va » STOCKÉ — l'accord explicite des fenêtres d'objection\n  decisionId: Id\n  personId: Id\n  recordedById?: Id                // mode atelier\n}\n// RÈGLE DES FENÊTRES D'OBJECTION (state.ts) : à échéance sans objection ouverte —\n// easy ⇒ adopted (silence vaut accord) ; costly/irreversible ⇒ adopted SEULEMENT si\n// ≥1 Assent d'un concerné ≠ auteur, sinon PROLONGATION d'un cran (+objectionWindowHours,\n// relance au Fil) — jamais d'adoption par pur silence hors easy.\n\ninterface Objection extends Entity {\n  decisionId: Id\n  personId: Id\n  kind: 'content' | 'boundary'     // boundary SUSPEND la fenêtre — la frontière prime sur le fond\n  argument: string\n  status: 'open' | 'withdrawn' | 'integrated' | 'escalated'\n  resolutionNote?: string\n  recordedById?: Id                // mode atelier : « saisi par X pour Y — atelier du <date> »\n}\n\ninterface Advice extends Entity {\n  decisionId: Id\n  personId: Id\n  position: 'favorable' | 'reserved' | 'unfavorable'\n  note?: string\n  recordedById?: Id                // mode atelier\n}\n\n// ── Le pouvoir ───────────────────────────────────────────────\ninterface Mandate extends Entity {\n  title: string\n  holderId: Id\n  originDecisionId: Id             // le mandat EST né d'une décision — cliquable\n  domain: { circleIds: Id[]; tags: string[] }\n  startsAt: ISODate\n  endsAt: ISODate                  // toujours borné\n  electorCircleId: Id              // corpus d'élection = corpus de révocation\n  nominationMethod: 'ratified-self' | 'election-no-candidate' | 'nuanced-vote' | 'consent' | 'draw' | 'rotation'\n  reports: MandateReport[]\n  status: 'proposed' | 'active' | 'expired' | 'revoked'\n  // AUCUN agrégat/jauge : la fiche affiche des faits comptés (« Exercice du mandat »),\n  // jamais synthétisés ; le flux public = « Feux de la rampe »\n}\ninterface MandateReport { dueAt: ISODate; deliveredAt?: ISODate; content?: string }\ninterface MandateDraft {\n  title: string\n  domainCircleIds: Id[]\n  domainTags: string[]\n  durationDays: number\n  reportEveryDays?: number\n}\n\n// ── Les textes ───────────────────────────────────────────────\ninterface TextDoc extends Entity {\n  slug: string\n  title: string\n  role: 'pact' | 'reference'\n  description: string              // Pacte seedé : « Notre contrat social — sacralisé, jamais immuable »\n  provenance?: Provenance\n}\ninterface Provenance {\n  sources: { title: string; url: string; date?: string; version?: string }[]\n  voteRecord?: {\n    url: string; modeParams: string; period: string\n    result: { for: number; against: number; invalid?: number; wotSize: number; thresholdRequired: number; status: string }\n  }\n  contributors?: string[]\n  notes?: string                   // typos des textes votés : SIGNALÉES, jamais corrigées sans vote\n}\n\ntype InertiaPreset = 'low' | 'standard' | 'high' | 'max'\n// 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)\n\ninterface Clause extends Entity {\n  docId: Id\n  section: string\n  position: number\n  code: string\n  title: string\n  inertia: InertiaPreset\n  currentVersionId?: Id\n  settingKey?: string              // clauses du Pacte : ex. 'triage.smallGroupMax'\n}\n\ninterface ClauseVersion extends Entity {\n  clauseId: Id\n  decisionId: Id                   // TOUTE version naît d'une décision (y compris fondatrice seedée)\n  versionLabel: string\n  content: string\n  settingValue?: Json\n  status: 'current' | 'proposed' | 'superseded' | 'rejected'\n  adoptedAt?: ISODate\n}\n\n// ── Modalités & vote ─────────────────────────────────────────\ntype VoteMethod = 'consent' | 'binary' | 'nuanced' | 'parametric' | 'election'\n// UI : consentement · pour/contre (outil de dernier recours) · nuancé ·\n//      « Réglage collectif » (au curseur) · élection\n\ninterface Protocol extends Entity {\n  name: string\n  method: VoteMethod\n  description: string\n  durationDays: number\n  ballot: 'open' | 'secret'        // décidé par le Pacte — défaut 'open' (feux de la rampe).\n                                   // v2 mono-poste : « secret d'affichage — démo » (décomptes agrégés\n                                   // et commentaires anonymisés seuls) ; crypto réelle avec la synchro (v3)\n  formula: FormulaParams\n  modeParams: string               // DSL DÉRIVÉ affiché : 'D30M50B.1G.2S.1' — jamais édité à la main\n  pactClauseId?: Id                // référencé par le Pacte ⇒ le modifier = amender le Pacte\n}\ninterface FormulaParams {\n  majorityPct: number              // M\n  baseExponent: number             // B (défaut 0.1)\n  gradientExponent: number         // G — l'inertie\n  constantBase: number             // C (défaut 0)\n  smithExponent?: number\n  techcommExponent?: number\n  nuancedMinParticipants?: number\n  nuancedThresholdPct?: number\n  parametricMinParticipants?: number   // quorum du réglage collectif — non atteint ⇒ rejected au geste\n  electionMinParticipants?: number     // quorum de l'élection — non atteint ⇒ rejected\n  tieBreak?: 'runoff' | 'draw'         // départage d'élection DÉCIDÉ D'AVANCE par le Pacte\n                                       // (défaut 'runoff' : session de départage chaînée entre ex æquo ;\n                                       // 'draw' : tirage au sort entre ex æquo — jamais choisi par le moteur)\n}\n\ninterface VoteSession extends Entity {\n  decisionId: Id\n  protocolId: Id\n  corpusPersonIds: Id[]            // SNAPSHOT à l'ouverture — UI : « liste arrêtée le … »\n  corpusSize: number               // W — plus jamais 0 (lettre réservée à l'Atelier)\n  opensAt: ISODate\n  closesAt: ISODate\n  status: 'open' | 'frozen' | 'closed'\n  // 'frozen' : PARAMÉTRIQUE uniquement — à closesAt les votes sont figés, la médiane figée est affichée,\n  // et la session ATTEND le geste humain du garant (relance au Fil s'il tarde).\n  crystallizedById?: Id            // le geste « Cristalliser » : qui, quand — daté et signé\n  crystallizedAt?: ISODate\n  outcome?: 'adopted' | 'rejected' | 'tie'\n  // 'tie' : élection à égalité — l'outil ne départage JAMAIS : session de départage chaînée\n  // (restreinte aux ex æquo) ou tirage au sort SI le protocole l'a prévu (tieBreak).\n  // Consent/nuancé/binaire : open→closed automatique à closesAt (le moteur constate un seuil\n  // sur un contenu formulé par des humains). Paramétrique : open→frozen→closed (geste).\n  // INVARIANT : tallies, histogrammes ET médianes TOUJOURS recalculés depuis Vote[] — jamais dénormalisés.\n}\n\ninterface Vote extends Entity {\n  sessionId: Id\n  voterId: Id\n  value?: 'for' | 'against' | 0 | 1 | 2 | 3 | 4 | 5\n  // nuancé UI : 0 Pas du tout · 1 Plutôt non · 2 Réservé · 3 Plutôt oui · 4 Oui · 5 Tout à fait\n  values?: number[]                // paramétrique — ordre de paramSpec.params HORS derived\n  choicePersonId?: Id              // élection — désignation ; vote déposé sans choicePersonId = BLANC\n                                   // (compte pour la participation, pas pour la désignation)\n  // INVARIANT : EXACTEMENT UN de value / values / choicePersonId selon la méthode (validé par le store) —\n  // sauf blanc d'élection (aucun des trois, méthode 'election' seulement)\n  comment?: string                 // OBLIGATOIRE si négatif (against, 0, 1)\n  supersedesVoteId?: Id            // re-vote audité — PRIVACY : la chaîne n'est JAMAIS affichée\n                                   // publiquement sous le nom d'un votant ; visible du SEUL auteur ;\n                                   // même en ballot 'open', seul le DERNIER vote actif apparaît sous un nom,\n                                   // le décompte agrégé est recalculé (« pardonner les positions »)\n  recordedById?: Id                // mode atelier\n}\n\n// ── Réglages résolus du Pacte (fonction pure — PAS une table settings) ──\ninterface CollectiveSettings {     // resolveSettings(pactClauses, versions)\n  triage: {\n    smallGroupMax: number          // défaut 5\n    collectiveMin: number          // défaut 50\n    consentMax: number             // défaut 7\n    objectionWindowHours: number   // défaut 48\n    adviceWindowHours: number      // défaut 72\n    framingDays: number            // défaut 14 — « s'instruire et formuler des contre-propositions »\n    concernEscalateRatio: number   // défaut 0.5 — atteint ⇒ traitement OBLIGATOIRE (garde state.ts)\n    recurrenceThreshold: number    // défaut 3\n    reviewDelayDays: number        // défaut 90\n    requireEffects: 'none' | 'structural' | 'binding'\n    // clé 'triage.requireEffects' — gouverne la garde matière des sessions COLLECTIVES :\n    // 'binding' = binding ET structural (défaut association/cooperative/commune/free-currency/symmetric) ;\n    // 'structural' = structural seul ; 'none' seedé dans blank et informal.\n    // Sous garde, structural ⇒ ≥1 effet avec cible mesurable (target).\n  }\n  protocolByRange: {\n    consent: Id                    // OBLIGATOIRE — invariant : tout collectif a un protocole Consentement\n                                   // (tout gabarit le seede, l'import le valide)\n    nuanced?: Id\n    large?: Id                     // ex-inertialBinary : le nom ne présume plus la méthode.\n                                   // Gabarits standard → nuancé ; free-currency → binaire inertiel\n    parametric?: Id                // « Réglage collectif »\n    election?: Id\n    clauseByInertia?: Record<InertiaPreset, Id>   // l'héritage Ğ1 vit ici, intact\n  }\n  // REPLI SPÉCIFIÉ (resolveSettings) : toute clé optionnelle non résolue retombe sur consent ;\n  // consent introuvable (bundle corrompu) ⇒ le triage route 'advice' avec bannière\n  // « Aucun protocole — crée-le ou décide sur avis » — JAMAIS un crash.\n}\n\n// ── Moteurs purs (frontend/app/engine/ — implémentation UNIQUE, vitest) ──\n// threshold.ts   : wotThreshold(W,T,{M,B,G,C}) — port exact de threshold.py (ceil) ;\n//                  + smithThreshold, techcommThreshold, nuancedResult (histogramme 6 niveaux exposé) ;\n//                  + electionResult(votes, corpus, formula) → { winnerId } | { outcome:'tie', exAequoIds }\n//                    | { outcome:'rejected' } — pluralité simple des derniers votes actifs, blancs comptés\n//                    en participation, quorum electionMinParticipants, JAMAIS de départage moteur.\n//                  SPEC EXÉCUTABLE : cas Forgeron W=7224 T=120 M50 B.1 G.2 ⇒ 94.\n// parametric.ts  : validateVote(spec, values) — bornes/step/clamp dynamique sum100, sanitize NaN/inf ;\n//                  resolveDerived(spec, values) — sum100 linéaire (100 − Σ autres), étiquette « calculé » ;\n//                  medianByElement(votes) — MÉDIANE BASSE par curseur (pair ⇒ élément central inférieur :\n//                  chaque valeur médiane est une valeur effectivement votée ⇒ step respecté par\n//                  construction — « une position que chacun aurait pu proposer », testé) ;\n//                  crystallize(spec, votes) — médiane basse des parts votées PUIS resolveDerived ;\n//                  derived hors bornes ⇒ clamp à la borne + renormalisation proportionnelle des parts\n//                  non-derived (somme 100 restaurée) — spec testée ;\n//                  computeMyImpact(spec, resources, values, myAttr, corpusAttrs) — 'linear-share' :\n//                  UNIQUEMENT si constraint='sum100' && resources.amount && impactAttrKey ;\n//                  montant(p) = amount × p/100 ; maPart(p) = montant(p) × myAttr / Σ corpusAttrs ;\n//                  par curseur + total, aux trois positions (mienne/médiane/baseline) ;\n//                  myAttr absent ou Σ=0 ⇒ null — JAMAIS un chiffre inventé ;\n//                  detectBimodality(values[]) — plus grand écart entre valeurs triées vs dispersion,\n//                  jamais bloquant. Dégénérescences : 0 vote ⇒ baseline, jamais d'écran vide.\n// triage.ts      : triage(input, ctx, settings) → Verdict (règles ci-dessous)\n// modeParams.ts  : parse/format du DSL\n// settings.ts    : resolveSettings(clauses, versions) → CollectiveSettings (défauts + replis spécifiés)\n// state.ts       : canTransition(decision, to, ctx: { concerns: Concern[], settings: CollectiveSettings,\n//                    session?: VoteSession, children?: Decision[], assents?: Assent[],\n//                    objections?: Objection[] }) — machine à états UNIQUE, gardes :\n//                  windowSuspendedAt (frontière) ; affluence (ratio ⇒ élargir ou scopeKeptNote) ;\n//                  matière (requireEffects) ; ressources (weight != light hors solo) ;\n//                  Assent (fenêtres non-easy) ; dossier (framing→closed si children terminaux, geste) ;\n//                  cristallisation (paramétrique : closed exige crystallizedById).\n// impact.ts      : computeConcerned(scope, circles, mandates) → { personId, reason }[]\n// app/lexicon.ts : source UNIQUE des libellés français + test vitest anti-lexique\n//                  (déléguer, délégation, dette, retard, en souffrance, corpus, snapshot,\n//                  CONTRE, verdict, triage, oligarchie, peuple adulte…).\n//                  Règles de ton : (1) tutoyer la personne dans ses gestes ;\n//                  (2) actes collectifs à l'infinitif (« Adopter notre Pacte ») ;\n//                  (3) sujet des phrases générées = personnes/collectif, JAMAIS la formule.\n\ninterface TriageInput {\n  title: string; tags: string[]\n  scope: Decision['scope']\n  reversibility: Reversibility\n  weight: Weight\n  urgent: boolean\n  amendsClauseId?: Id\n}\ninterface TriageContext {          // assemblé par le store, consommé pur — testable sans I/O\n  myActiveMandates: Mandate[]\n  otherActiveMandates: Mandate[]\n  matchingClauses: Clause[]        // index Q0 « déjà décidé ? » — le MÊME index que Cmd+K\n  similarRecentCount: number       // décisions adoptées partageant ≥2 tags sur 90 j\n  similarRecordedCount: number     // consignations 'record' partageant ≥2 tags — maturation\n  computedConcernedIds: Id[]\n}\ninterface Verdict {\n  route: DecisionRoute\n  rule: TriageRule\n  explanation: string              // UNE phrase française — affichée SEULE, sans code de règle\n  protocolId?: Id\n  windowHours?: number\n  framingDays?: number\n  reviewRequired: boolean\n  engravingSuggested: boolean\n  conservatoryChain?: boolean\n  parametricHint?: boolean         // nombre/%/montant détecté ⇒ « C'est un réglage » mis en avant\n  alternatives: { route: DecisionRoute; label: string; cost: string }[]\n  // toujours présentes : « C'est un réglage — décidez au curseur » (parametric) ;\n  // « Déjà tranché — je le consigne » (record) ; le binaire avec son coût (« deux camps, un perdant »)\n  suggestion?: { kind: 'claim-mandate' | 'create-rule' | 'protocolize'; prefill: Json }\n}\n\n// ── Persistance locale & synchro future ──────────────────────\ninterface Bundle {                 // export/import ET seeds — le MÊME chemin de code\n  schemaVersion: 2\n  exportedAt: ISODate\n  collective: Collective\n  people: Person[]; circles: Circle[]\n  decisions: Decision[]; concerns: Concern[]; objections: Objection[]; advices: Advice[]\n  assents: Assent[]\n  mandates: Mandate[]\n  docs: TextDoc[]; clauses: Clause[]; versions: ClauseVersion[]\n  protocols: Protocol[]; sessions: VoteSession[]; votes: Vote[]\n}\n// data/persistence.ts : IndexedDB (idb-keyval), clé `ld2:<collectiveId>`, débounce 500 ms.\n// importBundle() valide protocolByRange.consent + pose Collective.lineage si bundle étranger.\n// Prêt-synchro : UUIDv7, updatedAt (LWW), archivedAt, Vote/Advice/Objection/Assent append-only.\n// Contrat des stores Pinia inchangé — l'adaptateur FastAPI futur ne change AUCUN écran.\n// NOTES contrat : ballot 'secret' devra devenir cryptographique côté serveur (v3) ;\n// 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.\n\nTRIAGE — 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.\n\nFORMULATION (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.\n\nDÉLIBÉRATION — selon la route :\n- 'solo' selfOnly : draft → adopted immédiat (2 gestes). Trace facultative, visibility 'private' par défaut.\n- 'record' : draft → adopted immédiat, decidedHow posé, trace pure.\n- '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.\n- 'advice' : draft → advice (72 h) ; avis déposés ; l'auteur décide → adopted (avis annexés). Objection formelle → escalade collective/consent.\n- '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).\n  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).\n\nGARDE 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.\n\nADOPTION : 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 »).\n\nRÉ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.\n\nDOSSIER 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.\n\nRÉ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 »).\n\nURGENCE : « 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 ».\n\nTRANSMISSION : 'transmit' → 'transmitted' (terminal pour l'auteur) ; le mandataire reprend ou l'auteur conteste le mandat.\n\nMACHINE À É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).",
      "triage_algorithme": "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.\n\nENTRÉ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.\n\nRÈGLES, DANS L'ORDRE — première qui matche (libellés français FINAUX) :\n- 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. »\n- 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.\n- 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.\n- R0c MANDAT D'UN AUTRE : ⇒ 'transmit' : « Le mandat de Cgeek couvre — transmets-lui. » Alternative : « Conteste ce mandat ».\n- 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).\n- 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.\n- 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.\n- 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.\n- 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).\n\nALTERNATIVES 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.\n\nDÉ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.\n\nMÉ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.",
      "modalites": "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) :\n\n1. 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.\n\n2. 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.\n\n3. 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.\n\n4. É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.\n\n5. 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).\n\nRÉ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[].",
      "perimetres_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é.\n\nDEUX PORTES, UNE LISTE, CHAQUE ENTRÉE SOURCÉE (Concern horodaté) :\n- 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.\n- 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.\n\nOBJECTION 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.\n\nMONTÉ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é.\n\nGRADIENT 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).\n\nPONDÉ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.\n\nANTI-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).\n\nFRACTALITÉ : 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_evaluation": "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.\n\nLA 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.\n\nLE 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 ».\n\nLE 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.\n\nLA 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).\n\nL'É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.\n\nL'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.\n\nSIDEBAR — 4 ENTRÉES, pas une de plus :\n1. Aujourd'hui (/) — le Fil + la capture. À 3 personnes, c'est tout l'outil.\n2. Décisions (/decisions) — le registre + l'Observatoire.\n3. Textes (/textes) — les documents sous vote permanent, Pacte épinglé.\n4. Mandats (/mandats) — les pouvoirs confiés.\n\nDISSOLUTIONS 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).\n\nROUTES : / — 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.\n\nCOUCHES 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).",
      "ecrans": [
        {
          "route": "/creer",
          "nom": "Créer un collectif",
          "role": "Onboarding en 3 écrans — le premier usage EST le tutoriel ; s'ouvre sur le rêve",
          "contenu": "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."
        },
        {
          "route": "/",
          "nom": "Aujourd'hui",
          "role": "L'écran quotidien unique : capture + Fil personnel — la boîte de réception de la démocratie",
          "contenu": "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."
        },
        {
          "route": "/decider",
          "nom": "Le chemin (tunnel)",
          "role": "Une phrase → un chemin exécutable en un tap — 10 s pour le routinier, 3 min pour le stratégique",
          "contenu": "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."
        },
        {
          "route": "/decisions",
          "nom": "Registre des décisions",
          "role": "Toutes les décisions par état — SectionLayout conservé",
          "contenu": "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."
        },
        {
          "route": "/decisions/[id]",
          "nom": "Fiche décision",
          "role": "URL permanente de l'objet pivot — progressive disclosure par état",
          "contenu": "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."
        },
        {
          "route": "/decisions/[id]/vote",
          "nom": "Salle de vote",
          "role": "Le geste démocratique central — instruit, puis prononcé",
          "contenu": "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 »."
        },
        {
          "route": "/decisions/observatoire",
          "nom": "L'Observatoire",
          "role": "Comment nous décidons, dans les faits — le miroir et l'apprentissage",
          "contenu": "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)."
        },
        {
          "route": "/textes",
          "nom": "Textes",
          "role": "La bibliothèque des documents sous vote permanent",
          "contenu": "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."
        },
        {
          "route": "/textes/[slug]",
          "nom": "Document vivant",
          "role": "Clauses versionnées, boucle vote⇒texte fermée",
          "contenu": "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."
        },
        {
          "route": "/textes/formules",
          "nom": "Atelier des formules",
          "role": "La pédagogie du seuil — seule maison des lettres",
          "contenu": "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 »)."
        },
        {
          "route": "/mandats",
          "nom": "Mandats",
          "role": "La carte des pouvoirs confiés : qui peut décider quoi, jusqu'à quand",
          "contenu": "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)."
        },
        {
          "route": "/mandats/[id]",
          "nom": "Fiche mandat",
          "role": "Le pouvoir confié, visible et reprenable",
          "contenu": "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."
        },
        {
          "route": "/mandats/nouveau",
          "nom": "Wizard mandat",
          "role": "Le meilleur flux v1, conservé et branché sur le pivot",
          "contenu": "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."
        },
        {
          "route": "/donnees",
          "nom": "Données locales",
          "role": "Local-first assumé : tes données, ton fichier, ta machine",
          "contenu": "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 <date> » ; 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": [
        {
          "terme": "Le chemin",
          "remplace": "Le Verdict",
          "contexte": "Carte centrale de /decider et titre du tunnel — le type TS Verdict reste en code ; « verdict » et « triage » ne sortent jamais du code"
        },
        {
          "terme": "Concerné·e en premier lieu",
          "remplace": "calculé (glyphe calculator)",
          "contexte": "Popover/panneau Périmètre — pastille pleine ; « la machine t'a désigné » est banni"
        },
        {
          "terme": "Concerné·e en second lieu — s'est déclaré·e",
          "remplace": "déclaré",
          "contexte": "Popover/panneau — la main levée reste ; « Ça me concerne » inchangé"
        },
        {
          "terme": "Concernés",
          "remplace": "Touchés",
          "contexte": "Chip du tunnel /decider"
        },
        {
          "terme": "Périmètre",
          "remplace": "Cercles (panneau) / « qui est convoqué »",
          "contexte": "Panneau de la fiche + frise du chemin ; « Cercle » = groupe durable seulement ; « scope » reste code"
        },
        {
          "terme": "Mandats — les pouvoirs confiés",
          "remplace": "les pouvoirs délégués",
          "contexte": "Sidebar + rôle de /mandats/[id] ; tout dérivé de « déléguer » banni de l'UI (test anti-lexique)"
        },
        {
          "terme": "À toi de décider",
          "remplace": "dette décisionnelle",
          "contexte": "Header du Fil, compteur nu — interdits : dette, retard, en souffrance ; « dette décisionnelle » survit en métrique interne dev"
        },
        {
          "terme": "Exercice du mandat",
          "remplace": "Jauge de confiance",
          "contexte": "Fiche et cartes mandat — faits comptés, jamais synthétisés ; « confiance » banni des agrégats"
        },
        {
          "terme": "Feux de la rampe",
          "remplace": "Observatoire (bloc fiche mandat)",
          "contexte": "Flux public des décisions prises sous un mandat — contestables"
        },
        {
          "terme": "L'Observatoire",
          "remplace": "Mémoire",
          "contexte": "/decisions/observatoire — « comment nous décidons, dans les faits »"
        },
        {
          "terme": "Qui vote : 11 personnes — liste arrêtée le 12/08",
          "remplace": "corpus visible : W, T / snapshot",
          "contexte": "Salle et fiche ; W/T/M/B/G/C vivent uniquement à l'Atelier des formules"
        },
        {
          "terme": "Pas du tout · Plutôt non · Réservé · Plutôt oui · Oui · Tout à fait",
          "remplace": "0=CONTRE … 5=TOUT À FAIT",
          "contexte": "Échelle nuancée — valeurs 0-5 et commentaire obligatoire 0-1 inchangés, résultats Ğ1 intacts"
        },
        {
          "terme": "L'épreuve du réel / « Le réel a-t-il suivi ? »",
          "remplace": "Verdict de réalité",
          "contexte": "Bloc revoyure — fiche et Fil"
        },
        {
          "terme": "Ça tient / À revoir / À révoquer",
          "remplace": "confirmée / réviser / révoquer",
          "contexte": "3 boutons de l'épreuve du réel (Review.verdict inchangé en code)"
        },
        {
          "terme": "C'est urgent / « Décidé en urgence — le collectif ratifie »",
          "remplace": "décision conservatoire",
          "contexte": "Toggle du tunnel + badge ; « conservatoire » survit dans le PV et la doc"
        },
        {
          "terme": "Réglage collectif / décider au curseur",
          "remplace": "—(nouveau : VoteMethod 'parametric')",
          "contexte": "Protocole et mode de la salle — « raisonner curseur / table de mixage »"
        },
        {
          "terme": "Cristalliser",
          "remplace": "—(nouveau : geste du garant)",
          "contexte": "Clôture paramétrique : « Les votes sont figés — cristallise la médiane » ; « l'agrégat éclaire, le geste cristallise » — jamais automatique"
        },
        {
          "terme": "Votes figés — en attente de cristallisation",
          "remplace": "—(nouveau : status 'frozen')",
          "contexte": "Bandeau de la salle/fiche entre closesAt et le geste du garant"
        },
        {
          "terme": "Décision incrémentielle",
          "remplace": "—(nouveau : chainKind 'element')",
          "contexte": "Découpage d'un dossier en micro-décisions — le nom de l'auteur réservé à CE mode (Taïwan)"
        },
        {
          "terme": "Cartographie de clôture",
          "remplace": "—(nouveau)",
          "contexte": "Section auto-générée du dossier découpé ; publiée par le geste « clore » du garant, devient le PV du dossier"
        },
        {
          "terme": "contrainte / calculé",
          "remplace": "—(nouveau)",
          "contexte": "Étiquettes du paramétrique : cadre en lecture seule vs part dérivée — le votant sait ce qu'il contrôle"
        },
        {
          "terme": "Pour moi",
          "remplace": "—(nouveau)",
          "contexte": "Carte d'impact (ma position / médiane / statu quo) — « estimation sur données déclarées », jamais de chiffre inventé"
        },
        {
          "terme": "S'instruire",
          "remplace": "—(nouveau, regroupe l'existant)",
          "contexte": "Bloc de tête salle/fiche : résumé compact toujours visible + dépliables, auto-replié aux visites suivantes"
        },
        {
          "terme": "Ce que ça engage",
          "remplace": "—(nouveau : resources)",
          "contexte": "Ligne suggérée du tunnel + bloc fiche/PV — la décision connexe de ressources ; exigée à l'ouverture, jamais au tunnel"
        },
        {
          "terme": "Déjà tranché — je le consigne",
          "remplace": "—(nouveau : route 'record')",
          "contexte": "Alternative permanente du tunnel — l'observatoire en un geste"
        },
        {
          "terme": "Aujourd'hui : … / Aujourd'hui → Proposé",
          "remplace": "—(nouveau : baselineNote)",
          "contexte": "Statu quo en en-tête de fiche ; marqueur « actuel » sur chaque curseur"
        },
        {
          "terme": "Je décide · Je décide, sous mandat · Je transmets · J'écoute, puis je décide · Nous décidons",
          "remplace": "Solo / Mandat / Transmettre / Avis / Collectif",
          "contexte": "Libellés des routes (lexicon.ts) — le chemin est un geste, pas une catégorie ; formes courtes en pills de filtres"
        },
        {
          "terme": "Ton vote est remplaçable — ton historique n'est visible que de toi",
          "remplace": "re-vote audité — l'historique reste (indéterminé)",
          "contexte": "Salle de vote : la chaîne supersedes n'est jamais publique sous un nom ; seul le dernier vote actif apparaît en ballot open"
        },
        {
          "terme": "Vote blanc",
          "remplace": "—(nouveau : élection)",
          "contexte": "Élection : vote déposé sans désignation — compte pour la participation, pas pour la désignation"
        },
        {
          "terme": "En cas d'égalité, vous départagez — jamais l'outil",
          "remplace": "—(nouveau : outcome 'tie')",
          "contexte": "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"
        },
        {
          "terme": "Il manque un accord explicite",
          "remplace": "—(nouveau : Assent)",
          "contexte": "Fenêtre d'objection non réversible prolongée : ≥1 « Ça me va » requis — le silence ne vaut accord que pour le réversible"
        },
        {
          "terme": "pour/contre — « l'outil de dernier recours des très grands corps »",
          "remplace": "vote binaire (neutre)",
          "contexte": "Description seedée du protocole binaire + Atelier ; libellé Ğ1 : « héritage Toile de Confiance »"
        },
        {
          "terme": "Adopter notre Pacte",
          "remplace": "Adoptez votre Pacte",
          "contexte": "Première décision proposée — actes collectifs à l'infinitif (règle de ton n°2)"
        },
        {
          "terme": "Révoquées — ce qu'on en a appris",
          "remplace": "Cimetière des révoquées",
          "contexte": "Section de l'Observatoire — droit à l'erreur, curiosité du chercheur"
        },
        {
          "terme": "mode atelier — « saisi par X pour Y — atelier du <date> »",
          "remplace": "agir en tant que (pur démo)",
          "contexte": "/donnees — saisie assistée en présence, passerelle hors-écran"
        },
        {
          "terme": "exploration — ne compte pas",
          "remplace": "—(nouveau)",
          "contexte": "Étiquette du sandbox Explorer de la salle paramétrique"
        },
        {
          "terme": "essaimé de …",
          "remplace": "—(nouveau : lineage)",
          "contexte": "Métadonnée d'affichage d'un collectif né d'un bundle d'un autre"
        },
        {
          "terme": "compte à rebours suspendu — frontière contestée",
          "remplace": "(conservé v1 — il est juste)",
          "contexte": "Pastille pause de l'objection de frontière"
        }
      ],
      "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.\n\nMAPPING Ğ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).\n\nDEUXIÈ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.\n\nGABARITS (/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.",
      "design_directives": "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.\n\nPÉ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).\n\nCYCLE 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.\n\nJAUGE 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.\n\nNUANCÉ : 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.\n\nCURSEURS (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.\n\nMICRO-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 ».\n\nGRAVURE 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.\n\nPRINT 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.\n\nMOODS 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_implementation": [
        "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. 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. 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. 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. 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. 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. 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. 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. 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. 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. 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"
      ]
    },
    "verdicts": [
      {
        "verdict": "reserves",
        "must_fix": [
          "Cristallisation paramétrique : en faire un geste humain daté — à closesAt les votes sont figés mais c'est le garant (stewardIds) qui cristallise la médiane en position adoptée (relance au Fil s'il tarde), et la cristallisation automatique est au minimum bloquée quand detectBimodality est positif. Le corpus tranche explicitement (tension « Agrégat mathématique vs jugement construit ») : « l'agrégat éclaire une délibération, la cristallisation reste un geste humain distinct et daté » ; chez SejeteralO la publication est un geste distinct de l'agrégation vivante. L'automatisme actuel (« Clôture à closesAt ou geste du garant ») est le seul endroit du blueprint où un calcul produit un contenu adopté sans geste humain — exactement la « décision algorithmique », repoussoir absolu de la doctrine.",
          "Historique des re-votes : spécifier que la chaîne supersedesVoteId n'est JAMAIS affichée publiquement sous le nom d'un votant — visible du seul auteur (et du décompte agrégé recalculé), même en ballot 'open'. Le corpus tranche (tension « Mémoire vive vs droit à l'erreur ») : « archiver les mandats, pardonner les positions ; l'historique des votes révisés n'est jamais opposable à une personne » — or « Mon vote remplaçable (historique audité) » et « re-vote audité — l'historique reste » laissent la visibilité publique indéterminée, ce qui ouvre un contrôle des personnes entre elles (le glas doctrinal)."
        ],
        "remarques": [
          "Binaire réellement remis à sa place : protocolByRange.large → nuancé dans tous les gabarits standard, binaire inertiel confiné à free-currency et clauseByInertia (R3), coût affiché « deux camps, un perdant », description seedée « outil de dernier recours », l'Atelier comme seule école des lettres. L'héritage Ğ1 (33+59 clauses, D30M50B.1G.2) survit à sa place — conforme à la contrainte du commanditaire ET à « remis à sa place dans la boîte à outils ».",
          "Personnes jamais notées : vérifié partout — jauge de confiance supprimée (l'oxymore confiance/contrôle correctement identifié), « Exercice du mandat » en faits comptés jamais synthétisés (le contrôle porte sur le pouvoir, pas la personne), invariant 3 du modèle, Person.attributes jamais affichés ni agrégés, tirage/rotation disponibles. Conforme au cloisonnement exigé par le corpus.",
          "Instruction : le point le plus fort du blueprint — bloc « S'instruire » non repliable avant les boutons, garde d'ouverture ≥1 effet recherché (state.ts), symptômes/causes, un même champ Effect pour instruction ET épreuve du réel : « il n'est pas consulté, il est instruit » et le mandat fondateur « acquisition collective des expériences » sont structurels, la boucle est fermée par construction.",
          "Observatoire avant protocole : gabarit blank en tête de /creer, route 'record' à 2 gestes, maturation ≥3 consignations ⇒ protocolisation pré-remplie, renommage /decisions/observatoire — le flux consigner→observer→protocoliser est le chemin ordinaire, pas un discours. L'inversion de noms v1 (Mémoire) est corrigée dans le sens doctrinal exact.",
          "Médiane/faisceau/impact : réels, pas décoratifs — engine/parametric.ts spécifié avec tests (medianByElement dont le résultat est une position valide, resolveDerived sum100, dégénérescences 0-vote), agrégateur NOMMÉ et expliqué en langage courant (le défaut SejeteralO explicitement corrigé), faisceau strip-plot anonyme + médiane épaisse + baseline, « Pour moi » borné aux données déclarées (« jamais un chiffre inventé ») — honnêteté locale-first exemplaire.",
          "À préciser (une phrase suffit) : le cadre paramétrique lui-même (paramSpec — bornes, contrainte, baseline, impactAttrKey) se pose et se conteste en framing comme toute formulation. Tension corpus « Ancrage vs influence » : « le cadre lui-même (qui publie la référence, qui fixe les contraintes) doit être décidable par la couche méta » — structurellement couvert par le framing, mais jamais écrit.",
          "Incohérence d'implémentation à anticiper : le test anti-lexique bannit « CONTRE » alors que la salle binaire héritée affiche « pour/contre » — prévoir l'exemption contextuelle du protocole binaire dans le test, sinon il sera contourné dès le sprint 6.",
          "Le « degré d'inefficacité collectivement accepté » (mécanisme nommé du corpus) n'apparaît pas comme tel : il est de fait réglé par les clauses de fenêtres/framingDays du Pacte — une clause commentée portant ce nom serait une fidélité lexicale à coût nul.",
          "Grand corpus structural sans nombre détecté : le chemin par défaut reste le nuancé simple là où la doctrine appellerait le découpage incrémentiel (« à grand volume, cela devient la décision incrémentielle ») — défendable car l'outil ne prescrit jamais et le bouton « Découper en micro-décisions » existe en framing, mais à surveiller à l'usage : envisager une suggestion non bloquante de découpage quand structural ET corpus > collectiveMin.",
          "« Feux de la rampe » est restreint au flux des décisions sous mandat : c'est l'usage le plus exact (actes des mandatés) mais plus étroit que le concept doctrinal de transparence radicale générale — acceptable, le reste de la transparence existant sous d'autres noms (registre, Observatoire, isTransparent)."
        ]
      },
      {
        "verdict": "reserves",
        "must_fix": [
          "Restreindre la garde d'ouverture « ≥1 effet recherché » aux sessions collectives de poids binding/structural, ou la gouverner par une clause de Pacte (comme requireEffectsForStructural) désactivée dans les gabarits blank/informal : telle qu'écrite (« exigé à l'OUVERTURE de TOUTE session collective », state.ts draft→voting), elle impose un champ de matière rituel au consentement léger du trio (« on part le 12 » → « effet recherché : avoir une date »), en contradiction frontale avec le manifeste « jamais plus lourd que l'enjeu » et avec la carte blank « consentement simple ».",
          "Préciser que la ligne « Ce que ça engage » (resources) est suggérée-dépliée dans le tunnel mais exigée SEULEMENT à la garde d'ouverture de fenêtre/session dans state.ts (même mécanique que brief.effects, dont le blueprint dit explicitement « la matière s'écrit en framing, pas dans le tunnel ») : le modèle dit « exigé si weight != 'light' hors solo » sans localiser la garde, et un champ texte obligatoire au tunnel qui ne change pas le chemin viole la métrique produit énoncée deux paragraphes plus loin (« le tunnel n'affiche JAMAIS un champ qui ne change pas le chemin ») — c'est le cas nominal de la trésorière (binding hors solo) qui prend la lourdeur.",
          "Condenser le bloc « S'instruire » de la salle de vote : résumé compact toujours visible avant les boutons (titre, effets, ce que ça engage) avec versions/diff, avis/objections et provenance en dépliables internes, et replié automatiquement aux visites suivantes de la même personne — « voter sur un titre nu impossible » est préservé, mais « NON repliable avant les boutons » tel quel impose à la citoyenne de 40 000 un mur de scroll mobile à CHAQUE re-vote d'un vote pourtant révisable, à rebours de la leçon SejeteralO listée au corpus (« agir d'abord, comprendre ensuite »)."
        ],
        "remarques": [
          "Le chemin nominal tient réellement : solo = phrase + Entrée + bouton (2 gestes), consignation 'record' = 2 gestes aussi, compteur nu, alternatives à coût affiché, sections vides masquées — la capture d'une décision banale est effectivement plus simple que de ne pas utiliser l'outil (et Q0/Cmd+K rend la trace retrouvable). Les trois must_fix sont les trois seuls endroits où ce contrat fuit.",
          "baselineNote « suggéré dans le tunnel » pour advice/collective viole doucement la même règle (champ qui ne change pas le chemin) : le déplacer en framing/fiche ou l'aligner sur le traitement retenu pour resources.",
          "Trou de spec vivabilité : à échéance d'une fenêtre d'objection sur reversibility 'costly' sans AUCUNE réponse (silence ≠ accord), le blueprint ne dit pas ce qui advient — la décision ne doit pas pourrir sans issue ; spécifier relance, prolongation ou escalade automatique (la v1 disait « au moins un Ça me va par cercle touché », le v2 a perdu la suite).",
          "Gabarit blank : « aucun protocole installé » mais routes annoncées incluant « consentement simple » — seeder un protocole consentement minimal ou reformuler la carte, sinon la première montée en collectif casse.",
          "Quorum paramétrique non atteint ⇒ 'rejected' sec : dans un collectif de 12, offrir « prolonger la fenêtre » comme alternative au rejet automatique (décidable via le protocole du Pacte).",
          "Onboarding mono-poste : « Adopter notre Pacte » (collective/consentement) exige de fait le mode atelier dès la première session — le prévoir explicitement dans le flux /creer (consentement guidé en mode atelier, ou consignation du Pacte fondateur) pour tenir la promesse < 10 min avec un non-théoricien.",
          "Garde d'affluence à très petit effectif : 2 concernés calculés + 1 main levée (ratio 0.5) bloque la clôture — vivable car élargir = 1 tap, mais s'assurer que le traitement est offert au garant/steward et pas au seul auteur (absence = blocage).",
          "Ampleur du delta (24 changements, 11 chantiers) pour « une seule refonte livrable » : la vivabilité du projet repose sur l'isolation déjà prévue des modules paramétrique et incrémentiel (étapes 6 et 10 après le socle) — la maintenir strictement, et accepter de dégrader Explorer/bimodalité/Pour-moi en v2.1 plutôt que d'entamer le socle des 2 gestes.",
          "Le mode 'secret d'affichage — démo' est honnêtement étiqueté et à coût quasi nul : conforme Ockham, rien à corriger, mais veiller à ce qu'il n'apparaisse jamais comme choix par défaut dans les gabarits (défaut 'open' bien posé)."
        ]
      },
      {
        "verdict": "reserves",
        "must_fix": [
          "Élection non codable : Vote n'a aucun champ pour désigner une personne (value 'for'|'against'|0-5, values number[]) alors que VoteMethod 'election', la salle « ÉLECTION (désignation) » et le protocole seedé « Élection sans candidat » sont en scope v2 — ajouter Vote.choicePersonId?: Id (exactement un de value/values/choicePersonId selon la méthode) et spécifier la règle de clôture (pluralité, égalités, abstention).",
          "Contrainte sum100 dégénérée non spécifiée : définir resolveDerived quand 100 − Σ autres sort des bornes du paramètre 'derived' (au vote : validateVote rejette ou la géométrie des curseurs l'empêche ; à la cristallisation : la médiane des parts ne conserve pas la somme → définir clamp + renormalisation ou médiane sous contrainte), et imposer EXACTEMENT une part 'derived' quand constraint='sum100' (avec zéro derived, l'agrégat viole la contrainte sans variable d'absorption).",
          "Convention de médiane non fixée : avec un nombre pair de votes, la moyenne des deux valeurs centrales peut violer ParamDef.step, ce qui casse l'invariant affiché « la médiane est une position que chacun aurait pu proposer » — spécifier dans medianByElement la médiane basse (ou le snap au step) et l'écrire dans les tests vitest.",
          "computeMyImpact 'linear-share' sans formule : définir précisément le calcul (quels params concernés, rôle de Resources.amount comme multiplicande, rôle de Person.attributes[impactAttrKey], résultat par curseur ou global) — l'exemple seedé « budget d'ateliers × 'heures/mois' » n'est pas calculable en l'état.",
          "canTransition(decision, to) n'a pas ses entrées : la garde d'affluence exige les Concern[] (|déclarés| vs |calculés|) et la garde matière exige CollectiveSettings (requireEffectsForStructural), absents de la signature — l'étendre en canTransition(decision, to, ctx: { concerns, settings, session? }).",
          "Contradiction silence-vaut-accord : pour la fenêtre d'objection non-'easy', « silence vaut accord UNIQUEMENT si easy » contredit « à échéance sans objection ouverte → adopted » deux phrases plus loin — définir le comportement à échéance sans accord explicite (ex. exiger ≥1 « Ça me va » et nommer l'entité qui le stocke : Vote 'for' ? Advice ? nouveau champ ?).",
          "Clôture du dossier découpé impossible : le parent d'une chaîne 'element' reste en framing dont la seule sortie est framing→voting — définir sa transition terminale (ex. framing→closed quand tous les éléments sont dans un état terminal, la cartographie de clôture devenant le PV du dossier).",
          "Gabarit 'blank' incompatible avec CollectiveSettings : « aucun protocole installé » mais protocolByRange type des Id non-optionnels (consent/nuanced/large/parametric/election) et la route consentement est annoncée — seeder au minimum le protocole Consentement dans blank et spécifier le fallback de triage/resolveSettings quand une clé de protocolByRange est non résolue (proposer consent ou bloquer avec suggestion de créer le protocole, jamais un crash)."
        ],
        "remarques": [
          "Vérifié positivement : cas Forgeron W=7224 T=120 ⇒ 94 exact par la formule ; seeds Ğ1 sans perte (33+59 clauses, voteRecord 97/23/19/7224 en Provenance verbatim, clauseByInertia intact via R3, binaire inertiel conservé pour free-currency, 11 personnes/5 smiths/3 mandats) ; le renommage inertialBinary→large est purement référentiel, zéro migration de données.",
          "Modalité consentement hors invariant : « tallies toujours recalculés depuis Vote[] » ne couvre pas le consentement dont la clôture dépend des Objection — préciser le stockage du « Ça me va » (Vote{value:'for'} recommandé) pour que le moteur unique de clôture ait des entrées homogènes.",
          "detectBimodality : la constante de déclenchement (ratio plus grand écart / dispersion) n'est pas fixée — la poser dans la spec vitest, sinon la bannière est non testable.",
          "Vote.values est positionnel sur paramSpec.params : geler paramSpec à l'entrée en 'voting' (ou clé les valeurs par ParamDef.key) pour éviter la corruption si le spec est édité en framing après premiers votes exploratoires.",
          "Test anti-lexique « CONTRE » : la salle binaire héritée affiche « pour/contre » — scoper la règle (casse stricte CONTRE majuscule, ou exclure les libellés du protocole binaire) sinon le test est rouge par construction.",
          "États non spécifiés : l'état cible de sunsetAt (closed ?) et le prédicat « acte one-shot → closed » (aucun champ ne distingue l'acte one-shot — choix manuel à l'épreuve du réel ?) restent à trancher.",
          "Suspension de frontière : préciser si windowEndsAt est décalé de la durée suspendue à la levée de windowSuspendedAt (sinon une suspension longue consomme la fenêtre).",
          "Nomination 'draw' et 'rotation' : le mécanisme d'exécution (source d'aléa, ordre de rotation, qui déclenche) n'est pas spécifié alors que le wizard les propose.",
          "DSL modeParams : la grammaire affichée (D30M50B.1G.2S.1) n'a pas de lettre pour parametricMinParticipants ni nuancedThresholdPct — étendre le format ou documenter que ces params vivent hors DSL.",
          "UX de la garde matière : pour une décision collective légère en consentement (pas de framing), l'endroit où saisir le ≥1 effet recherché exigé à l'ouverture n'est décrit nulle part — prévoir un prompt inline à la validation du chemin.",
          "Budget 400 lignes : la salle de vote cumule 5 modalités + secret d'affichage + print A4 + Explorer — imposer dès le plan un composant par modalité dans components/votes/ sinon le budget est structurellement intenable.",
          "Test de non-perte seeds : la formulation mélange voteRecord.modeParams (champ frère de result) et les champs de result — écrire l'assertion sur la structure exacte de Provenance pour éviter un test qui passe sur une structure fausse."
        ]
      }
    ]
  },
  "workflowProgress": [
    {
      "type": "workflow_phase",
      "index": 1,
      "title": "Confrontation"
    },
    {
      "type": "workflow_phase",
      "index": 2,
      "title": "Synthèse finale"
    },
    {
      "type": "workflow_phase",
      "index": 3,
      "title": "Vérification"
    },
    {
      "type": "workflow_agent",
      "index": 1,
      "label": "critique:fidelite",
      "phaseIndex": 1,
      "phaseTitle": "Confrontation",
      "agentId": "a19d69446c7f5120d",
      "model": "claude-fable-5",
      "state": "done",
      "startedAt": 1786415645101,
      "lastProgressAt": 1786415645101,
      "cached": true,
      "resultPreview": "{\"constats\":[{\"probleme\":\"R5 fait du « vote binaire à formule inertielle » la modalité PAR DÉFAUT de tout corpus > 50 (triage_algorithme R5, CollectiveSettings.protocolByRange.inertialBinary), alors que la doctrine proscrit le clivage binaire comme format par défaut (« Le clivage binaire est un fléau contre la réflexion, un ennemi fatal : il la tue » ; « proscrire le binaire oui/non… le numérique …",
      "promptPreview": "CONTEXTE : libreDecision v2, refonte de zéro. Intention de Yvv : que n'importe quel collectif, de 3 personnes à une population entière, aille le plus loin possible dans l'auto-décision — « la capacité d'une démocratie qui n'a jamais existé ». Contraintes : Nuxt 4 SPA local-first (IndexedDB, export/import), UI française, design borderless/moods, une seule refonte livrable, les contextes Ğ1 existant…"
    },
    {
      "type": "workflow_agent",
      "index": 2,
      "label": "critique:mecanismes",
      "phaseIndex": 1,
      "phaseTitle": "Confrontation",
      "agentId": "a2e6b8c7b3f37e1bd",
      "model": "claude-fable-5",
      "state": "done",
      "startedAt": 1786415645101,
      "lastProgressAt": 1786415645101,
      "cached": true,
      "resultPreview": "{\"constats\":[{\"probleme\":\"Le modèle ne connaît que 4 VoteMethod (consent/binary/nuanced/election) : aucune décision à paramètres continus, alors que la doctrine en fait le format central — « raisonner curseur / table de mixage » (MNP p.68, p.159-161), mécanisme corpus « Décision paramétrique continue avec viabilité auto-calculée », leçon SejeteralO « voter = régler une forme, pas choisir un camp »…",
      "promptPreview": "CONTEXTE : libreDecision v2, refonte de zéro. Intention de Yvv : que n'importe quel collectif, de 3 personnes à une population entière, aille le plus loin possible dans l'auto-décision — « la capacité d'une démocratie qui n'a jamais existé ». Contraintes : Nuxt 4 SPA local-first (IndexedDB, export/import), UI française, design borderless/moods, une seule refonte livrable, les contextes Ğ1 existant…"
    },
    {
      "type": "workflow_agent",
      "index": 3,
      "label": "critique:vocabulaire",
      "phaseIndex": 1,
      "phaseTitle": "Confrontation",
      "agentId": "a18cd8ad29fa87cf1",
      "model": "claude-fable-5",
      "state": "done",
      "startedAt": 1786415645101,
      "lastProgressAt": 1786415645101,
      "cached": true,
      "resultPreview": "{\"constats\":[{\"probleme\":\"La navigation dit « Mandats (/mandats) — les pouvoirs délégués » et la fiche mandat « Le pouvoir délégué, visible et reprenable ». C'est la contradiction doctrinale la plus frontale possible : « On procède par délégation de pouvoir, mais on ne délègue pas, on abandonne » ; « Le peuple adulte ne délègue plus, il mandate » (Mon nom est personne, métaphore du peuple adulte ;…",
      "promptPreview": "CONTEXTE : libreDecision v2, refonte de zéro. Intention de Yvv : que n'importe quel collectif, de 3 personnes à une population entière, aille le plus loin possible dans l'auto-décision — « la capacité d'une démocratie qui n'a jamais existé ». Contraintes : Nuxt 4 SPA local-first (IndexedDB, export/import), UI française, design borderless/moods, une seule refonte livrable, les contextes Ğ1 existant…"
    },
    {
      "type": "workflow_agent",
      "index": 4,
      "label": "critique:echelle",
      "phaseIndex": 1,
      "phaseTitle": "Confrontation",
      "agentId": "af88662473ae950a8",
      "model": "claude-fable-5",
      "state": "done",
      "startedAt": 1786415645101,
      "lastProgressAt": 1786415645101,
      "cached": true,
      "resultPreview": "{\"constats\":[{\"probleme\":\"La décision connexe d'allocation de ressources est totalement absente du modèle. Doctrine : « chaque décision implique une allocation de ressources, donc une décision connexe incontournable » (MNP p.89, p.269 ; mécanisme « Décision → ressources liées » du corpus ; « pas de démocratie sans son économie »). La Decision v2 a des stewardIds mais aucune trace de ce qu'elle eng…",
      "promptPreview": "CONTEXTE : libreDecision v2, refonte de zéro. Intention de Yvv : que n'importe quel collectif, de 3 personnes à une population entière, aille le plus loin possible dans l'auto-décision — « la capacité d'une démocratie qui n'a jamais existé ». Contraintes : Nuxt 4 SPA local-first (IndexedDB, export/import), UI française, design borderless/moods, une seule refonte livrable, les contextes Ğ1 existant…"
    },
    {
      "type": "workflow_agent",
      "index": 5,
      "label": "architecte:final",
      "phaseIndex": 2,
      "phaseTitle": "Synthèse finale",
      "agentId": "a562685026aef906c",
      "model": "claude-fable-5",
      "state": "done",
      "startedAt": 1786415645102,
      "lastProgressAt": 1786415645102,
      "cached": true,
      "resultPreview": "{\"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 consu…",
      "promptPreview": "CONTEXTE : libreDecision v2, refonte de zéro. Intention de Yvv : que n'importe quel collectif, de 3 personnes à une population entière, aille le plus loin possible dans l'auto-décision — « la capacité d'une démocratie qui n'a jamais existé ». Contraintes : Nuxt 4 SPA local-first (IndexedDB, export/import), UI française, design borderless/moods, une seule refonte livrable, les contextes Ğ1 existant…"
    },
    {
      "type": "workflow_agent",
      "index": 6,
      "label": "verif:1",
      "phaseIndex": 3,
      "phaseTitle": "Vérification",
      "agentId": "ae6356968d165be73",
      "model": "claude-fable-5",
      "state": "done",
      "startedAt": 1786415645134,
      "lastProgressAt": 1786415645134,
      "cached": true,
      "resultPreview": "{\"verdict\":\"reserves\",\"must_fix\":[\"Cristallisation paramétrique : en faire un geste humain daté — à closesAt les votes sont figés mais c'est le garant (stewardIds) qui cristallise la médiane en position adoptée (relance au Fil s'il tarde), et la cristallisation automatique est au minimum bloquée quand detectBimodality est positif. Le corpus tranche explicitement (tension « Agrégat mathématique vs …",
      "promptPreview": "CONTEXTE : libreDecision v2, refonte de zéro. Intention de Yvv : que n'importe quel collectif, de 3 personnes à une population entière, aille le plus loin possible dans l'auto-décision — « la capacité d'une démocratie qui n'a jamais existé ». Contraintes : Nuxt 4 SPA local-first (IndexedDB, export/import), UI française, design borderless/moods, une seule refonte livrable, les contextes Ğ1 existant…"
    },
    {
      "type": "workflow_agent",
      "index": 7,
      "label": "verif:2",
      "phaseIndex": 3,
      "phaseTitle": "Vérification",
      "agentId": "a6ade8d5af85bb487",
      "model": "claude-fable-5",
      "state": "done",
      "startedAt": 1786415645135,
      "lastProgressAt": 1786415645135,
      "cached": true,
      "resultPreview": "{\"verdict\":\"reserves\",\"must_fix\":[\"Restreindre la garde d'ouverture « ≥1 effet recherché » aux sessions collectives de poids binding/structural, ou la gouverner par une clause de Pacte (comme requireEffectsForStructural) désactivée dans les gabarits blank/informal : telle qu'écrite (« exigé à l'OUVERTURE de TOUTE session collective », state.ts draft→voting), elle impose un champ de matière rituel …",
      "promptPreview": "CONTEXTE : libreDecision v2, refonte de zéro. Intention de Yvv : que n'importe quel collectif, de 3 personnes à une population entière, aille le plus loin possible dans l'auto-décision — « la capacité d'une démocratie qui n'a jamais existé ». Contraintes : Nuxt 4 SPA local-first (IndexedDB, export/import), UI française, design borderless/moods, une seule refonte livrable, les contextes Ğ1 existant…"
    },
    {
      "type": "workflow_agent",
      "index": 8,
      "label": "verif:3",
      "phaseIndex": 3,
      "phaseTitle": "Vérification",
      "agentId": "a77c9bbc9a86d7c09",
      "model": "claude-fable-5",
      "state": "done",
      "startedAt": 1786415645161,
      "queuedAt": 1786415645136,
      "attempt": 1,
      "lastToolName": "StructuredOutput",
      "lastToolSummary": "reserves",
      "promptPreview": "CONTEXTE : libreDecision v2, refonte de zéro. Intention de Yvv : que n'importe quel collectif, de 3 personnes à une population entière, aille le plus loin possible dans l'auto-décision — « la capacité d'une démocratie qui n'a jamais existé ». Contraintes : Nuxt 4 SPA local-first (IndexedDB, export/import), UI française, design borderless/moods, une seule refonte livrable, les contextes Ğ1 existant…",
      "lastProgressAt": 1786416127824,
      "tokens": 182790,
      "toolCalls": 10,
      "durationMs": 482662,
      "resultPreview": "{\"verdict\":\"reserves\",\"must_fix\":[\"Élection non codable : Vote n'a aucun champ pour désigner une personne (value 'for'|'against'|0-5, values number[]) alors que VoteMethod 'election', la salle « ÉLECTION (désignation) » et le protocole seedé « Élection sans candidat » sont en scope v2 — ajouter Vote.choicePersonId?: Id (exactement un de value/values/choicePersonId selon la méthode) et spécifier la…"
    },
    {
      "type": "workflow_agent",
      "index": 9,
      "label": "architecte:final",
      "phaseIndex": 2,
      "phaseTitle": "Synthèse finale",
      "agentId": "a064f0d5e30b0bae0",
      "model": "claude-fable-5",
      "state": "done",
      "startedAt": 1786416127851,
      "queuedAt": 1786416127827,
      "attempt": 1,
      "lastToolName": "StructuredOutput",
      "lastToolSummary": "Personne n'a jamais vécu en démocratie — alors nous la rêvo…",
      "promptPreview": "CONTEXTE : libreDecision v2, refonte de zéro. Intention de Yvv : que n'importe quel collectif, de 3 personnes à une population entière, aille le plus loin possible dans l'auto-décision — « la capacité d'une démocratie qui n'a jamais existé ». Contraintes : Nuxt 4 SPA local-first (IndexedDB, export/import), UI française, design borderless/moods, une seule refonte livrable, les contextes Ğ1 existant…",
      "lastProgressAt": 1786419283153,
      "tokens": 212204,
      "toolCalls": 9,
      "durationMs": 3155302,
      "resultPreview": "{\"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 consu…"
    }
  ],
  "totalTokens": 394994,
  "totalToolCalls": 19
}