ブランチ修正を検証する

// GUIDE · BRANCH-FIX

候補の修正を end-to-end でテストする。

Vivarium はレシピ(バグ)と比較サーフェス(あなたの修正)と、修正が壊れた code path を実際に回避したときに反転する verdict を組み合わせている。本ガイドはそのループを Layer 1(ブラウザ内)と Layer 2/3(Docker)の両方で end-to-end に歩く。

// 0 · このループの目的

AI-slop 検証 — その修正、本当に動く?

AI エージェント(Claude Code、Cursor、Cline、Continue、…)が アップストリームのバグに対する候補の修正を提案してきた。素直な問いは 「本当にバグを直したのか、それとも修正に見えるだけか?」。Vivarium の branch-fix ループはこれに 機械的な verdict 反転 で答える: 修正をレシピのランタイムに通し、バグがまだ trigger するか を見るだけ。

verdict のセマンティクス。 reproduced は 「バグが trigger する(修正は回避できていない)」、 unreproduced は「バグが trigger しない(修正が壊れた code path を回避できた)」。動く修正は verdict を reproduced から unreproduced に反転させる。

2 つのパスは同じワイヤ形(Contract v1)と同じ比較サーフェス (/repro/compare)を共有する:

01
Path A — Layer 1(ブラウザ内ソース置換)。

レシピページに代替版の再現スクリプトをペーストする。レシピの WASM ランタイム(php-wasm、ruby.wasm、Pyodide)が同じタブで再走させ、verdict をキャプチャする。CI 不要、Docker 不要。

02
Path B — Layer 2/3(Docker イメージ再ビルド)。

branch-fix Docker イメージを自分でビルドして push する。GitHub Actions ワークフローがそのイメージを pull して走らせ、verdict をキャプチャ、/repro/compare が描画するアーティファクトバンドルを公開する。

Layer ディスパッチは自動 — レシピのカタログエントリが既にどの Layer かを知っているし、MCP の verify_branch_fix ツールは両方に 正しい足場を返す。

// 1 · レシピを選ぶ

カタログでバグを探す。

既知のレシピから入るか、エラー文から入るかで 2 通り:

01
レシピが既に分かっている。

ギャラリーを眺めて該当レシピのページに入る。slug をメモする(例: php-12167)。

02
エラー文があるのでレシピを探したい。

/repro/match(エラーをペーストして候補をスコア順に表示)を使うか、AI エージェントから match_error を呼ぶ(同じスコアリング、同じサーフェス)。

// 2 · PATH A — LAYER 1

レシピページに修正をペースト、verdict をキャプチャ。

Path A に opt-in した Layer 1 レシピは、ベースライン出力の下に 「Try a fix」 パネルを描画する。現時点では php-12167 に出荷済み、形が proven したら他のレシピも続く。

01
レシピページを開く。

ベースラインの再現が先に走り、オリジナルの verdict(典型的には reproduced)がキャプチャされたあとパネルが描画される。

02
修正ソースを供給する。

3 つのモード: (a) textarea にペースト、(b) 公開取得可能 URL(raw GitHub / Gist)を指定、(c) ディスクからファイル選択。URL 取得時の CORS エラーはペーストへフォールバック。

03
実行をクリック。

レシピが既にロード済みの WASM ランタイムが置換ソースを実行する。パネルは Contract v1 形の verdict バンドルをキャプチャする: branch-fix-verdict.json + original-verdict.json

04
両方の verdict をダウンロード。

パネルは side ごとに 1 つずつダウンロードリンクを描画する。両ファイルは Contract v1 に準拠 — Layer 2/3 のワークフロー実行から /repro/compare が消費するのと同じ形。

05
/repro/compare にドロップ。

/repro/compare を開いて両方の JSON ファイルをドロップゾーンにドラッグする。ページは side-by-side で evidence を描画し、divergent なフィールドをハイライトする。

エージェント駆動のショートカット。 AI エージェントから verify_branch_fix(slug, fix_url) を呼ぶと、ツールは ?fix_url= 事前読み込み済みの compare_url を返す — その URL を開けばレシピページが自動で fix を走らせる。 verify_branch_fix(slug, fix_source) も同様 (≤4 KiB inline、長い fix は fix_url 経由)。

// 3 · PATH B — LAYER 2 / 3

イメージをビルド、ワークフローを実行、アーティファクトをドロップ。

Layer 2(Docker カタログ)と Layer 3(record-replay)はブラウザ タブでは走らせられない — バグは本物の OS、本物のソケット、 本物のファイルシステムを要求する。Path B はビルドをあなた自身の インフラに移し、push したイメージに対する verdict を GitHub Actions ワークフローでキャプチャする。

01
branch-fix イメージをビルドして push する。

AI の候補修正を fork に当て、レシピの Dockerfile で Docker イメージをビルドし、GitHub Actions ランナーが pull できるレジストリ(公開 ghcr.io / Docker Hub repo)に push する。image-as-input の境界は contract — Vivarium はあなたのソースをビルドしない、あなたが行う。

02
比較ワークフローを trigger する。

gh workflow run branch-fix-verdict.yml --repo aletheia-works/vivarium -f slug=<slug> -f branch_image=<your-image-ref> を実行する。ワークフローはあなたのイメージを pull、その中で再現を走らせ、Contract v1 verdict をキャプチャ、branch-fix-verdict-<slug>-<run_id> をアーティファクトとしてアップロードする。

03
アーティファクト zip をダウンロード。

ワークフロー実行ページからアーティファクト zip を取得する。branch-fix-verdict.json と(デプロイ済みスナップショットがあれば)original-verdict.json が含まれる。

04
zip を /repro/compare にドロップ。

ページは zip をクライアントサイドでパースし、両 verdict を Contract v1 スキーマに照らして検証、side-by-side で evidence を描画する。

エージェント駆動のショートカット。 Layer 2/3 の slug に対する verify_branch_fix(slug) は、コピペ可能な gh_command を返す。エージェントが実際にそれを走らせるには gh 認証とレジストリアクセスが必要 — だがコマンド自体は 組み立て済み。

// 4 · VERDICT を読む

ここでの `reproduced` と `unreproduced` の意味。

branch-fix の verdict が伝えるのはちょうど 1 つ: 修正が当たった状態で バグは trigger したか?

  • オリジナル = reproduced、branch-fix = unreproduced 修正がバグを回避した。典型的な 「修正が動いた」結果。

  • オリジナル = reproduced、branch-fix = reproduced 修正は slop — outcome を変えていない。 修正を反復して再走させる。

  • オリジナル = unreproduced、branch-fix = reproduced リグレッション — あなたの変更が バグを導入した。diff を巻き戻すか、何を変えたかを確認する。

  • オリジナル = unreproduced、branch-fix = unreproduced どちらも変化なし。レシピが 非アクティブ(アップストリームが既に修正済み)か、現在のランタイム に対してあなたの修正が no-op。

Path A は ユーザーランド の修正が壊れた code path を回避するか をテストする — アップストリームのインタプリタにパッチを当てる わけではない。Path B は 完全に再ビルドしたイメージ がバイナリレベルでバグを直すかをテストする。重みは違う、ワイヤ形は同じ。

// 5 · エッジケース

ループが計画通り進まないとき。

  • ランタイムが verdict 生成前にエラーした。 Path A ではパネルのステータスラインが赤になり、ランタイムエラー テキストが出る。よくある原因: ペーストした修正の構文エラー。 構文を直して Run をもう一度クリック。

  • スキーマが verdict 形を reject した。 /repro/compare は各 verdict を verdict.schema.json (Contract v1 rev3)に照らして検証する。エラーリージョンは bad フィールドの JSON path を表示する。Path A は構造的に well-formed な verdict を生成するので、これが見えるなら 手編集ファイルをドロップしている可能性が高い。

  • CORS で URL 取得がブロックされた。 公開 raw GitHub と Gist URL は CORS 対応ヘッダを返す。セルフホスト URL はしばしば 返さない。その場合はペーストモードへフォールバック。

  • Path B のプライベートレジストリイメージ。 ランナーは認証なしで pull する。プライベートレジストリは v1 の スコープ外。public ref に push するか、pull 認証情報フォロー アップを待つ。

  • 修正が長すぎて ?fix= に入らない。 インライン URL パラメータの上限は 4 KiB。Gist や fork URL を 使った ?fix_url= を使う。

// 6 · この先

このループの上に組めるエージェントループ。

01
エージェントループを end-to-end に閉じる。

パイプライン: match_error → slug に絞り込み → verify_branch_fix → compare_url を開く → verdict を読む。reproduced ならエージェントに別の候補を頼む。unreproduced ならマージへ。

02
自分のバグのレシピを足す。

カタログにまだあなたのバグが無いなら、レシピを書く。Path A は 1 行で opt-in できる。

03
verdict を自分の CI と組み合わせる。

自分のリポジトリに統合する パスは push のたびに verdict ドリフトを検出する — オンデマンドだけではない。

どこかで詰まったら、それは本ガイドのバグです。slug、Layer、path(A か B)、 詰まったステップ番号を Issue に残してください。

// NEXT

用語集

残りのガイドが前提にしている語彙 — Layer、manifest、contract、verdict、evidence、slug — を 1 ページにまとめてある。

VIVARIUM は ALETHEIA-WORKS の一部 · GitHub でソースを見る →