# Phase 0(走路骨格)完了レポート - 作成: 2026-10-18 - ブランチ: `feat/phase0-walking-skeleton` - 検証: `node scripts/verify-bundle.mjs` → **全12検査 PASS** ## 1. 達成したこと(設計書 §6 Phase 0 の完了条件に対する答え) | # | 目標 | 結果 | 証拠 | |---|---|---|---| | 1 | 自作バンドルを DSH の Cordis 木に載せる | **達成** | 合成ツリーに `# == dsh-forjp-tui` と `- id: forjp` が出現。`name` は `file:///…/node_modules/dsh-forjp-tui/lib/index.js` に正規化 | | 2 | C(フル host-entry)経路で起動 | **達成** | `FORJP_ENTRY=in-process node lib/bin.js --help` → exit 0。実モデル実行も exit 0 で `final: "OK"` | | 3 | C を故意に壊すと B へフォールバックして起動し続ける | **達成** | `DSH_FORJP_HOST_PACKAGE=/nonexistent-path` を渡すと C が `HostResolutionError` で落ち、stderr に明示したうえで子プロセスへ落ちて exit 0 | | 4 | `session/event` の生ダンプを取得 | **達成** | 15種類 / 18件を捕捉(`turn/start` `step/start` `assistant/message` `system/message` `request/header` `request/context` `approval/policy` `sandbox/mode` `permission/preset` `session/title` `session/title-llm-request` `user/message` `agent/inbox/spliced` `step/end` `turn/end`) | ## 2. 作ったもの | ファイル | 役割 | |---|---| | `src/index.ts` | Phase 0 観測プラグイン。`apply` マーカーと `session/event` を NDJSON で書き出す。**描画はしない**(Phase 0 の制約) | | `src/host-contract.ts` | **DSH への依存を集約する唯一のファイル**(設計書 §3.3 制約2) | | `src/bin.ts` | 入口。C を既定とし、失敗したら B(`dsh --profile` 子プロセス)へフォールバック | | `cordis.patch.yml` | バンドルパッチ。`insert:` で `forjp` 行を1つ挿す | | `scripts/verify-bundle.mjs` | 上記を再現検証するスクリプト(12検査) | ## 3. 設計を変えた発見 ### 3.1 C(host-entry)は「複製」ではなく「公開関数の呼び出し」で足りる 参考実装 dsh-TUI は DSH の boot 手順を写して **736行** を要した。しかし `dsh/lib/bin.js:213-222` を読むと、 ランチャ自身が `@deepseek-ai/dsh/profile-boot` の `runProfile({ environment, profile, fromDefaultProfile, patchFiles, args })` を呼んでいるだけである。**我々は同じ公開関数を自分の入口から呼べばよい。** 結果、ホストへの依存は **2モジュール・2エクスポート**に収まった: ```ts export const HOST_MODULES = { '@deepseek-ai/dsh/profile-boot': ['runProfile'], '@deepseek-ai/dsh-app-boot': ['loadLayeredEnv'], } as const ``` 設計書 §3.3 が想定していた「`HOST_MODULES` 8モジュールの export 名に依存する脆さ」は、**この経路を採る限り発生しない**。 (参考実装が脆いのは boot 手順を写したからであり、公開関数を呼べば同じ「自前の入口」が得られる。) ### 3.2 `engines.dsh` は実装されていない(設計書 D9 の訂正) 調査の結果、`dsh-app-boot` に `engines` を読む箇所は**存在しない**。互換性判定に効くのは **`peerDependencies` の版指定**であり、`^0.2.0` のような範囲は prerelease (`0.2.0-rc.2`) に**非適合**として **行が無言で `disabled` 化される**(`dsh-app-boot/lib/index.js:286-313, 2085-2089`)。 → DSH パッケージを peer に書くときは **exact `0.2.0-rc.2`** を使う。 ### 3.3 `name:` の解決形式(実測) `cordis.patch.yml` の `insert:` 行の `name:` は、**絶対パス / `file://` URL / 相対パス**の3つとも解決される。 相対パスは**パッチファイル基準**で `file://` に自動変換される。これにより、パッケージが プロファイルの `node_modules` に無くても、または pnpm install を行わなくても木へ挿せる。 ## 4. 検証環境(このリポジトリ固有) `$HOME/.dsh` には**一切書き込んでいない**。`DSH_HOME` をワークスペース内へ向けて完結させている。 詳細は `docs/research/2026-10-18-sandbox-and-dsh-home.md`。 ``` DSH_HOME=$PWD/.dsh-home node lib/bin.js --json "..." ``` ## 5. やっていないこと(次フェーズ以降) - **描画**: 一切していない(Phase 0 の制約)。`src/ink/` への Ink fork は未着手(Phase 0.5 / 2) - **`HOST_DEVIATIONS` 相当**: 上流と意図的に異なる挙動の記録は、まだ差分が無いので空である - **上流ファイル同一性の検出**: `host-replica.snapshot.json` 相当は未実装(設計書 §3.3 制約3) - **TUI としての入口**: 現状の `forjp` プロファイルは検証の足場として `dsh-headless` を同梱している。 自前のランナーに置き換えるのは Phase 1 以降 - **`Context` の型**: `src/index.ts` は最小のローカル型を使っている。DSH の実型への置換は依存供給方法の決定後 ## 6. 再現手順 ```sh pnpm install pnpm build COMMANDCODE_API_KEY=... node scripts/verify-bundle.mjs ``` `COMMANDCODE_API_KEY` が無い場合、E(実モデル)は skip され、A〜D の構造検査のみ実行される。