画像:AI生成
toulmin は契約を計算する。ルールは Go 関数、例外は defeat グラフとして宣言され、h-Categoriser がグラフを判定に変える。問題は、その契約を実際に監査する必要のある人は、たいてい Go を読めないということだ。
融資ポリシーを監査する税理士。アクセス制御ルールを確認する小規模事業者。振込の補償ロジックをレビューする銀行員。彼らの誰も func(ctx Context, specs Specs) (bool, any) を見て「はい、これは正しい」とは言えない。エンジンの数学がどれほど健全でも、読み手がコードを読めなければ、その監査は芝居にすぎない。
AI が書き、人間が読む
TANGL(Toulmin Amgoud Nute Graph Language)はその溝を埋める。あなたはマークダウンの文を書き、その文が そのまま 実行可能なコードなのだ。
## 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 ツールチェーンはこのマークダウンをそのまま *ast.Document にパースし、validate/effects/gen はそれを変えずに走る。著者は AI で、検証者は人間だ — その非対称性こそが核心である。AI はただ一つの厳格な正規文法に従えばよく、人間はただ自分の言語で一文を読めばよい。
一つの意味論、複数の面
TANGL の意味論は英語文法の中で一度だけ定義される — Evaluate/Run の二重性、once(tick の冪等性)、undo(補償)、カスケードのタイミング、決定論的な実行順序。いかなるロケール版(韓国語であれ、次に来るどの言語であれ)もこれらを再定義しない。同じ AST の上に載るキーワードと語順の表を差し替えるだけだ。韓国語の一文は英語の一文と 1:1 で対応し、両者は同一の AST ノードにパースされる。
これは便宜のために後付けされた翻訳レイヤーではない — 荷重を担う構造だ。韓国における TANGL の実際の読者は、開発者でない監査者たちである。소상공인、세무사。don't X when Y や is a general rule のような英語キーワードでは、開発者でない人が「はい、これは正しく読める」と確認できない。読み手が韓国人なら、監査が実際に機能するためには面が韓国語でなければならない — そして逆もまた、英語の読み手に対して対称的に成り立つ。
韓国語版を作る中で、英語文法だけからは見えなかったものが浮かび上がった。韓国語の SOV 語順は翻訳の重荷ではなく、条件ルールにより適合するのだ。`Y`면 `X` 실행한다(おおよそ「Y のとき X をする」)は、韓国語では do X when Y よりも自然に読める — 条件が先、述語が後というのは、この言語がそもそもそう構造化されているというだけのことだ。韓国語の助詞ポリシーはこれをさらに推し進める。助詞(은/는/이/가/을/를 …)はレキサーが捨てる省略可能なトークンだが、AI が書く正規形は常にそれらを含める — パーサーのためではなく、人間の読み手のために。AI が唯一の著者である以上、パーサーは自由な語順や話し言葉のゆらぎを受け入れる必要はなく、ただ一つの正規形をパースすればよい。その非対称性こそが、非自明な自然言語の面をそもそも扱い得るものにしている。
七つのセクション
Subject → See → Definitions → Rules → Cases → Provides → Internal
| セクション | 役割 | 必須 |
|---|---|---|
| Subject | 文書が何についてかを宣言する | 必須 |
| See | 外部パッケージのシンボルを参照する | 任意 |
| Definitions | 用語と構造体 | 任意 |
| Rules | インラインの条件述語 | 任意 |
| Cases | 判定 + 実行(グラフそのもの) | 必須 |
| Provides | エンドポイント | 任意 |
| Internal | tick/イベント駆動の内部処理 | 任意 |
各構文は自身のセクション内でのみ有効だ — これはどのロケール版も変わらず継承する同じスコープ規律である。文はそれ自身の種類を名づける完結した文として読める。is a general rule、don't ... when、do ... once when、undo ... when、run ... when。
例:コーヒーロボット
TANGL の実行意味論 — Evaluate/Run の二重性、once、カスケード — がどのように普通のマークダウン文として現れるかを示す。
## 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 がなければ、注文が有効なあいだ、アームは tick ごとに新しいカップを置き続けてしまう — 遅いセンサー更新が物理的に危険な再実行に化けないのは、ひとえにこの語のおかげだ。監査者はこの一文から、Go のガード節を一度も読むことなく、再実行の安全性を確認する。
例:補償 — 失敗しても世界は無傷のまま
undo は却下と同じではない。却下はグラフの通常の分岐であり、undo は途中で死んだ実行への補償だ。
- do `bank`.`withdraw` once when `balance sufficient`
- undo `bank`.`refund` when `balance sufficient`
- run `can deposit` when `balance sufficient`
「残高が十分なら、一度引き出す。下流で何かが失敗したら、refund でロールバックする。そして deposit へ進む。」失敗時、順序は決定論的だ。
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 だ。マークダウンのテキストが直接パースされ実行される。だが、テキストが実行入力であることは便宜であって、必然ではない。言語が二つの面 — 英語と韓国語 — を持った瞬間、「どちらが正規か?」という問いが現れる。今の答えは「英語、慣例により」だ。それは決定であって、構造的な保証ではない。
TANGEUL はその問いを取り除く。そしてそれはすでに、tangl ツールチェーンのためのバイナリな単一の真実の源 pkg/tangeul として出荷されている。正規の実行アーティファクトは バイナリのグラフストリーム(.tangeul)であり、check/ast/effects/gen はすべてこれに対して直接走る。英語と韓国語のマークダウンファイルは、その同じグラフへ吸収され、そこから描き戻される面のコーデックだ。
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とバイト単位で同一になる — 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 は整合性ゲートだ。記録されたブロックはソーステキストを正確にタイル状に敷き詰めねばならず、これはロードのたびに、そしてエンコーダ出力のたびに走る。パリティテストは、.tangeul ストリームからロードされた AST が、パーサーが元の .md から生成する AST と等しい(行番号を除いて)ことを主張する。バイナリへのリターゲットは、コードの振る舞いを変えることではない — グラフは、したがって生成される出力も同一だ。それは、同じテキストの複数のコピー間でドリフトが起こる可能性を、構造的に取り除くことなのだ。
監査可能な契約
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 — 実行可能マークダウン文法(TANGEUL.en.md)
- pkg/tangeul — バイナリ SSOT フォーマット(README)
- park-jun-woo/toulmin — ルールエンジンと tangl ツールチェーン
変更履歴
- 2026-07-03: 初版