本記事は Zenn にも同内容を公開している: https://zenn.dev/flip451/articles/sotohe-sot-chain-overview
AI コーディングエージェントはコードを書くのが速い。しかし「書かれたコードが仕様どおりである」ことは、実は誰も保証していない。この問題を解く一つの方法として、仕様や設計を文書のままにせず、機械が強制する制約として扱う機構を提案する。その機構は、設計判断、仕様、型契約、実装を一方向の参照で結ぶチェーンと、各リンクを検証する CI ゲートからなる。
本記事はシリーズ第 1 回。まず問題設定と全体像を示し、個別の仕組みは第 2 回以降で扱う。
「仕様どおり」は誰が保証するのか
Claude Code や Codex のようなエージェントに機能追加を頼むと、数分でコンパイルが通り、テストも green のコードが返ってくる。それ自体はもう驚くことではない。問題はその先にある。
- 問 1: そのコードは、合意した仕様を実装しているのか。仕様に書いていない振る舞いを勝手に足していないか
- 問 2: 仕様の側は、設計判断と矛盾していないか
- 問 3: テストは仕様の約束を検証しているのか、それとも「テストが存在する」だけなのか
人間だけのチームなら、この整合はレビューと記憶で保たれてきた。しかし AI エージェントが実装の主力になると、生産されるコードの量と速度に対して人間のレビューが構造的に追いつかなくなる。そして、レビューが追いついた範囲でも、仕様と実装の一致を機械が検査しているわけではない。人手による確認である以上、結果は担当者やそのときの状況に左右される。
だとすれば、保証は人の注意力の外側に置くしかない。といって、規約やプロンプトに書いて守らせるだけでは足りない。指示は読み飛ばされることがあり、読まれても守られるとは限らない。だからルールは、迂回できない機構(CI ゲート、フック、スキーマ検証)として実装する。筆者が開発している SoTOHE(Source of Truth Oriented Harness Engine)は、この考え方を一貫させたテンプレートである。
SoTOHE とは
SoTOHE は、AI エージェントによる仕様駆動開発(SDD: Spec-Driven Development)を管理する Rust 製 CLI(sotp)+ エージェントハーネスのテンプレートである。Claude Code / Codex CLI を操作面とする。開発の全工程(設計判断の記録、仕様書の作成、型契約の宣言、実装、レビュー、コミット、PR)を、機械可読な成果物と検証ゲートの連なりとして管理する。
SSoT(Single Source of Truth、その情報について信頼できる唯一の源)という語は広く知られている。SoTOHE はこれを一枚のドキュメントに求めるのではなく、階層ごとに置く。中核にあるアイデアはひとつだけだ。
設計から実装までを 4 つの階層に分け、各階層に SSoT を 1 つずつ独立ファイルとして置き、下流が上流を参照する一方向チェーンを機械検証する。
SoT Chain の 4 階層
階層ごとに置かれた SSoT を、下流から上流への参照で一本の鎖につないだもの。それを SoTOHE では SoT Chain と呼んでいる。各階層と、その SSoT となるファイルは次のとおりである。
| 層 | SSoT ファイル | ライフサイクル |
|---|---|---|
| ADR | knowledge/adr/*.md |
開発単位を跨ぐ恒久的な設計判断 |
| 仕様書 | spec.json |
開発単位ごとの要件(目的 / スコープ / 制約 / 受け入れ基準) |
| 型契約 | <layer>-types.json |
開発単位ごとの型宣言(型レベルのテスト) |
| 実装 |
libs/* / apps/* のソース |
恒久的なコード |
最上流の ADR (Architecture Decision Record) は、「なぜこの設計にしたのか」という決定を、理由ごと 1 件ずつ短い文書として残す記録形式である。SoTOHE 固有の発明ではなく、広く使われているこの実践をチェーンの起点に置いている。
この参照には向きがある。下流は必ず上流を参照する1。仕様書の各項目は根拠となる ADR を引用し、型契約の各型宣言は根拠となる仕様項目を引用し、実装は型契約と突合される。参照が切れる(上流に根拠のない記述が下流に現れる)と、CI が止まる。
「ドキュメントとコードを同期させましょう」という掛け声とこの仕組みの違いは、参照が機械可読であることだ。引用は JSON のフィールドとして書かれ、チェーンの評価はコマンド一発で再現できる。実装と型契約の一致も機械的に検証可能だ。
参照を 3 色で評価する信号機
各リンクの評価結果は信号機で表現される2。
| 参照 | 🔵 Blue | 🟡 Yellow | 🔴 Red |
|---|---|---|---|
| 実装 → 型契約 | 実装と契約が一致 | 未実装 | 契約違反 |
| 型契約 → 仕様書 | 宣言の根拠あり | 根拠あるが未文書化 | 根拠なし |
| 仕様書 → ADR | 永続化文書に根拠あり | 根拠あるが非永続化 | 根拠なし |
色は検査の結果であって、作業を止める指示ではない。止めるかどうかを決めるのは、色を読む側の「ゲート」である。3 色それぞれの扱いは次のようになる。
- 🔵 は根拠がつながっている。そのまま進んでよい
- 🟡 はつながっているが、解消すべき課題が残る。止まるかどうかはゲートの設定次第だが、開発単位の完了までには必ず解消する
- 🔴 は参照が切れている。どのゲートでも止まり、即修正
なお、この 3 色は CI 自体の green / red とは別レイヤーの語彙である。信号の評価結果が、コミットゲートや CI の pass / fail に翻訳される。🔴 が残っている限り、コミットは物理的にできない。人間の注意力を当てにしない。
構造と意味論の二層検証
ここまでの検証は決定論的な構造検査である。しかし構造検査で分かるのは「参照がある」ことまでで、「参照が意味的に正しい」ことは分からない。ADR を引用した仕様書が、その ADR と矛盾する内容を書くことはいくらでもできる。
そこで SoTOHE は各リンクを二層で守る。
- 構造検証(決定論):参照の存在と整合を機械が検査する
- 意味論検証(LLM 判定):「この引用は意味的に成立しているか」を LLM が判定する
意味論の判定結果は、信号機の 3 色に混ぜず、別レーンの結果として持つ(そうする理由は第 4 回で述べる)。
「LLM に判定させる」と聞くと不安になるだろう。SoTOHE はこの判定を CI ゲートとして信頼できるものにするため、いくつかの規律を課している。合格判定には根拠箇所の引用が必須である(「LGTM」だけの合格は存在しない)。判定結果は入力の hash に凍結され、上流か下流が 1 文字でも変われば失効する。失効の回復手段は hash の再計算ではなく、再判定の合格のみである。これは「変更を読んで整合を確かめた」ことと「盲目的に再発行した」ことを区別するためだ。詳細は第 4 回で扱う。
さらに、最後のリンク(実装 → 型契約)には、もう一段の意味論検証がある。型宣言からテスト義務を機械導出する。その義務が果たされているかを検証するゲートだ。「書くべきテストが書かれていない」を CI で検出する仕組みで、これは第 5 回の主題である。
作業単位としての track
SoTOHE はすべての作業を track という単位で管理する。1 track は 1 機能追加または 1 バグ修正に相当する。各 track は専用ブランチ上で進む。仕様書、型契約、実装計画、レビュー結果は、track ディレクトリに独立ファイルとして残る。
正規フローは 2 コマンドに集約されている。
/adr:add <slug> # 設計判断を ADR として記録する(対話ヒアリング)
/track:adr2pr # その ADR を起点に、仕様 ⇒ 型契約 ⇒ 実装計画 ⇒ 実装
# ⇒ レビュー ⇒ コミット ⇒ PR まで自走する
この 1 本のコマンドの内側では、仕様を書くエージェント、型を設計するエージェント、実装するエージェント、レビューするエージェントが役割分担して動く。役割ごとに担当プロバイダ(Claude / Codex / Gemini)を設定ファイルで割り当てられる。たとえばレビューは、実装したエージェントとは別に起動される独立したレビュアーが行い、指摘ゼロになるまでコミットできない。git commit の直接実行はフックでブロックされ、コミットはガード付きの経路しか存在しない。
こうして工程の大半が自動で進むので、人間が判断する地点は二つに絞られる。入口で ADR を書いて確定させることと、出口で PR をマージすることだ。ワークフローの詳細は第 2 回で扱う。
SoTOHE 自身の dogfooding
この仕組みは机上のフレームワークではない。SoTOHE 自身(sotp CLI)が、SoTOHE のワークフローで開発されている。本稿執筆時点で、200 個以上の track がこのパイプラインを通っている。この記事で紹介した信号機も意味論検証も、それ自体が track として仕様化され、型契約を宣言され、レビューゲートを通って実装されたものだ。
自作の仕組みを自分の開発に使うこと(dogfooding)は、品質保証であると同時に、設計への強制力でもある。ゲートを一つ増やすたびに、その煩雑さのコストを最初に払うのは筆者自身である3。
正直なコストの話
よいことばかりではない。この仕組みには実費がかかる。
- 意味論検証の LLM 判定にはトークンコストがかかる(hash 凍結キャッシュにより変更がなければゼロだが、初回と変更時は実費)
- 実装に着手する前に ADR、仕様書、型契約を書くため、着手までのリードタイムは「いきなり書く」より長い
- 成果物のスキーマや規約という学習コストがある
それでも筆者は、このコストを開発を人間から AI へ明け渡すための対価としてとらえている。人間がすべての成果物をレビューし続ける限り、明け渡しは起きない。AI が書く量が増えると、人間のレビューで品質を支える路線はいずれ破綻する。だから「仕様どおり」を保証する仕事を、人間の注意力から機構と成果物の側へ移す。実装前に書く ADR、仕様書、型契約も、LLM 判定の実費も、その移転のための支払いである。
このシリーズで書くこと
最後に、シリーズ全体の地図を置いておく。本記事で見た SoT Chain(📍)が中心にあり、続く各回はその周辺を一つずつ掘っていく。
以降の回で、各層を順に扱う。冒頭の問 1 から問 3 に答えるのは、第 3 回から第 5 回である。問 1 は構造の話と振る舞いの話に分かれるので、担当も 2 回にまたがる。
- 第 2 回: ADR から PR まで自走する track ワークフローとマルチエージェント分業
- 第 3 回: 型契約書を SSoT にする TDDD(型定義駆動開発)(問 1)
- 第 4 回: hash 凍結 verdict と引用義務で LLM の判定を CI ゲートにする(問 2)
- 第 5 回: 「書くべきテストが書かれていない」を検出するテスト義務ゲート(問 1 と問 3)
- 第 6 回: SoTOHE を使い始めるためのテンプレート export と新規プロジェクト実走記録
- 第 7 回: SoTOHE を支える設計原則
シリーズ一覧
- AI エージェントに「仕様どおり」を保証させる — SoT Chain という設計(本記事)
- ADR から PR まで自走する track ワークフローとマルチエージェント分業(公開予定)
- 型契約書を SSoT にする — TDDD(公開予定)
- LLM の判定を CI ゲートにする — hash 凍結 verdict と引用義務(公開予定)
- 「書くべきテストが書かれていない」を検出する — テスト義務ゲート(公開予定)
- SoTOHE を使い始める — テンプレート export と新規プロジェクト実走記録(公開予定)
- SoTOHE を支える設計原則(公開予定)
リポジトリ: https://github.com/Flip451/SoTOHE-core
-
本シリーズでは矢印を書き分ける。→ は参照の向きで、「参照する側 → 参照される側」、つまり下流から上流を指す(実装 → 型契約 など)。← はその逆から書いた表記で、チェーン全体の列挙(ADR ← 仕様書 ← 型契約 ← 実装)に使う。⇒ は工程の順序で、時間の前後を表す(仕様化 ⇒ 実装 ⇒ レビュー など)。 ↩
-
もともとクラスメソッド社の AI 駆動開発フレームワーク Tsumiki に着想を得て作成した機能だったが、気がついたら別物になっていた。 ↩
-
実際に払った例がある。コードの意味的な重複を LLM で検査するゲートは、かつて全コミットで必須だった。だが自分の開発を計測すると、この検査にまつわる作業が開発時間の約 15% を占めていた。しかも再検査 58 回のうち 84% は指摘ゼロの空振りだった。いまは既定で無効にし、必要なときだけ有効にする位置づけへ下げている。 ↩