ADR-0013 は sandbox verification framework (scratch/verification/) の存在を決定したが、 framework 内部に 2 種の検証 method が育った後も両者の境界は明文化されていなかった:
runner.sh): hook script 単体を mock JSON payload で発火 (echo | bash、 REQ-VER-003 = exit code 中心)、 または CLI subcommand 単体を golden-diff (ADR-0018 kind:cli-golden)。 plugin load 非依存・決定的・CI 可能。Track 1 (cli-golden、 ADR-0018) と Track 2 (ADR-0007 context injection の e2e S-F) でこの 2 method が両方とも実体を持ったため、 verification.html §5.2 が「Phase X3 Step 1 完了後」 に予約していた本 ADR (hook unit test vs integration test 境界) を起票確定する時期に達した。 確定すべきは: どの failure class をどちらの層が所有するか、 各層の assertion model、 integration 層でしか検証できない behavior の判定規則。
folio の verification は unit 層 (sandbox) と integration 層 (e2e) の 2 層で構成する。 両者は包含関係になく、 所有する failure class が異なる 相補的な層である。
| 軸 | unit 層 (sandbox) | integration 層 (e2e) |
|---|---|---|
| location | verification/scenarios/ + runner.sh | verification/e2e/ + runbook.md |
| 検証対象 | hook script 単体 / CLI subcommand 単体 (隔離) | live load 済 plugin 全体 (hook chain + marker + SKILL + SessionStart) |
| 発火 | mock payload echo | bash (kind:hook) / bin/folio 直接実行 (kind:cli-golden) | 実 Edit/Write tool 操作 + fresh session 起動 (agent-driven) |
| assertion | exit code + stderr_contains (REQ-VER-003) / byte-exact golden-diff (ADR-0018) | file 作成有無 (deny→不在 / notify→存在、 REQ-VER-009) + fresh session の context 観察 (S-F) |
| 実行者 / 決定性 | runner.sh (自動・決定的・CI 可能・plugin load 非依存) | agent が runbook を walk (live plugin load 必須・CI 不可) |
| 所有 failure class | hook / CLI のロジック正当性 (component 単位) | plugin packaging・hook 登録・hook 間相互作用・Claude Code 統合点 (deny bug 可視性・SessionStart source 発火・stdout→context 注入) |
ある behavior が 単一 script への mock payload または 単一 CLI command の隔離実行で exercise できるなら、 その behavior は unit 層で検証する MUST。 unit 層は決定的・高速・CI 可能であり、 regression を component 単位で pinpoint できる。 integration 層は unit で代替できない場合の例外として用いる (e2e は実 session / 実 tool / agent walk が必要でコスト大)。
以下は mock が再現できない live Claude Code runtime 依存であり、 unit 層に移せない。 これらは integration 層 (e2e) で検証する MUST:
~/.claude/plugins/<name> symlink + cld auto discovery 経由で plugin が load され hook が登録されるか。同一機能が unit 層と integration 層に分割される ことを最も明瞭に示すのが ADR-0007 の context injection である。 この境界規則の canonical example として保持する:
folio prime が出力する Tier 1 digest text は kind:cli-golden + capture:stdout で golden-diff 検証する (prime-digest.yaml、 REQ-VER-012)。 決定的・CI 可能。inject-inventory.sh に mock payload を流せば「script が動く」 ことは unit で言えるが、 「Claude Code が stdout を context に注入する」 ことは言えない — これが本 ADR の境界そのものである。
| 案 | 採用しなかった理由 |
|---|---|
| 案 A (採用): 二層モデル (unit=sandbox / integration=e2e) + 境界規則 (unit 既定、 §2.3 該当のみ e2e) | 所有 failure class が相補的で包含関係なし。 unit の CI 決定性と e2e の統合被覆を両立、 判定規則が明確 |
| 案 B: unit 層のみ (sandbox + cli-golden、 e2e 廃止) | deny 可視性 (research §2.6)・SessionStart 注入・hook 間相互作用が原理的に検出不能。 framework を生んだ動機 (実機統合の不確実性) を defeat |
| 案 C: e2e 層のみ (agent eyeball で全検証) | CI 不可・非決定的・低速、 component 単位の regression pinpoint 不能。 ADR-0018 が既に golden-diff の決定性を選択済 |
| 案 D: ADR-0013 に統合 (別 ADR 化しない) | ADR-0013 は framework の存在決定。 unit/integration 境界 + 層別 assertion model は Track 1/2 で実体化した別の決定であり、 §5.2 が ADR-0017 枠を予約済 |
| 案 E: kind:hook と kind:cli-golden を別「層」 と扱う | 両者は共に unit 層 (隔離 component 検証)。 本質的な軸は assertion 方式でなく unit-vs-integration (live runtime 依存か否か) |
runner.sh (commit c65a2de で cli-golden 拡張)