🛡️

SDD + TDD + VDDを融合したClaude Codeプラグイン「VSDD Claude Code」を作った話

に公開

はじめに

AI開発が当たり前となった現在、開発速度は格段に向上しました。
それでも、根本的な問題は解決されていません。

LLMが生成したコードはテストを通過し、レビューでも問題が見つからない。

「これでいける」と思い、リリースしてから初めて、問題が露呈するというようなケースが多々あります。

例えば、本番環境に出てから初めて仕様との乖離が見つかった、エッジケースが考慮されていない、ハッピーパスしかテストされていない、などのケースがあります。

つまり、LLMが生成したコードの実態は抽象化が過剰で変更に脆いという問題があります。
このような現象を総称して「AIスロップ(AI slop)」と呼びます。

AIスロップとは解説した通り、表面上は正しく見えながら隠れた欠陥を抱えたコードのことです。

この対策として、最近ではAIエージェントを囲むハーネス(制御基盤)を設計することが重要になってきています。

ハーネスを簡単に言うと、AIモデル単体に委ねるのではなく、計画・実装・レビューといったフェーズを構造的に強制する「外側の仕組み」を作るアプローチのことです。

https://www.anthropic.com/engineering/harness-design-long-running-apps

問題は、仕様書を書いてもAIがそれを忠実に守ってくれるとは限らないことです。

つまり、「仕様に合っているように見えるコード」を生成することはできても、「本当に仕様を満たしているかをAI自身が保証する仕組みがない」ことが問題です。

その答えとなり得るのが 現時点では、VSDD(Verified Spec-Driven Development) だと私は考えています。

https://gist.github.com/dollspace-gay/d8d3bc3ecf4188df049d7a4726bb2a00

今回はこのVSDDの仕組みをClaude Codeでワークフローとして作成してみたので、ワークフローの仕様とSDDとの比較について解説していきたいと思います。

VSDDとは何か

VSDD とは Verified Spec-Driven Development の略で、SDD(仕様駆動開発)・TDD(テスト駆動開発)・VDD(検証駆動開発)の3つの手法と、それらをつなぐ敵対的レビュー(Adversarial Review) という1つのゲートを統合した開発ワークフローです。

一言で言うと、「仕様 → テスト → 実装 の順序を機械的に強制し、最後に欠陥を探すことだけを命じられた別のAI による徹底的な批判レビューを生き残ったコードだけを完了と認める仕組み」です。

3つの融合要素

SDD(Spec-Driven Development) では、コードを書く前に仕様を完全に定義します。入力と出力、エッジケース、エラー条件を明文化してから初めて実装フェーズに進むことができます。

TDD(Test-Driven Development) では、失敗するテストを書いてからでないと実装コードに触れることができません。「テストがある実装」ではなく「テストに先立つ実装は存在しない」という原則を機械的に強制します。

VDD(Verification-Driven Development) では、テストをパスしただけでは完了にしません。かなり批判的なレビュアーが徹底的に欠陥を掘り起こし、もう何も見つからないと判断されて初めて完了とみなします。

敵対的ゲート

この3つをつなぐのが敵対的レビュー(Adversarial Review) です。

BuilderエージェントとはまったくContextを共有しない新規Adversaryエージェント(Opusモデル)が、ディスク上の成果物だけを読んでバイナリ判定を下します。

構造的にBuilderの「コンテキスト汚染」を排除することで、Builderが正しいと思い込んでいる欠陥を見逃さない仕組みになっています。

SDDとの比較

SDDは「仕様 → タスク → 実装」という直線的なフローでAI開発に秩序をもたらします。

仕様を真実の源とすることで、それに基づいてタスクを分解し、実装に進むというアプローチは非常に実用的です。

VSDDはその基盤の上に、フィードバックループと多重ゲートを加えた構造になっています。

観点 SDD VSDD
仕様定義 spec.md + tasks.md EARS形式 + 検証アーキテクチャ
TDD統合 なし(実装は指示ベース) Red→Green→Refactorの強制
レビュー 人間レビュー OpusのFresh Contextによる敵対的審査
フィードバック 手動で戻る フェーズ自動ルーティング
形式検証 なし Tier 0〜3の検証プロファイル
追跡 なし Chainlinkビードによる完全トレーサビリティ
構造 直線フロー ループ構造(収束まで繰り返す)

次の図が両者の違いをよく表しています。

SDDが直線的に進むのに対し、VSDDはAdversaryのFAILで前のフェーズに戻り、収束するまでループし続けます。

どちらが優れているかという話ではなく、目的が異なるということが重要です。

SDDはAIの暴走を構造的に防ぐ実用的なフレームワークです。
VSDDはそこにAIスロップへの対策を組み込み、「完了」の定義を「仕様・テスト・実装・検証」という4つの多次元の条件に拡張・昇華させたものだと言えます。

VSDDの全体像 — 6フェーズ・4ロール・8原則

VSDDは 6つのフェーズ4つのロール8つの原則 によって構成されています。

このセクションでは全体像をひと通り把握できるよう、パイプラインの流れ、各フェーズの成果物、ロールの役割分担、そしてAIスロップ対策として特に重要な3原則を順に紹介します。

6フェーズパイプライン

VSDDは6つのフェーズで構成されており、直線的に進むのではなくAdversaryがFAILを出すたびに適切なフェーズへ戻るループ構造になっています。全フェーズをクリアして初めて完了です。

フェーズ一覧

上記の図を踏まえて、各フェーズで何が行われ、どんな成果物が生まれるかを一覧で整理します。

フェーズ サブフェーズ 名称 主な成果物
1 1a 仕様結晶化 behavioral-spec.md(EARS形式)
1 1b 検証アーキテクチャ verification-architecture.md
1 1c 仕様レビューゲート verdict.json(Adversary判定)
2 2a テスト生成(Red) テストファイル + red-phase.log
2 2b 実装(Green) ソースコード + green-phase.log
2 2c リファクタ リファクタ済みソース
3 敵対的レビュー verdict.json + FIND-NNN.json
4 フィードバック統合 フェーズ遷移記録
5 形式的ハードニング verification-report.md, security-report.md, purity-audit.md
6 収束判定 収束レポート

4つのロール

VSDDでは人間とAIがそれぞれ明確な役割を持ちます。
誰が何を担当するかを整理したものが以下の表です。

ロール 担当者 責任範囲
Architect 人間 戦略ビジョン、仕様承認、紛争調停
Builder Sonnet 仕様執筆、テスト生成、実装
Adversary Opus(フレッシュコンテキスト) 超批判的レビュー、ゼロトレランス
Verifier Sonnet 形式検証コーディネーション

なお、原典のVSDDでは4つ目のロールとしてTrackerが定義されています。

階層的な課題分解 — Epic → Issue → Sub-issue。すべての仕様・テスト・実装がSub-issueに紐づく。

本プラグインではその役割をロールではなく内部の仕組みとして吸収し、代わりに形式検証を担うVerifierを独立したロールとして追加しています。

また、原典のVSDDではAdversaryにGPTなど別モデルの使用を推奨していますが、本プラグインはClaude Opusに統一しています。

ここでは、AdversaryだけがモデルにOpusとFresh Contextの制約を持つ点が重要です。

BuilderがどれだけSonnetで確信を深めていても、AdversaryBuilderの会話履歴を一切持たない新規インスタンスとして起動し、ディスク上の成果物だけを根拠に判定します。

8つの原則

VSDDは以下の8原則に基づいて設計されています。

# 原則名 概要
1 Spec Supremacy(仕様至上主義) 仕様が最高権威。テストは仕様に従い、コードはテストに従う
2 Verification-First Architecture(検証優先設計) 形式検証の必要性が設計を決める。実装後に検証しようとしても手遅れ
3 Red Before Green(レッド優先) 失敗するテストなしに実装コードは書かない
4 Anti-Slop Bias(反スロップバイアス) 最初に「正しく見える」バージョンには隠れた負債があると仮定する
5 Forced Negativity(強制否定性) Adversaryは問題を必ず見つけなければならない
6 Linear Accountability(線形説明責任) すべての仕様・テスト・コードはビードで追跡され、抜け漏れを許さない
7 Entropy Resistance(エントロピー抵抗) 毎回のレビューでAdversaryのコンテキストをリセットし、馴れ合いを防ぐ
8 Four-Dimensional Convergence(4次元収束) 仕様・テスト・実装・検証の4つがすべて揃って初めて完了

AIスロップ対策の3原則

8原則の中でも、AIスロップ対策として特に重要な3つが原則4・5・7です。

これらはAdversaryの設計思想の核心でもあります。

原則4 — Anti-Slop Bias(反スロップバイアス)

AIが生成したコードは「一見正しく見える」ことが多いですが、それ自体は正しさの証拠にはなりません。

VSDDでは最初のバージョンに必ず隠れた負債があると仮定し、Adversaryが積極的に掘り起こします。「動いているから大丈夫」という思い込みがAIスロップを見逃す最大の原因です

原則5 — Forced Negativity(強制否定性)

Adversaryには「問題を見つけなければならない」という義務が課されています。

「全体的に良い」「概ね問題なし」という所見は有効な判定として認められません。AIモデルには礼儀正しく肯定的になろうとする傾向があるため、その傾向を設計レベルで無効化しています。

原則7 — Entropy Resistance(エントロピー抵抗)

長期間の会話を続けると、AIは相手の考えに同調し批判が甘くなっていきます。

VSDDではレビューのたびにAdversaryのコンテキストを完全リセットし、Builderとの会話履歴を一切持たない状態で起動します。これにより、何度繰り返しても初回と同じ厳しさを維持します。

Adversary — VSDDの核心

VSDDで最も独自性が高い部分がAdversaryの仕組みです。

AIスロップの3カテゴリ

Adversaryが検出を義務付けられているAIスロップには、大きく3つのカテゴリがあります。

  1. 構造的スロップ

これは設計レベルの問題です。

handleDataprocessInputのような汎用的な命名、過度な抽象化、単一実装に対してインターフェースを作成する行為がこれにあたります。AIは「良い設計らしく見えるコード」を生成しようとするため、必要のない抽象化を施しやすくなっています。

  1. ロジックスロップ

これは実装レベルの問題です。

ハッピーパスのみのテスト、浅いバリデーション、デフォルト値によるエラー隠蔽、silent failure(エラーを記録せず黙って無視する)がこれにあたります。

テストスロップ

これは、テスト品質の問題です。

実装をそのままトレースしたようなミラーテスト、境界値が欠けたテスト、expect(result).toBeTruthy()のような弱いアサーション、過剰なモックがこれにあたります。

Adversaryの動作フロー

Adversaryは独立したエージェントとして起動し、Builderとは一切会話をしません。ディスク上のファイルだけを読んで判定を下し、結果もファイルに書き込みます。

以下がその流れです。

5次元バイナリ評価

AdversaryはすべてのディメンションでPASS/FAILを判定します。1つでもFAILなら全体FAILとなります。

なお、原典のVSDDではPhase 3の評価軸として「Test Quality」「Security Surface」「Spec Gaps Revealed by Implementation」が定義されていますが、本プラグインではこれらを以下の5次元に再編しています。

  1. Spec Fidelity — 実装は仕様の要件をすべて満たしているか
  2. Edge Case Coverage — エッジケースが網羅されているか
  3. Implementation Correctness — 実装に論理的な誤りがないか
  4. Structural Integrity — コード構造に問題がないか
  5. Verification Readiness — 形式検証が実行できる状態にあるか

指摘(Finding)のフォーマット

Adversaryが発見した問題はすべて構造化されたJSONとして記録されます。

FIND-001.json
{
  "findingId": "FIND-001",
  "dimension": "spec_fidelity",
  "category": "requirement_mismatch",
  "severity": "critical",
  "description": "REQ-003 requires returning ErrorCode.EMPTY_INPUT for empty string input. The implementation at src/parser.rs:45 returns None instead.",
  "evidence": {
    "filePath": "src/parser.rs",
    "lineRange": "43-48",
    "snippet": "if input.is_empty() { return None; }"
  },
  "routeToPhase": "2b"
}

routeToPhaseフィールドが重要で、このFindingをどのフェーズで修正すべきかをAdversaryが判断して記録します。

Phase 4(フィードバック統合)はこの値に基づいて自動ルーティングを行います。

Anti-Leniency規則

Adversaryには明示的な禁止ルールがあります。the implementation is mostly correctと書き始めたら、その時点でSTOPして見直すよう指示されています。

Adversaryが仕事を完了したと見なせるのは、具体的な証拠を引用した上でバイナリ判定を下したときのみです。

より具体的に言うと、「どのファイルの何行目に問題があるか」を示した上で、PASSかFAILかを明確に宣言したときのみ完了とみなします。

つまり、「全体的には良いと思います」のような曖昧な評価は完了とみなされません。

プラグインのアーキテクチャ

ここでは、VSDDをClaude Codeで動かすために、本プラグインがどのような構造になっているかを解説します。

エージェント間の通信方式、フェーズ違反を防ぐフック機構、そして成果物のトレーサビリティを保証するChainlinkビードの3点を中心に説明します。

ランタイム状態のレイアウト

VSDDのすべての状態は .vsdd/ ディレクトリ以下のファイルで管理されます。

エージェント間の通信も共有メモリや会話ではなく、このディレクトリへのファイル読み書きを通じて行われます。

Featureごとにディレクトリが分かれており、仕様・テスト証跡・レビュー結果・検証成果物がすべてここに蓄積されます。

.vsdd/
  index.json                      # 既知フィーチャーとアクティブポインタ
  active-feature.txt              # index.jsonのミラー
  history.jsonl                   # グローバル追記専用監査ログ
  features/
    <feature-name>/
      state.json                  # パイプライン状態(信頼できる唯一の情報源)
      specs/
        behavioral-spec.md        # Phase 1a 出力
        verification-architecture.md  # Phase 1b 出力
      contracts/
        sprint-{N}.md             # スプリント契約
      reviews/
        spec/
          iteration-{N}/
            input/manifest.json
            output/
              findings/FIND-NNN.json
              verdict.json
        sprint-{N}/
          input/manifest.json     # Orchestratorがレビュー前に書き込む
          output/
            findings/FIND-NNN.json
            verdict.json          # Adversaryがレビュー後に書き込む
      evidence/
        sprint-{N}-red-phase.log
        sprint-{N}-green-phase.log
      verification/
        verification-report.md
        security-report.md
        purity-audit.md
        security-results/         # Phase 5実行成果物(最低1件必須)

つまり、すべてのエージェント間通信はファイルを介して行われます。共有された会話状態は存在しません。BuilderとAdversaryの間に会話的な接続は一切ありません。

ゲートチェックフック

VSDDの最も強力な特徴の一つが、フェーズ違反を機械的にブロックするゲートチェックフックです。

vsdd-gate-check.jsPreToolUseイベントで動作し、Write/Edit/MultiEditとパスを対象とするBashコマンドを監視します。

scripts/hooks/vsdd-gate-check.js
// ソースコード: Phase 2b以前はブロック
{
  name: 'source files',
  blockedInPhases: new Set(['init', '1a', '1b', '1c', '2a']),
  matches: (filePath) => {
    const norm = filePath.replace(/\\/g, '/');
    return (
      norm.includes('/src/') ||
      norm.includes('/lib/') ||
      (SOURCE_FILE_EXTENSION_RE.test(norm) &&
       !norm.includes('test') && !norm.includes('spec'))
    );
  },
},
// テストファイル: Phase 2a以前はブロック
{
  name: 'test files',
  blockedInPhases: new Set(['init', '1a', '1b', '1c']),
  matches: (filePath) => {
    const norm = filePath.replace(/\\/g, '/').toLowerCase();
    return (
      norm.includes('/tests/') || norm.includes('.test.') || norm.includes('.spec.')
    );
  },
},

Phase 1aで仕様を書いている最中にAIが実装コードを書こうとすると、フックがそれをブロックして現在のフェーズを通知します。「書かせない」という機械的な強制が、AIの先走りを防ぎます。

Chainlinkビードトレーサビリティ

「このコードはなぜ存在するのか」を仕様要件まで遡れるのがChainlinkです。

Chainlink とは、VSDDの成果物を連鎖的に追跡するトレーサビリティの仕組みです。

仕様要件・検証プロパティ・テスト・実装・レビュー指摘・形式証明のそれぞれに ビード(bead) と呼ぶ一意のIDを割り当て、それらをチェーン構造として管理します。

すべての成果物は一意のビード識別子を持ち、双方向グラフとしてstate.json内に保存されます。

REQ-001  "空の入力の場合、パーサーは空のASTノードを返す"
  |
  +--> PROP-001  "forall empty input, parse(input).node_count == 0"
  |
  +--> TEST-001  "test_parse_empty_input() -> asserts node_count == 0"
  |
  +--> IMPL-001  "fn parse(input: &str) -> AstNode { ... }"
  |
  +--> FIND-001  "IMPL-001 does not handle null bytes before empty check"
  |
  +--> PROOF-001  "kani::proof fn verify_empty_input() { ... }"

このビードの連鎖はPhase 6の完了チェックにも使われます。Adversaryが出した指摘(FIND-NNN.json)に対応するビードが1つでも欠けていると、「まだ対処されていない問題がある」とみなされて完了がブロックされます。

以上がプラグインのアーキテクチャの概要です。
次に、実際に手元で動かすためのセットアップ手順を説明します。

セットアップ

インストール方法・プロファイルの選び方・言語ごとの検証ツール・フック設定の4点を順に説明します。

インストール

Claude Codeのプラグインシステムを使うのが最も手軽です。Claude Code上で以下の2コマンドを実行するだけでインストールできます。

terminal
/plugin marketplace add sc30gsw/vsdd-claude-code
/plugin install vsdd@sc30gsw-vsdd-claude-code

インストール後はClaude Code上でプラグインを再読込します

terminal
/reload-plugins

その他、インストールスクリプトやパッケージマネージャーを使ってインストールする方法もあります。

terminal
# インストールスクリプト
git clone https://github.com/sc30gsw/vsdd-claude-code.git
cd vsdd-claude-code
bash install.sh --profile standard

# パッケージマネージャー
npx vsdd-claude-code --profile standard
pnpm dlx vsdd-claude-code --profile standard

3つのインストールプロファイル

インストール時に--profileでインストールするファイルセットを選択できます。

初めて使う場合はstandardがおすすめです。
なお、このプロファイルはインストール内容を決めるだけで、実行時のモード(lean / strict)とは別の設定です。

コンポーネント minimal standard strict
Rules / Commands あり あり あり
Agents / Skills / Contexts なし あり あり
Hooks(ゲートチェック) なし あり あり
Core runtime scripts あり あり あり
terminal
bash install.sh --profile minimal   # 最小構成
bash install.sh --profile standard  # 推奨(フルワークフロー)
bash install.sh --profile strict    # 高保証ワーク向け

言語プロファイルと検証ツール

インストール時に--languageオプションを指定することで、言語ごとの検証ツールセットが有効になります。

Tier 1はプロパティベーステスト・ファジング・ミューテーションテストなど比較的手軽な検証ツール、Tier 2はより厳密な形式手法ツールです。

言語 Tier 1(プロパティ/ファジング/ミューテーション) Tier 2(軽量形式手法)
Rust proptest, cargo-fuzz, cargo-mutants kani
TypeScript fast-check, @stryker-mutator/core
Python hypothesis, mutmut
Go rapid, go-fuzz
C/C++ libFuzzer, CBMC CBMC

フックプロファイル

ゲートチェックの厳しさはVSDD_HOOK_PROFILE環境変数で切り替えられます。インストールプロファイルとは独立しており、後から変更可能です。

VSDD_HOOK_PROFILE環境変数でフックの挙動を制御できます。

terminal
export VSDD_HOOK_PROFILE=standard  # ゲートチェックあり(推奨)
export VSDD_HOOK_PROFILE=minimal   # ライフサイクルフックのみ
export VSDD_HOOK_PROFILE=strict    # ゲートチェック + 自動コミット

実践ウォークスルー — Leanモード

ここでは、実践サンプルとしてuser-authというFeatureでユーザー認証機能を実装するシナリオを順に追っていきたいと思います。

Step 1: フィーチャーパイプラインの初期化

まず実装したいフィーチャーを宣言し、パイプラインを初期化します。

/vsdd-init user-auth --mode lean

.vsdd/features/user-auth/ディレクトリが作成され、state.jsoninitフェーズで初期化されます。

leanモードでは仕様承認やスプリント契約が任意になるため、プロトタイプや通常のプロダクト開発に適しています。

Step 2: 仕様の結晶化(Phase 1a + 1b)

次に、実装の前に「何を作るか」を仕様として明文化します。

このフェーズを終えるまでテストも実装も書けません。

/vsdd-spec

Phase 1aでBuilderがbehavioral-spec.mdをEARS形式で記述します。

EARS(Easy Approach to Requirements Syntax)は要件を構造化された形式で記述するためのシンプルな構文です。

specs/behavioral-spec.md
## REQ-001: 空のメールアドレスの拒否
WHEN ユーザーが空のメールアドレスを送信する
THE SYSTEM SHALL ErrorCode.EMPTY_EMAIL を返す

## REQ-002: 無効なメールフォーマットの拒否
WHEN ユーザーが "@" を含まないメールアドレスを送信する
THE SYSTEM SHALL ErrorCode.INVALID_FORMAT を返す

## REQ-003: 重複アカウントの防止
IF 同じメールアドレスが既に登録済みである
THEN THE SYSTEM SHALL ErrorCode.DUPLICATE_EMAIL を返す

## REQ-004: ロックアウト
WHILE リトライ回数が3回を超えている間
THE SYSTEM SHALL 新たなログイン試行をすべてブロックする

Phase 1bではverification-architecture.mdに検証アーキテクチャを定義します。どの要件に形式検証が必要か、純粋性境界はどこかを設計時に決めます。

Step 3: 仕様レビューゲート(Phase 1c)

続いて、書いた仕様をAdversaryに審査させます。

穴があればここで潰すことができるため、後工程の手戻りを防げます。

/vsdd-spec-review

Adversaryが仕様をレビューしverdict.jsonを生成します。

leanモードでは人間承認は任意ですが、strictモードではArchitect(人間)の明示的な承認が必須となります。

仕様レビューでFAILの場合は、指摘内容を見てPhase 1aに戻り仕様を修正します。

Step 4: テスト生成(Phase 2a — Red)

このフェーズでは、仕様をそのままテストに落とし込みます。

この時点では実装コードが存在しないため、すべてのテストが失敗する状態(Red)を作ります。

/vsdd-tdd

Builderがすべての要件に対応する失敗するテストを生成します。ゲートチェックフックがこのフェーズまでソースコードへの書き込みをブロックしているため、実装コードは一行も存在しません。

このフェーズが正しく完了すると、red-phase.logに以下のマーカーが記録されます。

new-feature-tests: FAIL
regression-baseline: PASS

ここで重要なのは、「新しい機能テストが失敗している」かつ「既存テストは通過している」という状態を証明するログが出力されるという点です。

このログがPhase 2bへの入場条件となります。

Step 5: 実装とリファクタ(Phase 2b + 2c)

ここでは、テストをすべてPASSさせる最小限の実装を書き(Green)、その後テストを維持したまま構造を整えます(Refactor)。

/vsdd-impl

Phase 2bが完了すると、green-phase.logに以下のマーカーが記録されます。

target-feature-tests: PASS
regression-baseline: PASS

Phase 2cでグリーン状態を維持しながら構造を改善します。

この時点でAdversaryによるレビューに備えて、コードの品質を高めておきます。

Step 6: 敵対的レビュー(Phase 3)

いよいよレビューのフェーズです。
ここでは、テストをパスした実装をAdversaryが審査します。

FAILが出れば自動的に問題のフェーズへ戻り、PASSするまで繰り返します。

/vsdd-adversary

Adversaryが起動し、BuilderのすべてのContextは遮断されます。

Adversaryはディスク上の成果物だけを読んで5次元バイナリ評価を行います。

FAILの場合のシナリオ:

Adversaryがspec_fidelityでFAILを検出した場合、FIND-001.jsonには次のような内容が記録されます。

reviews/sprint-1/output/findings/FIND-001.json
{
  "findingId": "FIND-001",
  "dimension": "spec_fidelity",
  "category": "requirement_mismatch",
  "severity": "critical",
  "description": "REQ-001 は空のメールアドレスに対して ErrorCode.EMPTY_EMAIL を返すことを要求している。src/auth.ts:23 の実装は null を返している。",
  "evidence": {
    "filePath": "src/auth.ts",
    "lineRange": "21-25",
    "snippet": "if (!email) { return null; }"
  },
  "routeToPhase": "2b"
}

verdict.jsonのoverallVerdictがFAILとなり、Phase 4に自動的に進みます。

Step 7: フィードバック統合(Phase 4)

ここでは、AdversaryのFAILを受けて、各指摘をどのフェーズで修正すべきか自動で振り分けます。

/vsdd-feedback

具体的には、FIND-001.jsonrouteToPhase: "2b"を読み取り、自動的にPhase 2bへ戻ります。

また、指摘の種類によって戻り先も変化するようになっています。

  • 仕様の問題 → Phase 1a(仕様を書き直す)
  • テストの問題 → Phase 2a(テストを修正する)
  • 実装の問題 → Phase 2b(実装を直す)
  • 構造の問題 → Phase 2c(リファクタする)

戻り先のフェーズで問題を修正したら、再度/vsdd-impl/vsdd-adversaryを実行します。

leanモードではこのループが最大3回まで繰り返せます。

Step 8: 形式的ハードニング(Phase 5)

AdversaryのレビューをすべてのディメンションでPASSしたら、Phase 5に進みます。

/vsdd-harden

verification-architecture.mdで定義した検証ティアに応じて形式検証を実行します。

leanモードでも以下の3つの成果物は必ず生成されます。

  • verification/verification-report.md — 形式検証の実行結果まとめ
  • verification/security-report.md — セキュリティ観点のチェック結果
  • verification/purity-audit.md — 副作用のない純粋なコアが守られているかの確認結果

leanモードでは証明が不要な場合でも、この3ファイルは必ず作成されます。また、verification/security-results/フォルダに実際のツール実行結果が最低1件保存されていないと、Phase 6に進めません。

Step 9: 収束判定(Phase 6)

最後に、すべての条件が揃ったかを最終確認します。
1つでも満たされていなければ完了になりません。

/vsdd-converge

つまり、以下の4条件をすべてクリアして初めて完了と判断するということです。

  1. 仕様が敵対的レビューを乗り越えている
  2. テストが十分なカバレッジを提供している
  3. 実装がすべてのテストをPASSしている
  4. すべての必須証明がproved状態にある

加えて、Adversaryが出した指摘がすべてビードとして記録されていること、Phase 5の成果物が揃っていることも確認されます。1つでも欠けていれば完了にはなりません。

補足: ステータス確認

ステップとは別に、パイプラインのどの時点でも現在の状態を確認できるコマンドがあります。

行き詰まったときや進捗を把握したいときに便利です。

/vsdd-status

出力としては以下のような出力が得られます。

Feature: user-auth
Mode: lean
Current Phase: 6 (Convergence)
Sprint: 1

Phases:
  ✅ 1a - behavioral-spec.md
  ✅ 1b - verification-architecture.md
  ✅ 1c - spec review PASS
  ✅ 2a - red-phase.log (FAIL confirmed)
  ✅ 2b - green-phase.log (PASS confirmed)
  ✅ 2c - refactor complete
  ✅ 3  - adversary verdict PASS (iteration 2)
  ✅ 4  - feedback routed
  ✅ 5  - hardening complete
  🔄 6  - convergence check in progress

Beads: REQ-003 → PROP-002 → TEST-004 → IMPL-003 → PROOF-001

Strictモード

Strictモードはセキュリティ要件が厳しいシステムや金融・安全重要システムの開発向けです。

Leanモードより承認要件や証明義務が厳しく、より高い保証を得られます。

LeanモードとStrictモードの主な違いは以下のとおりです。

機能 Lean Strict
Sprint Contract リスクの高い作業のみ必須 毎スプリント必須
Phase 1c 人間承認 任意 必須
Adversary レビュー上限 3回 5回
証明義務 しばしばゼロ 強制
Sprint Contract レビュー 任意 Phase 3前に必須
適した用途 プロダクト開発、試作 セキュリティ重要、金融

strictモードの最大の特徴は、Phase 1cでAdversaryによる仕様レビューに加えてArchitect(人間)の明示的な承認が必須になる点です。

これは原典のVSSDが本来想定している形に最も近い運用形態です。

strictモードで初期化する場合は--mode strictを指定します。

/vsdd-init user-auth --mode strict

また、ゲートチェックの厳しさもあわせて引き上げたい場合は、フックプロファイルも設定してください。

terminal
export VSDD_HOOK_PROFILE=strict

ここまでで、セットアップから実際の動作の実践解説は以上となります。

VSDD Claude Codeでできたもの

こちらは、完全にVSDD Claude Codeのみで作ったTypeScript製のライブラリとです。

ライブラリのコンセプトはClaudeに決めてもらい、そこからVSDD Claude Code上で開発されたものとなります。
どの程度の品質になるか確かめたかったので、仕様だけでなく、TypeScriptの使用以外の技術選定も任せました。

.vsddにワークフローの軌跡があります。

https://github.com/sc30gsw/event-pipeline-ts

このプラグインだけで作らせた感想としては、CLAUDE.mdrulesなどがない状態でもある程度の品質が担保できるかつコードの品質も悪くないと思いました。

逆に言えば、まだまだコードを含め、品質改善の余地はあるとも言えるので、CLAUDE.mdrules、技術選定含めて、しっかりとした環境を組んだうえで実行すると、もっとよい品質になるのではと思います。

このあたりは、また検証して詰めていきたいと思います。

また、AIだけでここまでできるとはいえ、まだまだ人間のレビュー介入が必要そうというのが今回得られた所感です。

おわりに

VSDDは「AIが書いたコードをAIに攻撃させる」という逆説的なアプローチで、AIスロップの問題に取り組むアプローチです。

BuilderとAdversaryのContextを構造的に分離し、ゲートチェックフックで先走りを防ぎ、収束を多次元の条件として定義することで、「動いているように見える」ではなく「実際に正しい」コードへの経路を作ることが可能です。

ハーネス設計からSDDの導入までを一括導入したい場合に非常に有効なアプローチだと私自身は感じております。

ぜひ、VSDDを普段の開発に取り入れてみてください!

最後になりますが、ここまで読んでくださり、ありがとうございます。
フィードバックやIssueなどがあれば、GitHubまでお願いいたします!

https://github.com/sc30gsw/vsdd-claude-code

参考

https://gist.github.com/dollspace-gay/d8d3bc3ecf4188df049d7a4726bb2a00

https://x.com/__su888/status/2028230801372967333

https://www.anthropic.com/engineering/harness-design-long-running-apps

https://note.com/masa_wunder/n/n625405b7196e

https://zenn.dev/gotalab/articles/3db0621ce3d6d2

Discussion