はじめての再現を書く

// GUIDE · 再現を書く

ブラウザだけで動く Layer 1 レシピを 1 つ書く。

既存レシピをコピーしてスラッグと再現スクリプトを差し替えるだけで、Vivarium 互換の再現ページが手元で動く。完成したらアップストリームへ PR を送るか、自分のフォークに置き続けるかを選べる。

// 0 · このガイドが対象にするもの

Layer 1(ブラウザ内 WASM)の最小レシピ。

Layer 1 は PyodideRuby.wasm、php-wasm、 Rust の wasm32-wasip1 ターゲットなどで上流コードを ブラウザに持ち込み、ページが開いた瞬間に再現スクリプトを走らせて verdict を返す層です。インストール不要・サーバー不要なので、 Vivarium に最初に追加するレシピとして最もコストが低いです。

Layer 2(Docker)と Layer 3(record-replay)はそれぞれ アーキテクチャ に役割が書かれていますが、書き始めるならまず Layer 1 一択です。

このガイドはレシピを書くところまでを対象にします。 その先「どこに公開するか」は 2 分岐で、 自分のフォークで動かす または上流リポジトリへの PR、のどちらかです。

// 1 · 再現したいバグを決める

スラッグは <project>-<issue> 形式。

上流 Issue がある場合は <project>-<issue> (例: pandas-56679)が標準。 ない場合は説明的なケバブケース(例: bash-local-shadows-exit)。 これがディレクトリ名でもあり、Manifest v1 の slug でもあります。

バグを選ぶときは、Layer 1 で完結するか確認するのがコツです:

  • 外部 I/O(ネットワーク、ファイル、サブプロセス)を踏まない。
  • verdict が 1 つの真偽値に落ちる(例: 「2 つの値が等しいか」)。
  • 必要なライブラリが対象ランタイムの WASM ビルドに乗っている(Pyodide / Ruby.wasm / php-wasm の同梱パッケージ一覧)。

// 2 · クローンして雛形をコピーする

一番近い既存レシピを丸ごとコピーするのが最短。

01
リポジトリを用意する。

アップストリームに PR したいなら aletheia-works/vivarium を直接クローン、自分のフォークに置きたいなら フォーク手順 でフォークしてからクローンします。

02
mise でツールを揃える。

mise install でリポジトリ直下から bun など必要なツールが入ります。Layer 1 用には cd src/layer1_wasm 配下で bun install も走らせてください。

03
一番近い既存レシピをコピーする。

言語が同じレシピを丸ごとコピーするのが楽です。Python なら src/layer1_wasm/pandas-56679/、Ruby なら ruby-21709/、PHP なら php-12167/、Rust なら regex-779/cp -r src/layer1_wasm/pandas-56679 src/layer1_wasm/<あなたの slug> でディレクトリごと複製。

// 3 · index.html を書き換える

差し替えるのは title、見出し、lede の 3 か所。

コピーした index.html の構造はそのまま使い、以下を上流バグに合わせて差し替えます:

  • <title> — タブに出るタイトル(例: Vivarium · Reproducing <project>#<issue>)。
  • <h1> — 見出し。上流 Issue へのリンクを含めます。
  • <p class="lede"> — 1〜2 文でバグを説明する lede。

触ってはいけないもの: <meta name="vivarium-contract" content="v1">#verdict 要素、../_shared/style.css へのリンク。 これらが Contract v1 を構成しているので、外すと verdict が機械的に読めなくなります。

Contract v1 の正典は Contract v1 にあります。 data-verdict の取りうる値、VIVARIUM_RESULT envelope のスキーマは spec ページが正です。

// 4 · repro.ts を書き換える

再現ロジックだけ差し替える。helper はそのまま。

コピー元の repro.ts../_shared/loader.js ../_shared/verdict.js を import している部分が共通骨格です。 ここはそのまま残して、再現コード本体だけ差し替えます。 Python レシピなら以下のような形:

const REPRO_CODE = `
import pandas as pd
# ↑ 上流バグを表す最小コード
result = {
"left": ...,   # 比較する値 1
"right": ...,  # 比較する値 2
"mismatch": <left> != <right>,
}
result
`.trim();

verdict 設定は helper が面倒を見ます: 比較が true(バグが再現した)なら setVerdict("reproduced", "...")、そうでなければ setVerdict("unreproduced", "...")setResult({ contract: "v1", bug, runtime, result, timing }) VIVARIUM_RESULT envelope も書き出されます。

// 5 · ローカルで動かす

bun run build → 静的サーバ → ブラウザで開く。

# src/layer1_wasm/ から
bun install
bun run build         # repro.ts → repro.js を生成

# レシピディレクトリを直接サーブ
python -m http.server -d src/layer1_wasm/<あなたの slug> 8765
# ブラウザで http://localhost:8765/ を開く

ページが開き、上流ライブラリが CDN からロードされ、 verdict バッジが pending reproduced / unreproduced のどちらかに落ちます。 DevTools コンソールで VIVARIUM_VERDICTVIVARIUM_RESULT も同じ値が入っていれば、 Contract v1 上は OK です。

Pyodide / Ruby.wasm / php-wasm はいずれも SharedArrayBuffer を使わない構成にしてあるので、COOP/COEP ヘッダは不要です。 普通の静的サーバ(python -m http.server bunx serve)で動きます。

// 6 · ネイティブ再検証(任意)

ブラウザ外でも同じバグが出ることを 1 行で確かめる。

Pyodide / Ruby.wasm 経由で観測できたバグが、本物の CPython / MRI Ruby でも同じく再現することを示すと、レシピの説得力が上がります。 Python なら uv + PEP 723 inline metadata で 1 ファイル完結に書けます:

# /// script
# requires-python = ">=3.13"
# dependencies = ["pandas==2.3.3"]
# ///
import pandas as pd
# … 同じ再現ロジック …

mise exec uv -- uv run repro.py で ephemeral venv が組まれて走ります。Ruby、PHP、Rust も同様で、既存レシピの repro.rb / repro.php / Cargo.toml が雛形になります。

// 7 · recipes.json を再生成

ギャラリーに自分のレシピを並べる。

ギャラリー(/repro/)と MCP サーバが読む recipes.json は、ビルド時に src/layer*/ をスキャンして自動生成されます。 手元での確認用には:

mise run recipes:index
# あるいは
cd docs && bun run generate-index

生成された docs/public/api/recipes.json に 自分のスラッグが入っていれば成功です。 docs サイトをローカルで動かすと、ギャラリーにカードが現れます:

cd docs && bun run dev
# http://localhost:3000/vivarium/ja/repro/

// 8 · どこに公開するか

上流 PR か、自分のフォークか。

01
アップストリーム カタログに contribute する。

aletheia-works/vivarium 上で feat(layer1): add <slug> reproduction のような Conventional Commits で PR を立てます。レビュー基準は既存レシピを見れば分かりますが、最低限 Contract v1 に従っていれば CI が緑になります。

02
自分のフォークに置く。

レシピを自分の vivarium フォークの main に push し、フォーク手順 の deploy 設定を有効化すると、自分の <you>.github.io/vivarium/ に並びます。共有は URL を渡すだけ。

03
自分のリポジトリに統合する。

自分のプロジェクトリポジトリ側で「このレシピを CI で監視する」だけしたい場合は、レシピを書く必要はありません。自分のリポジトリに統合する に Manifest v1 と consumer-workflow.yml を使う最短手順があります。

手順のどこかで詰まったら、それは write-your-first-reproduction のバグです。詰まったステップ番号を Issue に残してください。

// NEXT

用語集を読む

ここで出てきた slug / verdict / contract / Layer といった単語は、用語集に固定的な意味でまとめてあります。

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