Изображение: сгенерировано ИИ
toulmin вычисляет контракты. Правила — это функции на Go, исключения объявляются как граф поражений (defeat graph), а h-Categoriser превращает граф в вердикт. Проблема в том, что человек, которому действительно нужно проверить контракт, обычно не умеет читать Go.
Налоговый консультант, проверяющий политику кредитования. Владелец малого бизнеса, сверяющий правило контроля доступа. Банковский служащий, изучающий логику компенсации перевода. Никто из них не может посмотреть на func(ctx Context, specs Specs) (bool, any) и сказать: «да, это верно». Каким бы безупречным ни была математика движка, если читатель не может прочитать код, аудит превращается в театр.
ИИ пишет, человек читает
TANGL (Toulmin Amgoud Nute Graph Language) закрывает этот разрыв. Вы пишете markdown-предложения, и эти предложения и есть исполняемый код.
## 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`
Эти пять строк — весь граф toulmin: Rule, Counter, Attacks и ребро исполнения. Автору не нужно думать об отдельном шаге компиляции: инструментарий tangl разбирает этот markdown прямо в *ast.Document, и validate/effects/gen работают с ним без изменений. Автор — это ИИ, проверяющий — это человек; в этой асимметрии весь смысл. ИИ достаточно следовать одной строгой канонической грамматике; человеку достаточно прочитать предложение на своём родном языке.
Одна семантика, множество поверхностей
Семантика TANGL определена один раз, в английской грамматике: двойственность Evaluate/Run, once (идемпотентность такта), undo (компенсация), тайминг каскадов, детерминированный порядок исполнения. Ни одна локальная редакция — корейская или та, что появится следующей, — ничего из этого не переопределяет. Она лишь заменяет таблицу ключевых слов и порядка слов, лежащую поверх того же самого AST. Одно корейское предложение отображается 1:1 в одно английское, и оба разбираются в идентичный узел AST.
Это не переводческий слой, прикрученный ради удобства, — он несущий. Настоящие читатели TANGL в Корее — это аудиторы-непрограммисты: 소상공인, 세무사. Английские ключевые слова вроде don't X when Y или is a general rule не позволяют непрограммисту подтвердить: «да, это читается правильно». Если читатель кореец, поверхность должна быть корейской, чтобы аудит действительно работал, — и симметрично то же верно для англоязычных читателей.
Создание корейской редакции выявило то, что не было очевидно из одной лишь английской грамматики: SOV-порядок корейского языка — это не переводческое бремя, а лучшая посадка для условных правил. `Y`면 `X` 실행한다 (примерно «когда Y, делай X») читается по-корейски естественнее, чем do X when Y, — условие сначала, предикат в конце — именно так изначально устроен этот язык. Корейская политика частиц идёт ещё дальше: частицы (은/는/이/가/을/를 …) — это необязательные токены, которые лексер отбрасывает, но написанная ИИ каноническая форма всё равно всегда их включает — ради человека-читателя, а не парсера. Поскольку ИИ — единственный автор, парсеру никогда не приходится принимать свободный порядок слов или разговорные вариации; ему нужно разобрать лишь одну каноническую форму. Именно эта асимметрия и делает нетривиальную поверхность на естественном языке вообще выполнимой.
Семь секций
Subject → See → Definitions → Rules → Cases → Provides → Internal
| Секция | Роль | Обязательна |
|---|---|---|
| Subject | объявляет, о чём документ | обязательна |
| See | ссылается на символы внешнего пакета | опционально |
| Definitions | термины и структуры | опционально |
| Rules | встроенные предикаты-условия | опционально |
| Cases | суждение + исполнение (сам граф) | обязательна |
| Provides | эндпоинты | опционально |
| Internal | внутренняя работа по такту/событию | опционально |
Каждая конструкция допустима только в своей секции — та же дисциплина областей видимости, которую любая локальная редакция наследует без изменений. Утверждения читаются как законченные предложения, называющие свой собственный вид: is a general rule, don't ... when, do ... once when, undo ... when, run ... when.
Пример: кофейный робот
Вот как семантика исполнения TANGL — двойственность Evaluate/Run, once, каскадирование — проявляется как обычные markdown-предложения.
## 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`
Аудитор читает это так: «Как только чашку можно поставить — если заказ получен, поставь чашку один раз и переходи к наливу воды. Если чашки нет, заказ недействителен. Чтобы сварить кофе, начни с установки чашки и повторяй каждую секунду, пока его не удастся подать».
Без once рука ставила бы новую чашку на каждом такте, пока заказ остаётся активным, — это слово и есть вся причина, по которой медленное обновление датчика не превращается в физически небезопасный повторный запуск. Аудитор подтверждает безопасность повторного запуска из этого одного предложения, ни разу не читая охранное условие на Go.
Пример: компенсация — мир остаётся целым даже при сбое
undo — это не то же самое, что отказ. Отказ — это нормальная ветвь графа; undo — это компенсация для исполнения, оборвавшегося на полпути.
- do `bank`.`withdraw` once when `balance sufficient`
- undo `bank`.`refund` when `balance sufficient`
- run `can deposit` when `balance sufficient`
«Если баланса достаточно, спиши один раз; если что-то ниже по цепочке сорвётся, откатись через возврат; и продолжай к зачислению». При сбое порядок детерминирован:
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
Если сам refund даст сбой, оставшиеся компенсации останавливаются, и вся транзакция эскалируется к шлюзу ручной проверки человеком (REVIEW) — система сама решает, что наполовину выполненный перевод — это не то, что можно автоматически замять.
Где текст перестаёт быть источником истины — TANGEUL
Всё вышеописанное — это TANGL: markdown-текст, разбираемый и исполняемый напрямую. Но то, что текст является входом для исполнения, — это удобство, а не необходимость. Как только у языка появляются две поверхности — английская и корейская, — возникает вопрос «какая из них каноническая?». Сейчас ответ таков: «английская, по соглашению». Это решение, а не структурная гарантия.
TANGEUL устраняет этот вопрос и уже поставляется как двоичный единый источник истины pkg/tangeul для инструментария tangl. Канонический артефакт исполнения — это двоичный поток графа (.tangeul), с которым check/ast/effects/gen работают напрямую; английский и корейский markdown-файлы — это поверхностные кодеки, которые впитываются в этот же граф и рендерятся обратно из него.
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): воспроизводит написанные байты в точности, так что вывод декодирования побайтно идентичен исходному
.md— проверяется тестом round-trip в CLI. - Mode 2 (regenerated):
decode --locale en|koперерендеривает каждое утверждение через кодек целевой локали, воспроизводя прозаические фрагменты дословно. Документ, написанный на корейском, можно отрендерить для англоязычного аудитора, и наоборот.
Поверхность авторства документа зафиксирована на одной локали (смешивание английских и корейских секций в одном файле отклоняется), но сам поток .tangeul не знает, на какой локали он был написан. Его можно отрендерить в любой из языков по требованию именно потому, что канонический артефакт — это граф, а не абзац.
Всё знание битового уровня изолировано в двух пакетах — word (16-битные слова, заголовки кадров) и codebook (только-добавляемые значения кодов), — чтобы слои над ними (пакеты, поток, контейнер документа) оставались стабильными, как бы ни развивалось кодирование:
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 — это шлюз целостности: записанные блоки должны в точности замостить исходный текст, и он выполняется при каждой загрузке и на каждом выходе кодировщика. Тесты паритета утверждают, что AST, загруженный из потока .tangeul, равен AST, который парсер производит из исходного .md (с точностью до номеров строк). Перенацеливание на двоичный формат — это не про изменение того, что делает код: граф, а значит и сгенерированный вывод, идентичен; это про структурное устранение самой возможности расхождения между несколькими копиями одного и того же текста.
Проверяемые контракты
Вывод toulmin состоял в том, что вердикт вычисляется формулой, а не решается человеком. TANGL добавляет к этому ещё одну строку: вычисление читаемо тем, кто никогда не писал формулу.
- Warrant (правило) = одно предложение,
`n` is a ... rule - Rebuttal (опровержение) = одно предложение,
don't `X` when `Y` - Ground (свидетельство) = один вызов функции из указанного пакета
- Verdict (вердикт) = формула h-Categoriser
А TANGEUL — это работа по гарантированию, на уровне байтов, что эти предложения указывают на один и тот же граф независимо от того, на каком языке они написаны. Человеку, который пишет правило, и человеку, который его проверяет, больше не нужно владеть общим языком.
MIT License. github.com/park-jun-woo/toulmin — pkg/tangl, pkg/tangeul, cmd/tangl.
Источники
- TANGL — грамматика исполняемого markdown (TANGEUL.en.md)
- pkg/tangeul — двоичный формат SSOT (README)
- park-jun-woo/toulmin — движок правил и инструментарий tangl
История изменений
- 2026-07-03: Первая редакция