TANGEUL — Rules Written in Markdown, Audited by Humans Image : générée par IA

toulmin calcule des contrats. Les règles sont des fonctions Go, les exceptions sont déclarées comme un graphe de réfutations, et un h-Categoriser transforme le graphe en verdict. Le problème, c’est que la personne qui a réellement besoin d’auditer le contrat ne sait généralement pas lire le Go.

Un expert-comptable auditant une politique de prêt. Un dirigeant de petite entreprise vérifiant une règle de contrôle d’accès. Un employé de banque examinant la logique de compensation d’un virement. Aucun d’eux ne peut regarder func(ctx Context, specs Specs) (bool, any) et dire « oui, c’est correct ». Aussi solides que soient les mathématiques du moteur, si le lecteur ne sait pas lire le code, l’audit n’est qu’un simulacre.

L’IA l’écrit, un humain le lit

TANGL (Toulmin Amgoud Nute Graph Language) comble cet écart. Vous écrivez des phrases markdown, et ces phrases sont le code exécutable.

## tangl:Cases
- in case of `can access`
  - `user` is required
  - `authenticate` is a general rule
  - `block ip` is a counter rule using `policy`.`IsIPBlocked` with `blocklist`
  - don't `authenticate` when `block ip`
  - do `policy`.`Allow` when `authenticate`

Ces cinq lignes constituent le graphe toulmin tout entier — Rule, Counter, Attacks, et l’arête d’exécution. Il n’y a pas d’étape de compilation séparée à laquelle l’auteur doive penser : la chaîne d’outils tangl analyse ce markdown directement en *ast.Document, et validate/effects/gen s’exécutent dessus sans changement. L’auteur est une IA, le vérificateur est une personne — cette asymétrie est tout l’enjeu. L’IA n’a qu’à suivre une seule grammaire canonique stricte ; l’humain n’a qu’à lire une phrase dans sa propre langue.

Une sémantique, plusieurs surfaces

La sémantique de TANGL est définie une seule fois, dans la grammaire anglaise : dualité Evaluate/Run, once (idempotence de tick), undo (compensation), timing de cascade, ordre d’exécution déterministe. Aucune édition locale — le coréen, ou celle qui viendra ensuite — ne redéfinit rien de tout cela. Elle échange seulement le mot-clé et la table d’ordre des mots posée au-dessus du même AST. Une phrase coréenne se mappe 1:1 sur une phrase anglaise, et les deux s’analysent en un nœud d’AST identique.

Ce n’est pas une couche de traduction ajoutée par commodité — c’est porteur. Les véritables lecteurs de TANGL en Corée sont des auditeurs non-développeurs : 소상공인, 세무사. Des mots-clés anglais comme don't X when Y ou is a general rule ne permettent pas à un non-développeur de confirmer « oui, ceci se lit correctement ». Si le lecteur est coréen, la surface doit être coréenne pour que l’audit fonctionne réellement — et l’inverse vaut symétriquement pour les lecteurs anglophones.

La construction de l’édition coréenne a fait apparaître quelque chose qui n’était pas évident à partir de la seule grammaire anglaise : l’ordre SOV du coréen n’est pas un fardeau de traduction, c’est une meilleure adéquation pour les règles conditionnelles. `Y`면 `X` 실행한다 (à peu près, « quand Y, faire X ») se lit plus naturellement que do X when Y en coréen — condition d’abord, prédicat en dernier est tout simplement la manière dont la langue est structurée dès le départ. La politique des particules coréennes pousse cela plus loin : les particules (은/는/이/가/을/를 …) sont des jetons optionnels que le lexeur écarte, mais la forme canonique écrite par l’IA les inclut toujours quand même — pour le lecteur humain, pas pour l’analyseur. Puisque l’IA est le seul auteur, l’analyseur n’a jamais à accepter un ordre des mots libre ni des variations parlées ; il n’a qu’à analyser une seule forme canonique. C’est cette asymétrie qui rend une surface en langue naturelle non triviale traitable, tout simplement.

Sept sections

Subject → See → Definitions → Rules → Cases → Provides → Internal
SectionRôleObligatoire
Subjectdéclare de quoi parle le documentobligatoire
Seeréférence des symboles de paquets externesfacultatif
Definitionstermes et structsfacultatif
Rulesprédicats de condition en lignefacultatif
Casesjugement + exécution (le graphe lui-même)obligatoire
Providespoints de terminaisonfacultatif
Internaltravail interne piloté par tick/événementfacultatif

Chaque construction n’est valide que dans sa propre section — la même discipline de portée que toute édition locale hérite sans changement. Les instructions se lisent comme des phrases complètes qui nomment leur propre nature : is a general rule, don't ... when, do ... once when, undo ... when, run ... when.

Exemple : un robot à café

Voici comment la sémantique d’exécution de TANGL — la dualité Evaluate/Run, once, la cascade — se présente sous forme de phrases markdown ordinaires.

## tangl:Cases
- in case of `can place cup`
  - `order received` is a general rule using `sensor`.`isOrdered`
  - `no cup` is a counter rule using `sensor`.`noCupAvailable`
  - don't `order received` when `no cup`
  - do `arm`.`placeCup` once when `order received`
  - run `can pour water` when `order received`

- in case of `can pour water`
  - `cup placed` is a general rule using `sensor`.`cupIsPlaced`
  - do `arm`.`pourWater` once when `cup placed`
  - run `can brew espresso` when `cup placed`

## tangl:Provides
- provides `make coffee`
  - run `can place cup`

## tangl:Internal
- every 1s until `can serve coffee`
  - run `can place cup`

Un auditeur lit ceci ainsi : « Une fois que la tasse peut être posée — si la commande a été reçue, poser la tasse une seule fois et passer au versement de l’eau. S’il n’y a pas de tasse, la commande est nulle. Pour faire un café, partir de la pose de la tasse, et réessayer chaque seconde jusqu’à ce qu’il puisse être servi. »

Sans once, le bras poserait une nouvelle tasse à chaque tick tant que la commande reste active — ce mot est toute la raison pour laquelle une mise à jour lente du capteur ne se transforme pas en une reprise physiquement dangereuse. Un auditeur confirme la sûreté de la reprise à partir de cette seule phrase, sans jamais lire une clause de garde Go.

Exemple : compensation — le monde reste entier même en cas d’échec

undo n’est pas la même chose qu’un rejet. Un rejet est une branche normale du graphe ; undo est la compensation d’une exécution qui est morte à mi-chemin.

- do `bank`.`withdraw` once when `balance sufficient`
- undo `bank`.`refund` when `balance sufficient`
- run `can deposit` when `balance sufficient`

« Si le solde est suffisant, retirer une seule fois ; si quoi que ce soit échoue en aval, annuler via remboursement ; et continuer vers le dépôt. » En cas d’échec, l’ordre est déterministe :

1. withdraw succeeds        → refund is armed on the compensation stack
2. deposit errors           → the Run aborts immediately
3. stack unwinds LIFO       → refund fires, the money comes back
4. the original error is reported — the transfer failed, and the world looks like it never happened

Si refund échoue lui-même, les compensations restantes s’arrêtent et l’ensemble de la transaction remonte vers une porte de revue humaine (REVIEW) — le système décide de lui-même qu’un virement à moitié exécuté n’est pas quelque chose à masquer automatiquement.

Là où le texte cesse d’être la source de vérité — TANGEUL

Tout ce qui précède est TANGL : du texte markdown analysé et exécuté directement. Mais que le texte soit l’entrée d’exécution est une commodité, pas une nécessité. Dès qu’un langage a deux surfaces — l’anglais et le coréen — la question « laquelle est canonique ? » apparaît. Pour l’instant, la réponse est « l’anglais, par convention ». C’est une décision, pas une garantie structurelle.

TANGEUL supprime la question, et il est déjà livré en tant que source de vérité unique binaire pkg/tangeul pour la chaîne d’outils tangl. L’artefact d’exécution canonique est un flux de graphe binaire (.tangeul) sur lequel check/ast/effects/gen s’exécutent tous directement ; les fichiers markdown anglais et coréen sont des codecs de surface qui s’absorbent dans ce même graphe, et se réaffichent à partir de lui.

 EN .md ──[EN codec]──┐                        ┌──[mode 1]── verbatim byte-identical round trip
                      ├──> .tangeul (SSOT) ────┤
 KO .md ──[KO codec]──┘                        └──[mode 2]── normalized EN/KO rendering
  • Mode 1 (verbatim) : rejoue exactement les octets rédigés, de sorte que la sortie de décodage est identique octet pour octet au .md d’origine — vérifié par le test d’aller-retour de la CLI.
  • Mode 2 (régénéré) : decode --locale en|ko réaffiche chaque instruction à travers le codec de la locale cible, en rejouant les segments de prose verbatim. Un document rédigé en coréen peut être affiché pour un auditeur anglophone, et vice versa.

La surface de rédaction d’un document est fixée à une seule locale (mélanger des sections anglaises et coréennes dans un même fichier est rejeté), mais le flux .tangeul lui-même ne sait pas quelle locale l’a écrit. Il peut être affiché dans l’une ou l’autre langue à la demande précisément parce que l’artefact canonique est un graphe, pas un paragraphe.

Toute la connaissance au niveau du bit est mise en quarantaine dans deux paquets — word (mots de 16 bits, en-têtes de trame) et codebook (valeurs de code en ajout seul) — de sorte que les couches au-dessus (paquets, flux, le conteneur de document) restent stables quelle que soit l’évolution de l’encodage :

pkg/tangeul/
├── word/       // 16-bit words, frame headers — bit-level knowledge stops here
├── codebook/   // NodeType/PropCode/Control codes, append-only
├── packet/     // Node/Edge/Control/Text packets
├── stream/     // Doc ↔ .tangeul serialization
└── doc/        // Doc container + VerifyTiling + the surface Codec interface

VerifyTiling est la porte d’intégrité : les blocs enregistrés doivent paver le texte source exactement, et elle s’exécute à chaque chargement et à chaque sortie d’encodeur. Les tests de parité affirment que l’AST chargé depuis un flux .tangeul est égal à l’AST que l’analyseur produit à partir du .md d’origine (aux numéros de ligne près). Le reciblage vers le binaire ne consiste pas à changer ce que fait le code — le graphe, et donc la sortie générée, est identique ; il consiste à supprimer structurellement la possibilité de dérive entre plusieurs copies du même texte.

Des contrats auditables

La conclusion de toulmin était qu’un verdict est calculé par une formule, non décidé par une personne. TANGL y ajoute une ligne de plus : le calcul est lisible par quelqu’un qui n’a jamais écrit la formule.

  • Justification (une règle) = une phrase, `n` is a ... rule
  • Réfutation = une phrase, don't `X` when `Y`
  • Fondement (preuve) = un appel vers une fonction de paquet référencée
  • Verdict = la formule du h-Categoriser

Et TANGEUL est le travail qui garantit, au niveau de l’octet, que ces phrases pointent vers le même graphe quelle que soit la langue dans laquelle elles sont écrites. La personne qui écrit la règle et la personne qui l’audite n’ont plus à partager une langue.

MIT License. github.com/park-jun-woo/toulminpkg/tangl, pkg/tangeul, cmd/tangl.

Sources

Journal des modifications

  • 2026-07-03: First edition