# DSH との互換性 **対応する版は DSH 0.2.0-rc.2 です。0.1.5 系への対応は外しました。** 会話の参照、一覧と投影、V4 記録、設定・ファイルの RPC が変わったため、旧版へ切り替えるだけでは動きません。後方互換の分岐はありません。 対応版と同梱ライブラリの固定版は [src/shared/dsh-compat.ts](../src/shared/dsh-compat.ts) にあります。この文書は移行後の境界、確認範囲、次に版を上げる手順をまとめます。作業の経過は [99 の実装メモ](design/99-integration.md#2026-10-04dsh-020-rc2-への移行) にあります。 ## GitHub Releases 配布版 0.0.8 の記録(Issue #18) **2026-10-05 に [v0.0.8 をリリースしました](https://github.com/AliceSaikawa/dsh-webui-m3e/releases/tag/v0.0.8)。** 指示役が PR #20 を通常のマージで取り込んだ main `d00515e0776f46608a5c3ffe70eb529974ecf744` を確認し、同じコミットにタグ v0.0.8 とリリースを作成しました。当面は添付 tgz の URL で配ります。npm レジストリにはアカウントが無いため未公開で、名前だけでは導入できません。添付のサイズ・SHA-256 とコマンドは [配布の記録](development.md#配布) にあります。 `package.json.version` は M3E の公開版、`src/shared/dsh-compat.ts` は対応 DSH と共有ライブラリの版です。今回 M3E だけを 0.0.8 に上げ、対応 DSH 0.2.0-rc.2 と共有ライブラリは変えていません。以前配布した 0.0.7 は今回の対応版での復帰先にしません。 リリース前には実 CLI で、隔離した loopback HTTP の URL による追加・0.0.8 → 0.0.10 → 0.0.8 の切替、302 転送、404、削除と標準画面を確認しました。版を変えた tgz は tmp のコピーだけです。リリース後には新しい隔離 HOME / DSH_HOME で GitHub の実 URL による追加が exit 0、version が 0.0.8、標準画面でログイン後 `/m3e/` と `/?ui=classic` が 200 であることを指示役が確認しました。npm 向けのメタデータ・prepack・配布検査・本番モジュール検査は維持しています。 同じローカル URL の中身を差し替えて再追加すると、pnpm 11.17.0 は新しい 0.0.10 を取得しました。古いキャッシュが使われたという結果ではありません。同じ URL が元の版を指さなくなるため、添付ファイルを差し替えず、新しい版・タグ・リリース・URL にします。公開した GitHub URL は 302 が 1 回の後に 200、取得ファイルの SHA-256 は添付と一致し、転送応答は Cache-Control: no-cache でした。list の resolved と profile の依存は指定した GitHub URL のままでした。GitHub/CDN での差し替えや別環境のキャッシュ挙動は未検証です。コマンドと出力は [ローカル URL 配布の実測](development.md#url-配布の実測2026-10-05)と [リリース後の実行記録](development.md#v008-リリース後の実行記録2026-10-05)にあります。 初回の追加確認では、型検査・ビルド・単体 1,027 件(配布検査 16 件を含む)・偽データ e2e 159 件が成功し、実 DSH の全 34 件も 2 回確認しました。その後のレビュー対応で配布検査は 26 件になり、監査の 35 変異と追加 11 変異をすべて検出しました。本番へ偽データの補助だけを読み込ませた build も失敗し、復元済みです。最新の全体検査は [development.md の検証結果](development.md#今回の検証結果)を参照してください。 Node の要件は DSH 自身(engines 無し)、CLI の commander 15(`>=22.12.0`)、pnpm 11.17.0(`>=22.13`)を区別しました。確認環境は macOS 27.2、Node 26.7.0、pnpm 11.17.0 です。未検証の下限を保証しないため M3E の `engines.node: >=22` を外し、3 言語 README の案内も修正しました。 単体試験だけのパッチは通りました。Host 補助の変更と代替補助の追加は、それぞれ 1 回試して保護フックに止められたため適用していません。二重ビルドを残し、指定された代替手順で導入ライフサイクルを手動確認しました。この一連の操作の自動の試験はありません。 隔離した実 DSH の file: 導入では、未導入状態からの追加と削除は再起動なしで反映されました。更新・旧版復帰では静的ファイルが先に変わり、Host のコードは再起動まで切り替わりませんでした。この切替と再起動の必要性は、ローカル URL 導入でも同じでした。リリース後の GitHub URL 導入では、稼働中の削除が exit 0、/m3e/ は 404、標準画面は 200、一覧と依存から消え、再起動後も同じでした。file: → GitHub URL の移行も両方 exit 0、依存が URL に変わり、再起動後 /m3e/ は 200 でした。 保持の確認はローカル URL と file: の範囲だけです。1 workspace・1 会話と返答・別の組込みプラグインのシェル設定を保持し、削除後と再起動後に標準画面で同じ会話を開けました。GitHub URL 導入時の保持、第三者プラグイン、長期利用データ、Desktop、本物の LLM、iPhone Safari・ホーム画面の Web アプリは未検証です。今回のリリース後確認は LLM のキー無し、127.0.0.1 のみで行いました。 受け入れ条件は [7 項目の判定](development.md#受け入れ条件の判定)で npm と GitHub Releases を分けています。npm の主経路は未充足です。GitHub の経路ではクリーン環境からビルド無しでの導入(2)と file: からの移行(4)、削除(7)を確認済みです。公開版同士の更新と復帰は、2 つ目の互換版がリリースされてから確認します。リリース直前の main では型検査・単体 1,039 件・ビルド・配布検査 19 ファイル・偽データ e2e 159 件、実 DSH 2 回(各回通常 33 件成功と既知の差の期待失敗 1 件)、pnpm/npm の両 tgz 検査がすべて成功しました。 ## 版ごとの確認結果 2026-10-05 時点のまとめ用ブランチ `46ec172`(本体と試験)と、文書を取り込んだ `ab5c09d` を基準にしています。**段階 1〜6、最終レビューと最後の全体監査への本体修正、修正後の独立した読むレビューは完了しました。追加試験の独立した変異の当て直しも完了し、生存した変異は 0 件でした。指示役は、文書を取り込んだ `ab5c09d` で、型検査・単体・ビルド・偽データ e2e と、実 DSH の 3 回連続の実行を確かめました。** この移行は、PR #19 として main にマージ済みです(`b895500`)。件数は合算せず、検証ごとの実行時点と根拠を区別します。 | DSH の版・確認時点 | 対応と確認結果 | 型検査・ビルド | 単体試験 | 偽データ e2e | |---|---|---|---:|---:| | 移行前 `413a857` | 0.2.0-rc.2 への接続は起動で失敗。実 DSH の内訳は [下表](#実-dsh-の統合試験) | 成功 | 747 件成功 | 119 件成功 | | 0.2.0-rc.2・追加試験込み `46ec172` | 対応版。実 DSH の内訳は [下表](#実-dsh-の統合試験) | 成功 | 1,011 件成功 | 159 件成功 | | 0.1.5 系 | 対応対象外。移行後のコードでは再検証していません | ― | ― | ― | | 上記以外 | 対応を保証しません。移行後のコードでは未検証です | ― | ― | ― | 移行前は共通の作業記録に基づきます。移行後の型検査・単体・ビルド・偽データ e2e は、指示役が文書を取り込んだ `ab5c09d`(本体と試験は `46ec172` と同じ)で実行した結果です。既存のチャンクサイズ警告は残っています。 ## 依存の境界 DSH の内部の型は [web/src/dsh/services.ts](../web/src/dsh/services.ts) に必要な分だけ書き写しています。起動時の [contract.ts](../web/src/dsh/contract.ts) は controller の入口を確認しますが、メソッドの存在だけでは引数・戻り値・寿命の一致までは分かりません。下表の `features/` は `web/src/features/` の略です。 | 境界 | 0.2.0-rc.2 の形と注意 | このリポジトリの場所 | |---|---|---| | 起動グラフ | `__DSH_BOOT__`、`__ModuleLoader__.create()`、相対の `plugins/…`。通信用プラグインと依存だけを個別 URL で読みます | `web/src/dsh/boot.ts`、`boot-graph.ts` | | 通信の宛先と `` | M3E の index に ``。プラグイン、RPC、WebSocket、画像送信を Host の `/plugins/…`、`/api/…`、`/api/remote.mux` へ解決します | `src/host/index.ts` の `prepareM3eIndex` | | 画面の URL | 通信の基準を変えても画面は `/m3e/` に残します。空のリンク先、hash、検索文字列、戻る操作、PWA scope に注意します | `web/src/app/route-match.ts` の `pageHref`、`router.ts`、`Markdown.tsx` | | 共有ライブラリ | cordis 4.0.4、cordis-plugin-loader 1.0.5、dsh-client-store 0.2.0-rc.2 | `package.json`、`src/shared/dsh-compat.ts`、`boot.ts` の `STATIC_MODULES` | | 稼働状態 | `loader.await()` の完了だけでは成功を保証しません。`FiberState.ACTIVE = 2`、`importError(id)`、`fiber.await()` で状態と原因を確認します | `boot.ts` の `assertPluginsActive` | | 会話の参照 | `retain(target, { source, signal? })`、`using`、`SessionReference.ready/release`。最後の参照を解放すると scope は即時破棄されます | `conversation-selection.ts`、`session-navigation.ts`、`features/composer/delivery.ts` | | 参照の借用と失敗 | `scope` / `binding` は保持中だけ使えます。Host 拒否では `ready` が解決しても `openState: 'error'`、中断・解放では拒否になります。signal の中断と明示解放は別です | `web/src/dsh/services.ts`、会話選択・送信処理 | | 一覧と子の会話 | 一覧は `ids/byId/phase/projectionsBySession`。子カタログは投影 `subagentCatalog`、行は `id/mode/label` など。`byId` だけにある子と親 ID も扱います | `web/src/dsh/session-navigation.ts`、`session-rows.ts`、`features/session-tools/presentation.ts` | | 順番待ち・割り込み | 投影 `inbox` の `next-turn` と利用者由来の `next-step`。編集・削除のメッセージ ID と送信照合の `source.rpcId` を区別します | `web/src/dsh/inbox.ts`、`features/composer/Sheets.tsx` | | ジョブ | 一覧から専用の `ctx.jobs.state`、`watchRows` へ移りました。起動グラフにジョブの controller を含めます | `web/src/dsh/jobs.ts`、`boot.ts`、`features/session-tools/JobsScreen.tsx` | | 完了して未読 | Host の保存値ではなく、標準画面と同じ観測規則で画面側の `completionUnread` を計算します。永続化しません | `web/src/dsh/completion-status.ts` | | V4 記録 | `tool/result` の `message.role` は `tool`。`toolCallId/content/isError` はメッセージ直下です。旧記録は Host が変換します | `features/chat/model.ts`、`tool-output.ts`、`features/trace/model.ts`、`RecordSheet.tsx` | | V4 の出どころ・拡張 | `source.kind` に `runtime-context`、`compact-checkpoint`、`plugin:<名前>` など。未知のイベント・ブロックにも `plugin:` が付きます | チャット・トレースの読み取り、`web/src/dsh/session-journal.ts` | | 設定の名前空間と保存 | profile の entry id。`subagent-model-selection-settings`、`bash-sandbox`(Windows は `pwsh-sandbox`)、`agent-preset-registry.selectedDefault`。Host の `dsh-settings` と `dsh-config-editor` が profile の `cordis.patch.yml` を編集します | `features/settings/schema.ts`、`store.ts`、`ModelsPanel.tsx`。M3E は RPC を使い、設定ファイルを直接編集しません | | 設定の公開範囲 | `.volatile()` の項目だけ公開・編集可能です。`autoGenerate` を尊重し、`applies` は `live` のみ。`revision` は Host のプロセス内で管理します。書込み時の拒否条件と、設定を利用するときの検証を区別します | `features/settings/`。`settings.describe/update/mutate`、通知 `(ns, revision)`。`tests/support/settings-write-cases.ts` を偽 RPC と実 DSH で共有します | | 設定の数値 | 整数付近の許容誤差で判定せず、実物の Schemastery と同じ十進移動・刻み判定を使います。画面は非有限数も拒否します | `features/settings/number-step.ts` の `matchesNumberStep`、`schema.ts`。偽 RPC も同じ刻み判定を使います | | ゴールと Agent の準備 | 保存済み投影があっても Agent の準備前は `goals.get` が失敗し得ます。準備・接続・投影などの通知で読み直し、準備失敗通知で古い応答を無効にします。タイマーでは再取得しません。同時読取りは 1 件で、進行中の通知を次の 1 回にまとめます | `features/session-tools/goal-activation.ts` の `watchGoalActivation`、`GoalScreen.tsx`。通知集約は M3E 側の制御です | | 権限の候補 | 投影 `permissions` は `currentValue` のみ。候補は `permissionPresets.catalog()` と `permission-presets/catalog-changed`。既定値は `defaultOptions/defaultPreset` を使い、`settings.mutate` で `permission` の `defaultPreset` を保存します | `features/composer/api.ts`、`Sheets.tsx`、`features/settings/` | | モデル・提供元・API キー | モデルのある提供元だけが利用候補です。キーの照会は登録状態、登録・削除の戻り値は `void`。アカウントに架空のキー参照を作りません。未登録と管理サービスの利用不能を分けて案内します | `features/settings/providers.ts`、`features/composer/api.ts`。保存内部と更新放送の正確な引数は未検証です。購読側は引数を使わず再取得し、`record-updated` 単独の画面更新は偽通知で確認します | | ファイル RPC | `readBytes(sid, path, { range: { offset, length }, baseFile? }, signal)` のバイト列は `Uint8Array`。`changes(sid, path, signal)` は `RemoteStreamHandle`。通知は監視対象自身のパス・版で、`ready` の後にも過去の通知が届き得ます | `features/session-tools/files.ts`、`FileScreen.tsx`、`FilesScreen.tsx`。実 DSH 試験は操作直後の `stat` と一致する版まで読みます | | 期限つきの質問 | 表示中だけ `userQuestions.attachWait` で待機を保持します。期限後は `userQuestions` 投影からカードを復元し、`answer` で次ステップへ回答を送ります | `web/src/dsh/interactions-store.ts`、`features/interactions/InteractionSheet.tsx`。取消・再接続・後着応答の世代を区別します | | その他の RPC・通知 | `commands.list`、`fileReferences.list`、`session.modelCatalog/selectModel`、`directoryPicker`、`goals`、承認・質問の返答 | 各機能の `api.ts`、`operations.ts`、`web/src/dsh/remote-events.ts`、`interactions-store.ts` | | エラー・その他の投影 | `RemoteResult` と `RemoteFailure`、エラーコード、`plan/modelSelection/goal/tokenUsage/contextPressure` の形 | `web/src/dsh/remote-result.ts` と各機能。型・案内の試験と、実際のエラー発生は別に確認します | | Host・標準画面 | `webServer.register/renderIndex/tapIndex`、`connection.authorizeIndex`、`settings.general.item`。preload の除去は相対 URL にも対応します | `src/host/index.ts`、`src/client/index.tsx` | | Host のフォルダ選択 | macOS / Windows の loopback 起動は条件により `native`、SSH 起動の印があれば `browse` になります | `features/home/directory.ts`、`e2e-dsh/dsh-host.ts` | | 偽 LLM との接続 | `/v1/messages` と Messages 形式の SSE、`tool_use/tool_result`、画像の `image` ブロック。ブラウザに届く V4 記録とは別の形式です | `e2e-dsh/fake-llm.ts` | ### 0.1.5 から 0.2.0 で壊れた境界と、どう直したか | 壊れた境界 | 移行で直したこと | |---|---| | 相対の bootstrap URL が `/m3e/plugins/…` へ向き、起動できませんでした | Host の index に `` を入れ、相対の preload を除去します。ルーターと Markdown のリンクは表示中のページを基準に解決します | | RPC・WebSocket・画像の宛先もページの基準 URL に依存していました | Host のルートへそろえました。個別の通信フックを差し込む案も比較し、画像の進捗通知を保てる `` を採用しました | | 共有ライブラリと loader の失敗処理が変わりました | 同梱版をそろえ、待機後の稼働状態と失敗原因を確認します。通信失敗を版の不一致に取り違えないようにします | | 会話の開閉 API と暗黙の scope 作成がなくなりました | 画面・準備・送信の参照の持ち主を分け、新しい参照を取ってから古い参照を解放します。一覧の準備待ち、失敗後の再選択、離脱・復帰にも対応します | | 一覧内の選択・ジョブ・子カタログ、会話内の順番待ち、完了フラグを前提にしていました | 選択は M3E、ジョブは専用 controller、カタログと順番待ちは投影、完了未読は画面側の計算へ移しました | | 旧記録の結果ブロックと出どころを読んでいました | V4 だけを読みます。注入文脈と自分の発言を分け、トレースの呼び出しと結果を結合します | | 設定と保存契約が変わりました | 名前空間・`selectedDefault`・`autoGenerate`・`live` に合わせ、公開項目を実物と照合しました。辞書キーの制約は独立した期待値で検査し、偽設定の架空項目を `example-extension` に分けました | | 権限候補と提供元の境界が変わりました | 現在値の投影と候補 RPC を分け、既定値の保存、新規会話への適用、候補変更時の再取得を接続しました。利用不能なアカウント提供元を除き、キーの更新通知と案内を補いました | | ファイルのバイト列と監視契約が変わりました | `range` と `Uint8Array`、対象パス付きの監視に合わせました。画像全体のバイト比較、フォルダ自身の通知、操作後の版の照合で確認します | | 質問を無期限の返答だけで扱っていました | timed の待機保持、非表示時の期限、期限後の回答と取消後のカード復帰を扱います。既定の legacy 質問の返答も維持します | | 偽 LLM が旧通信形式で応答し、Mac の試験が native のフォルダ選択で止まりました | Messages 形式へ移行し、隔離 Host だけに SSH 起動の印を付けて browse を選びます | ### RPC の照合結果 「同じ」は引数・公開型・呼び出す側の実装を照合した結果で、すべてを実 DSH の画面から実行した意味ではありません。実行した経路は [統合試験の表](#確かめた経路) で区別します。根拠となる DSH パッケージは `tmp/dsh-integration/dsh-0.2.0-rc.2/node_modules/@deepseek-ai/` の下です。 | RPC・通知 | 判定 | 確認範囲・実物の根拠 | |---|---|---| | `commands.list`、`fileReferences.list` | 同じ | `dsh-commands` と `dsh-api-session-controller` の `lib/typert.remote-client.d.ts`。任意の `definitionId` も反映しました | | `session.modelCatalog/selectModel` | 同じ | `dsh-api-session-controller/lib/index.js`。モデルのある group が利用候補です。モデル一覧の表示は実 DSH、選択操作全体は偽データで確認します | | `directoryPicker.list/createDirectory` | 同じ | `dsh-api-workspace-controller/lib/typert.remote-client.d.ts`。実 DSH は browse 一覧から追加する経路です | | `goals.get/pause/resume/complete/clear`、`goal/activation-changed` | 同じ・実 DSH の操作全体は未検証 | `dsh-goal/lib/typert.remote-client.d.ts`、`dsh-api-remotes/lib/index.js`。Agent の準備待ち・状態通知・読取り集約を実装し、単体・偽画面で確認しました | | `api-session/added`、`api-session/error` | 型・購読を追加 | `dsh-api-session-controller` と `dsh-api-remotes`。Agent の登録・準備失敗をゴール画面の再取得と古い応答の無効化に使います。登録通知は全初期化 listener の完了保証ではありません | | `workspaceFiles.list/read/stat` | 同じ | `dsh-api-workspace-files/lib/typert.remote-client.d.ts`。実ワークスペースの一覧・本文・版を確認しました | | `workspaceFiles.readBytes/changes` | 直した | 同パッケージの `lib/types/types.d.ts` と `lib/index.js`。入れ子の範囲、バイト列、監視の対象と解放を合わせました | | `settings.describe/update/mutate` | 直した | `dsh-settings/lib/types/types.d.ts`、`dsh-api-settings-controller`。公開スキーマと共有書込みケースの受理・拒否を照合しました。段階 6-C では整数付近の小数と旧プロフィール項目の拒否も確認しました。全設定値の網羅ではありません | | 設定の名前空間・通知 | 直した | 標準の設定 UI と `dsh-settings`。保存から `(ns, revision)` を送る偽通知と、購読側の再取得・解除を確認しました | | `permissionPresets.catalog` と変更通知 | 直した | `dsh-permission-presets`。既定値は文字列設定として保存し、画面は候補の所属も確認します。実 DSH で自動候補の追加・削除通知によるシート更新を確認しました | | 提供元一覧とキーの照会・登録・削除 | 同じ・表示を修正 | `dsh-llm`、`dsh-api-settings-controller/lib/index.js`、標準 Models の呼出し側。実 DSH で架空値の登録・削除、別ページへの更新、環境由来の変更不可表示を確認しました | | キー保存内部・`record-updated` の自然発火 | 未検証 | 保存側は保護対象のため未読です。実 DSH で購読登録、偽通知で単独の更新処理を確認しましたが、自然発火・引数・順序・回数は保証しません | | 承認・legacy 質問、timed 質問 | 同じ・timed を追加 | `dsh-user-approval`、`dsh-user-questions`。既存の返答を維持し、`attachWait`・投影・`answer` の経路を段階 6-B で接続しました | | `RemoteResult/RemoteFailure` | 同じ・案内を追加 | `dsh-typert-protocol/lib/types/types.d.ts`。モデル・投影・監視不能や実行中アーカイブの案内を追加しました。個々の実障害の再現とは別です | ### 総点検で分かった本体の不具合 偽物が実物より寛容なために見逃していた問題と、実 DSH 試験で見つかった問題です。修正の取り込み状況を分けて記します。 | 問題 | 修正と確認 | 取り込み状況 | |---|---|---| | 送った文が確定記録と送信中の両方に一瞬出ます | 利用者の記録の `source.rpcId` と送信の `requestId` を照合して重複を除きます。同じ本文の別送信は残し、実 DSH で DOM 更新と描画フレームごとに重複がないことを確認しました | 段階 6-A、取り込み済み | | timed 質問が期限で消える一方、非表示でも待機を保持し続ける場合がありました | 表示中だけ保持し、「あとで」・別会話・ページ離脱では解放します。期限後は `continued` の投影から復元して回答します | 段階 6-B、取り込み済み | | 返信取消で復帰したカードを古い回答応答が消していました | 回答の世代を識別します。実 DSH で別 Client の取消、旧応答の到着、答え直しのモデル到達を確認しました。現行 UI に返信取消ボタンはありません | 段階 6-B、取り込み済み | | 画像を読み直し続け、Blob URL の取得が失敗しました | 安定しない RPC オブジェクトの同一性を読み込みの依存にしないよう、ファイル画面の再取得を修正しました。画像の全バイトと寸法を実 DSH で確認しました | 段階 5、取り込み済み | | 整数に近い小数を画面が受理していました | `1.000000001` などを実物と同じ刻み判定で拒否します。実物の Schemastery を直接読み込み、有限の数 40 通りで本体と結果が一致することを確認しました。全数値の網羅ではありません | 段階 6-C、取り込み済み | | ゴールが Agent 準備前の読取り失敗から自動復帰しない場合がありました | `api-session/added`、`api-session/error`、接続・投影などの状態通知を使います。準備確認前は操作を無効にし、タイマー再取得は行いません | 段階 6-C、取り込み済み | | 通知の集中でゴールの読取りが同時に増えていました | 同時読取りは 1 件までにし、進行中の通知を完了後の 1 回へまとめます。その再取得中の通知も同じ規則で扱います。失敗後の再取得、外部での版更新、停止後の通知・遅い応答を単体・偽画面で確認しました | 段階 6-C、取り込み済み | ## 仕様と実物の差 [docs/ui-spec.md](ui-spec.md) は今回変更していません。以下は自動的に仕様変更したものではなく、**利用者が決める必要があること**です。 | 項目 | 確認した動き・制約 | 決めること | |---|---|---| | 再接続のバナー | 0.2.0-rc.2 でも Host 停止中は `connecting` のまま再試行し、進捗バーが続きます。統合試験の観測時間内にバナーは出ません。Host 復帰後の自動再接続は成功しています | 長い再接続をバナーへ切り替える時間、古いデータと手動再接続の案内を決めます | | 実行中のアーカイブ | `stopActivity` なしでは `workspace/session-active` で拒否されます。自動停止は加えず、止めてから再試行する案内だけを追加しました。実 DSH でこの UI 操作の再現は未実施です | 自動で止めるか、確認を出すかを決めます | | 完了して未読 | 標準画面と同じく、観測した実行状態の変化から計算します。起動時の待機中の一覧は未読にせず、会話を開く・再実行する・削除すると消します。保存しないため再読み込み後は引き継ぎません | 端末間や再読み込み後にも未読を保持するかを決めます | | 設定項目・反映時期 | 新名前空間の公開項目だけを扱い、`autoGenerate: false` は汎用フォームに出しません。既存の専用画面は維持し、反映は `live` のみです | 仕様書の旧名前空間と再起動後の反映の説明を、今後どう改訂するかを決めます | | アカウントでのログイン | 利用可能なアカウント提供元だけを表示する処理があります。ログイン、解除、失効、ログイン要求の画面は未対応で、ログイン済み実機も未検証です | M3E にアカウント操作を追加するかを決めます。通常の Host へのログインとは別です | | V4 で増えた記録 | `developer/message` のツール増減は読み飛ばします。標準画面には文脈として表示があります。`forked` は終了境界として扱い、専用の理由表示は足していません | ツール増減や分岐終了の表示を追加するかを決めます。未知ブロックは既存の非対応表示、未知イベントは読み飛ばしです | | モデル選択シート | 開いている間に提供元やモデルの設定が変わっても、開いた時点の一覧を表示します。移行前からの動きで、今回は直していません。閉じて開き直すと更新されます | シートを開いたまま候補を更新するかを決めます | | 期限つきの質問 | 待機保持と期限後の回答は対応済みですが、残り秒数・期限は表示しません。いつ AI が続行するかが分からず、`continued` と未続行の質問が同じカードに見えます | 残り時間、AI の続行状態、入力後の待機延長をどう案内するかを決めます | | native のフォルダ選択 | OS のダイアログを選ぶ Host では、ブラウザのフォルダ一覧を使う経路が拒否されました。統合試験は browse に限定します | ローカルの native 方式も M3E で扱うかを決めます | `?mock&scenario=disconnected` は状態を直接作る偽データです。実 DSH の Host 停止時に同じ状態へ移る証拠にはなりません。認証失効時の接続状態も未検証です。 ### 既知の制限と最後に確認すること **ゴールの読取りの応答が止まったままになると、そのあとの通知でも復帰しません。ゴール画面に入り直すと回復します。** 同時読取りを 1 件に制限しており、次の読取りは先行する応答を待つためです。偽 RPC の応答を保留して再現しました。実 DSH のネットワーク障害での再現は未検証です。画面終了時は遅い応答を適用せず待ちを破棄しますが、開始済みの通信自体の取消は追加していません。 段階 6-C の数値・ゴールの本体修正、旧プロフィール項目 `maxRetries` / `provider` / `maxRetryDelayMs` の拒否、設定と一覧の連動・配列・版の偽契約は取り込み済みです。停止後の通知、読取り失敗後の待ち、外部のゴール更新を見逃す試験も強化し、独立した再確認を通しました。 最終レビューと最後の全体監査への本体修正、修正後の独立した読むレビューは完了しました。追加試験の独立した変異の当て直しも完了し、生存した変異は 0 件でした。指示役は、文書を取り込んだ `ab5c09d` で、型検査・単体・ビルド・偽データ e2e と、実 DSH の 3 回連続の実行を確かめました。この移行は、PR #19 として main にマージ済みです(`b895500`)。上の制限と[意図した簡略化](#偽データの決まりと意図した簡略化)は残ります。指示役が自分で差分を適用した 3 コミットの扱いも、引き続き利用者の判断待ちです。経過は [99 の実装メモ](design/99-integration.md#2026-10-04dsh-020-rc2-への移行) を参照してください。 ## 実 DSH の統合試験 `e2e-dsh/` は実物の DSH Host と通信の部品、ビルド・pack した M3E を、Chromium から操作します。**LLM だけは偽物です。本物の LLM の動作を保証する試験ではありません。** 初回の DSH 取得には npm を使いますが、LLM の接続先はローカルです。 ### 集計 | 確認時点 | 通常の成功 | 既知の差の期待失敗 | 実行・根拠 | |---|---:|---:|---| | 移行前 `413a857` から 0.2.0-rc.2 へ接続 | 0 件 | 0 件 | 全 15 件のうち最初の 1 件が起動で失敗し、残り 14 件は実行されませんでした。期待失敗として扱ったものではありません | | 追加試験込み `46ec172`(文書の取り込み後の `ab5c09d` で実行) | 33 件 | 1 件 | 全 34 件。指示役が 3 回続けて実行し、毎回同じ内訳でした | 指示役は、その前の `52c2297` と `ecffe8b` でも実 DSH を 3 回ずつ続けて流し、毎回同じ通常成功と期待失敗の内訳を確認しています。 期待失敗は Host 停止中のバナーの既知の差です。Playwright の `passed` には「失敗すると宣言した試験が失敗した」場合も入るため、通常の成功と分けて読みます。 ### 仕組みと実行 - [fake-llm.ts](../e2e-dsh/fake-llm.ts) は `/v1/messages` に応答し、`message_start`、`content_block_*`、`message_delta`、`message_stop` の SSE を返します。ツールは `tool_use/tool_result`、画像は `image` ブロックで到着を確認します。ブラウザへ流れる V4 の `role: 'tool'` とは別の形式です。 - `[[slow]]`、`[[medium]]`、`[[approval]]`、`[[question]]` で応答を選びます。`holdTurn(prompt)` は指定した会話の進行を試験から解放できるようにし、順番待ちはターン終了後、割り込みは同じターンの次ステップに届くことを区別します。 - [dsh-host.ts](../e2e-dsh/dsh-host.ts) は `tmp/dsh-integration/` 配下に毎回新しい `HOME` と `DSH_HOME` を作ります。Host と偽 LLM は `127.0.0.1` の空きポートを自動で使い、Host の再起動は同じポートとホームを使います。固定の Vite ポートは使いません。 - Host に `DEEPSEEK_BASE_URL` と試験用の架空の API キーを渡します。`SSH_CONNECTION` の印で `browse` を選びます。SSH 接続を実行するものではなく、macOS / Windows の native ダイアログを避けて遠隔 Host のブラウザ操作を確認するためです。自動ブラウザ起動の抑止と open-in-app 候補が空になる副作用もあり、それらの経路は検証対象外です。 - [fixtures.ts](../e2e-dsh/fixtures.ts) で Host を worker 内で共有し、`workers: 1`、再試行なしで実行します。新しい spec は他の spec の会話を前提にせず、必要な会話を自分で用意します。 - 期限つき質問の spec は [timed-questions-fixtures.ts](../e2e-dsh/timed-questions-fixtures.ts) から別の Host を起動し、`startDsh(llm.url, { timedQuestionSeconds: 2 })` を使います。隔離ホームの `cordis.patch.yml` に専用 preset を作り、`dsh-tool-ask-user` を `mode: 'timed'`、`timeout: 2` にします。これらは公開設定ではないので起動前に設定します。追加の環境変数は不要で、通常の legacy 質問の Host と分けます。 ```bash env M3E_DSH_VERSION=0.2.0-rc.2 pnpm exec playwright test -c e2e-dsh/playwright.config.ts ``` | 環境変数 | 用途 | |---|---| | `M3E_DSH_VERSION` | 試す版。省略時は `SUPPORTED_DSH_VERSION` | | `M3E_DSH_DIR` | 入れ済みの DSH のディレクトリ。`node_modules/.bin/dsh` を含む場所です | | `M3E_SKIP_BUILD=1` | 既存の明示的 build だけを省きます。pack と、その prepack の build・検査は必ず行います | | `M3E_CHROMIUM_PATH` | Chromium の実行ファイル。偽データ e2e にも使えます | `fixture-contract.spec.ts` は DSH の検査関数を既定の `tmp/dsh-integration/dsh-<版>/` から読みます。`M3E_DSH_DIR` を使って Host の場所を変えても、この spec の参照先は変わらないため、全体を実行するときは既定の場所にも同じ版が必要です。 `pnpm test` には含めていません。結果は `tmp/dsh-integration/report.json`、失敗時の trace などは同じディレクトリの `results/` に出ます。再実行前に必要な証跡を保存してください。起動処理は以前の `run-*` を整理するため、長期利用したホームの検証にはなりません。試験は中断せず終了処理まで待ちます。 ### 確かめた経路 | 経路 | 実 DSH と偽 LLM で確認した内容 | 根拠 | |---|---|---| | 起動・埋め込み拒否 | `/m3e/` の一覧、index のヘッダー、iframe の表示拒否 | `real-dsh.spec.ts` | | ワークスペース | browse のフォルダ選択から追加 | 同上 | | 会話・履歴 | 初回送信、LLM への本文到着、返答、再読み込み後の履歴と題名、会話切り替え | 同上 | | 逐次表示・停止 | 途中の返答、停止時の LLM 接続切断、以降の表示停止 | 同上 | | 承認・質問 | 会話から許可・拒否・回答し、結果が LLM に戻ること | 同上 | | 順番待ち・割り込み | 待機表示、本文、モデルへ届くターン・ステップの違い | 同上。`holdTurn` で区別します | | 画像送信 | Messages の画像ブロックが LLM に届くこと | 同上 | | 再接続 | Host 停止中は送れず、復帰後は自動再接続して送れること | 同上。バナーの差は期待失敗として別集計です | | 参照の引き継ぎ・復帰 | 初回送信の参照を画面へ引き継ぐこと、送信中に離脱したときの解放、`pagehide/pageshow` 後の送信 | `session-contract.spec.ts`。Safari の実際の BFCache は未検証です | | V4 表示 | 承認・質問の結果本文がチャットとトレースで見えること、呼び出しと結果の結合、注入文脈と自分の発言の区別 | `records-v4.spec.ts` | | 設定・モデル | 公開スキーマの独立照合、共有入力の受理・拒否、辞書キー、整数付近の小数・旧プロフィール項目の拒否、シェル設定の保存・再読、提供元・モデル一覧 | `rpc.spec.ts`。画面の数値検証と RPC への直接入力は別です | | 権限 | 既定値の保存、新規会話への適用、会話内の切り替え、自動候補の追加・削除通知で開いたシートが更新されること | 同上 | | ファイル | 一覧、本文、分割読込みした画像の全バイトと寸法、範囲の引数、負数範囲の拒否、ファイル・フォルダ自身の変更後の版 | 同上。`ready` 後の最初の通知だけで成功扱いにしません | | API キー | 隔離ホームの架空値の登録・削除と再読み込み、別ページへの `reference-updated`、環境由来の変更不可表示 | 同上。`record-updated` は購読登録までで、自然発火は未検証です | | 発言の重複除去 | 送信中の表示を実際に観測し、確定まで DOM 更新・描画フレームごとに自分の発言が重ならないこと | `submission-overlap.spec.ts`。準備済みの通常会話への送信です | | 偽記録の実物照合 | 全 fixture と不正入力を V4 admission、復元、Session、commands / compaction の検査で照合 | `fixture-contract.spec.ts`。実物の検査関数を使いますが、偽記録の全経路を Host 上で生成する試験ではありません | | timed の保持・期限後の回答 | 表示中は Host の期限を越えて保持し、回答はツール結果として届くこと。ページ離脱後の期限切れでは、戻って回答が利用者メッセージとして届くこと | `timed-questions.spec.ts` | | 非表示の timed 質問 | 「あとで」と別会話への切替で保持を解放し、期限後に復元して回答できること | `timed-questions-hidden.spec.ts` | | timed 回答と取消の競合 | Host 受付後の応答だけを保留し、別 Client からキューを取り消してカードを復帰。旧応答の到着後も行が残り、答え直しがモデルへ届くこと | `timed-questions-race.spec.ts`。対応待ちの行から回答します。取消自体は別ページの実 RPC で行います | ### 偽データの決まりと意図した簡略化 **偽データは、画面が使う境界では実物と同じ厳しさで動くことを原則にします。** 成功する形だけでなく、拒否する入力、準備待ち、参照の寿命、取消、通知、後着応答も写します。厳し過ぎて実物の合法な操作を拒否する差も修正対象です。以下の例外は、実物と一致したという根拠には使いません。 | 偽物 | 写している実物と確認方法 | |---|---| | `web/src/dsh/mock/context.ts` と周辺 | session controller と gateway の参照・scope・cold/loading/open、保存済み会話と Agent の分離、送信観測と退役、通知の Context・取消寿命、inbox、ジョブの所有者を写します。`questions.ts` は実物の timed の保持・期限・遅延回答、`fork.ts` は開いた tool/step/turn の補完を写します | | 各機能の偽記録 | V4 の値・参照・前後関係、commands と compaction の規則を写します。静的な表示見本だけでなく動的なコマンド・モデル選択・fork も検査します。[V4 規則の対応表](../tests/helpers/s6b-v4-rules.md)、独立した不正入力、実物による検査を使います。履歴が欠けて検査対象が空になることも拒否します | | 設定の `mock-fixtures.ts` / `mock-validation.ts` と偽 RPC | 実在する名前空間の公開 schema・主要制約・`autoGenerate`、書込みの受理・拒否を写します。架空の汎用フォーム見本は `example-extension` に分離します。期待側を本体の decoder と共有せず、実 DSH と同じ入力表で比較します。配列操作は全操作後の値を検査し、初期版 0・無変更保存・版指定の省略、設定と提供元・モデル・権限の連動も写します | | `features/session-tools/mock-files.ts` / `mock-goals.ts` | ファイルは保存済み会話の作業フォルダを解決し、範囲の省略と `null` を区別します。ゴールは Agent の利用可能性を確認し、activation の変化があるときだけ通知します。両者の準備条件を同一視しません | 下表の番号は偽データ総点検の監査 A・B・C の指摘番号です。「妥当」はレビュー時点の現行画面の用途に限る判断です。段階 6-C のレビュー・再確認で残した差を、統合後のコードと照合しています。C-M6 のモデル選択記録と C-m4 のパンくずは、6-B の修正が取り込まれているため、下表では解消した部分を区別します。 | 対象 | 意図した簡略化・実物との差 | 見逃し得る誤りと使える範囲 | |---|---|---| | A-9:画像 | 正規 Base64、形式・枚数・容量・寸法上限は検査しますが、完全復号、CRC、再符号化、hash は省きます | 破損画像や正規化・画像識別の誤りは保証できません。本体の `prepareImage()` はブラウザで復号しますが、実画像での確認も必要です | | A-13:検索 | イベント単位、会話ごとの代表一致、Unicode code point 単位の抜粋は合わせ、順位は出現回数で代用します | 実 FTS の順位・スコアへの依存を見逃します。検索結果の表示・遷移には使えますが、検索品質の判定には使えません | | A-14:通知 | lifecycle の集約と listener の例外隔離は写し、正確な frame の選び方は省きます | 描画との厳密な順序や通知回数への依存は実通信でも確認します | | B:表示用の見本 | 空の stream、固定本文・価格、未知 producer の例、continued の即時取り込み、固定したコマンド一覧を使います | 実際の生成時機・価格・拡張プラグインの全能力は保証しません。表示見本と、controller を通る操作試験を分けます | | C-M1:提供元固有の検証 | headers、モデル定義、互換設定などの意味検証は一部だけです。廃止されたプロフィール項目の拒否は修正済みです | 複雑なプロフィールを組み立てる誤りを見逃します。現行画面は内部構造を汎用編集しません。編集範囲を増やすときは実物との照合も増やします | | C-M2:JSON 全体 | 未知項目・custom の内部について、JSON として渡せない値(非有限数など)の検証を省きます | 任意の要求値の組立て誤りを見逃します。現行の数値入力は有限性を検査し、複合値は読み取り専用です | | C-M4:保護された設定 | 標準 fixture は password 表現を使い、保護状態の sidecar、`hasDocument`、伏せ字を完全には写しません | sidecar による表示・reset 保護を落とす誤りを見逃します。別の単体試験で保護を確認しており、標準 fixture だけで契約一致とはしません | | C-M5:モデルの解決 | 一覧と設定は連動しますが、組込みカタログ、利用可能性、外部照会・解決失敗・再登録の全過程は簡略です | 利用不能な経路、外部取得失敗、登録解除や上書き設定への追従を見逃します。固定した成功候補以外は実物・専用の失敗入力で確認します | | C-M6:モデル選択の保存・再生 | `composer/mock.ts` は `model/selection` を追記して投影を更新し、既定モデルを背景で直列保存します。この部分は 6-B と統合済みです。ディスクへの永続化と再起動後の再生は再現しません | 記録の追記がないという旧報告は現在には当てはまりません。実保存からの選択復元は、偽データだけでは保証できません | | C-M10:ゴールの記録 | `mock-goals.ts` は投影を直接更新し、`goal/change` の記録を追記しません | 履歴表示、記録からの再投影・再起動後の復元、記録と投影の不整合を見逃します | | C-M7・M8:登録とファイル | 自動権限候補の登録・解除は試験用の入口で模擬し、ファイルは作業フォルダごとの小さな固定木です | 実プラグインの寿命・入替え、作業フォルダ外の絶対ファイルや OS 例外の扱いは保証できません | | C-M11:版と通知 | 名前空間・スキーマ・実体の交換による版や通知は省きます | 再登録時の再取得漏れを見逃します。通常の保存・再読が通っても再登録の証明にはなりません | | C-m1:設定の層 | 継承値との単純マージ、optional な `null`、reset 後の層の正規化を簡略化します | 複雑な継承設定の復帰不良を見逃します。現行画面は返却値を読み、未設定には `unset` を使います | | C-m2:失敗の詳細 | 一部の失敗分類・details は完全には一致しません | 偽物固有のエラーへの依存を見逃します。現行の対象画面には、その details に依存する分岐はありません | | キー・OS・試験用の入口 | キーは登録有無だけを保持し、OS のファイル監視開始を即時化します。失敗・遅延・状態の固定注入は偽物専用です | 保存・OS 監視・実際の通知順を保証しません。現在の画面が呼ばない RPC も省略しています | | 旧バイト範囲の拒否 | 実物は旧形式の平らな範囲指定を無視して全体を返しますが、偽物は明示的に拒否します | 旧呼出しの退行を早く検出するための意図した厳しさです。実物が同じ拒否を返すという証拠には使いません | C-m4 のパンくずは、統合後の `features/home/directory-mock.ts` で `hidden: false` にそろっています。別ブランチの古い残件を、現在の簡略化として残していません。 ### 試験の強さの確かめ方 移行では、読むレビューに加え、**本体や偽 controller を一時的に壊し、対象の試験が落ちることを確かめる監査**を行いました。成功件数だけでは、準備を通っていない試験や、別の文字列を拾って通る試験を見つけられないためです。 下表は段階ごとの独立監査の初回集計です。調べる対象になった試験の延べ数で、変異の個数や現在の全試験数とは異なります。「直した」は初回に生存した試験を強化して検出を確認した件数で、本体の不具合件数ではありません。 | 段階・監査 | 対象の試験 | 初回に落ちた(検出) | 初回に生存 | 直した | 未決・未実施と再確認 | |---|---:|---:|---:|---:|---| | 3:M1〜M3(参照・送信・画面) | 322 | 302 | 20 | 20 | 初回の未決・未実施なし | | 4:M4(V4 記録) | 34 | 29 | 5 | 5 | 同上 | | 5:M5(RPC) | 51 | 47 | 4 | 4 | 生存した変異の再検出を確認しました | | 6-A:M6A(偽 controller) | 65 | 63 | 2 | 2 | 子孫の活動と検索代表の検査を強化しました | | 6-B:M6B(偽記録・質問) | 33 | 27 | 6 | 6 | 初回の弱点を修正。追加の再確認で見つかった穴も別に直しました | | 3〜6-B 小計 | 505 | 468 | 37 | 37 | 初回の生存分は修正済みです | | 6-C:M6C(設定・ゴール) | 35 | 31 | 0 | 初回生存分なし | 初回は適用待ち 3、未決 1。適用待ちは後の再確認で検出を確認。未決は RPC 直接入力が画面の検証を通らないためです | 初回の対象は合計 540 件ですが、未決・未実施をすべて検出済みとして扱いません。再確認で追加した変異は重複を避けて上表へ加算していません。段階 3 の親 ID、段階 4 の本文可視性、段階 5 の設定受理・辞書キー・通知処理、段階 6-B の V4 規則や回答競合でも穴を直しました。 段階 6-C の再確認は、次のように試験の抜けを強化し、同じ変異で検出を確認しました。この表の単位は**変異の種類**で、上表の対象試験数とは異なります。再確認間にも重複があるため合算しません。 | 再確認 | 調べた変異 | 落ちた(検出) | 生存 | 生存分の修正・再検出 | |---|---:|---:|---:|---| | 1 | 22 | 20 | 2 | 権限候補の再取得だけの欠落、終了時のタイマー取消の欠落を強化し、再確認 2 で 2 種類とも検出しました | | 2 | 11 | 10 | 1 | ゴール画面からの終了処理の欠落を強化し、再確認 3 で検出しました | | 3 | 16 | 15 | 1 | 切断中・削除後の activation 通知を排除する検査を強化し、再確認 4 で検出しました | | 4 | 11 | 8 | 3 | 例外・`ok:false` 後に待ちを捨てる 2 種類と、ゴールの id・revision への追従を失う 1 種類を強化しました | | 5 | 3 | 3 | 0 | 再確認 4 で生存した 3 種類を当て直し、取得回数と画面操作の可否の検査で検出しました | 再確認 1 は 22 種類を延べ 26 回実行した記録です。途中のタイマー方式は、その後の本体修正で状態通知方式へ置き換えました。段階 6-C の blocking は解消しましたが、[応答停止時の制限](#既知の制限と最後に確認すること)は残ります。 最後の全体監査と `ecffe8b` に対する受け直しも完了しました。次の表は**変異を当てた回数**で、上の対象試験数とは単位が異なります。受け直しには同じ変異と追加の境界入力が含まれるため、初回と合算しません。 | 全体監査 | 当てた回数 | 検出 | 生存 | 動きが変わらないもの | |---|---:|---:|---:|---| | 初回(本体) | 57 | 51 | 5 | 等価 1 回 | | 受け直し(対象 24 試験) | 42 | 36 | 0 | 6 回はその境界入力では動作差がない組み合わせ。未決・未実施なし | 初回に通ったのは、ジョブの購読解除、ジョブの表示順、ゴールのラウンド上限ちょうどの判定、操作中・添付不正の 2 種類のエラー案内です。5 か所の試験を `ecffe8b` で強化し、同じ変異の再検出を確認しました。初回で実 DSH が初めて検出したのは、停止呼出しの削除と権限候補の更新通知の無視です。既知の差の期待失敗は検出数に含めていません。レビューと修正の経過は [99 の実装メモ](design/99-integration.md#2026-10-04dsh-020-rc2-への移行) にまとめています。 権限シートの重複を直した `54b55db` は、新しいセッションの読むレビューで blocking 0 件・major 0 件でした。変異 8 種のうち 7 種を検出し、1 種が通りました。「開いている途中」の印を描画のたびに作り直す変異で、連打の間に再描画を挟まない試験が弱かったためです。本体は正しく印を保持しています。`46ec172` で既存会話・新しい会話の各 1 件に本文入力と再描画を挟む試験を追加し、実装役は同じ変異で 2 件とも失敗を確認しました。別の新しいセッションでも同じ変異を当て直し、追加した 2 件がシートの枚数の確認(期待 1 枚、実際 2 枚)で落ちることを確かめました。生存した変異は 0 件です。 読むレビューだけでは見つからなかった例です。 - 偽履歴の初期化を壊して対象が消えても検査が通りました。対象集合・件数と必須の履歴を独立に要求し、空のループを成功にしないよう強化しました。 - API キーの `record-updated` は購読登録だけを調べていました。処理を空にしても通ったため、この通知だけを届けて表示と再照会が変わる試験を加えました。自然発火の未検証は別に残します。 - 子孫の稼働確認を消しても、同時に置いた実行中ジョブがアーカイブを拒否して通りました。子だけ・孫だけ・所有ジョブだけの条件を分け、各条件の欠落を検出します。 次回も、追加した試験と入力・期待を変えた試験ごとに、次の手順を行います。 1. 通常状態での成功と、確かめる動きを確認します。監査用の隔離 worktree を使い、既存の未コミット変更を巻き戻さないようにします。 2. 最小の変更を本体か偽 controller に当てます。準備の空振りを調べる場合は、データ投入や操作を一時的に省きます。 3. 対象ファイルや試験名に絞って実行します。型エラー・読み込み失敗・無関係な時間切れは検出に数えません。 4. 通った場合は「空振り」「一部の確認が弱い」「動きが同じ変異」「別の試験が担当」を分けます。動きが同じなら別の変異で試します。 5. 強化後に、生存したのと同じ変異を当て直して失敗を確認します。表示試験は本文の一致と、その本文の要素が見えることを確かめます。通知は登録数だけでなく、受信処理から表示更新まで要求します。画面の検証を壊す変異に、RPC へ直接入力するだけの試験を割り当てません。 6. 一時変更だけを `git restore <対象ファイル>` で戻し、差分と通常実行を確認します。試験名・変異箇所・狙った失敗・復元結果を記録し、変異はコミットしません。 7. blocking の修正後は、新しいセッションの独立したレビューか再確認を通してからマージします。元の変異の当て直しに加え、別の変異も試し、統合後の境界も確認します。 ### 偽データでしか確かめていないもの 次は単体試験や `?mock` の確認が中心で、実 DSH の対応する操作全体は未検証です。 - 実際に生成したサブエージェントへの送信、子カタログの競合・拒否・再試行、統計、ジョブの購読・停止、ゴールの操作。 - 会話の分岐、手動の題名変更、アーカイブ、ワークスペースの名前変更・並べ替え、検索の結果と抜粋、完了未読の表示と消去。 - プラン確認、対応待ちからの承認、トレースからの承認・質問への回答、応答が失われたときの「送信結果が不明です」。対応待ちからの timed 回答は上の実 DSH 試験に含まれます。 - `record-updated` 単独での画面更新、質問の複数同時待ち・再接続相当の channel 交換、各種の失敗・遅延注入。実 DSH の質問の取消競合を確認しても、通信断中の回答配送全体まで確認したことにはなりません。 - `developer/message`、`forked`、未知の `plugin:` 拡張、compaction の発生時の表示。古い記録の移行・検索 index・ページング全体も未検証です。 - 監視非対応、writer-held、投影不能、モデル不能などの実際のエラー発生。再接続後に生成途中の応答が続く経路も、復帰後の新規送信とは別に残っています。 偽 controller と実物の差は [意図した簡略化の一覧](#偽データの決まりと意図した簡略化) を参照してください。ゴールの準備失敗・遅延、通知の集中、読取り応答の停止も、実 Host に故障を注入した確認は未実施です。 ### 人が実機で確かめるべきもの - 利用する Host の `dsh --version` が対応版であること。本番や利用者の DSH の更新・確認は隔離試験に含めていません。 - iPhone の Safari とホーム画面の Web アプリで、キーボード、シート、画像、送信・停止、再接続、期限つき質問の非表示・復帰・回答を操作すること。特に別ページから「戻る」で **実際の BFCache から復帰**した後に、参照が戻って送れること。 - TLS やリバースプロキシを挟んで `/m3e/`、`/plugins/…`、`/api/…` が通り、WebSocket と埋め込み拒否のヘッダーが保たれること。 - 本物の LLM の長い返答、考えた内容、複数ツール、途中のエラー、サブエージェント。実 API キーによる外部接続とログイン済みアカウントも未検証です。 - 長期利用した `DSH_HOME` の多数の会話と古い記録、Windows のシェル、native のフォルダ選択を使う構成。 ## 版を上げるときの手順 1. 対応版、起点コミット、既知の差、通常成功と期待失敗を記録します。利用者の DSH を使わず、`e2e-dsh` の隔離環境で新しい版を試し、最初に止まる境界を記録します。 2. 共有ライブラリを照合し、`package.json` と `src/shared/dsh-compat.ts` を同時に更新します。loader の待機・失敗処理も確認します。 3. 起動グラフ、preload、``、RPC・WebSocket・画像の宛先を確認します。`/m3e/` の遷移、空の Markdown リンク、戻る・再読み込み、PWA scope も確認します。 4. 実 DSH 試験の前提を確認します。LLM の接続形式、SSE、ツールと画像の形式を実物に合わせ、フォルダ選択の native / browse を確認します。環境の差を API の破損と取り違えないようにします。 5. セッション controller の型・実装を照合し、参照の所有、ready の成功・失敗、解放、一覧と投影、ジョブを移行します。偽 controller も公開契約に合わせ、非同期の準備・中断・後着応答を確認します。 6. 会話の記録を実際に受信し、チャット・トレース・偽記録を合わせます。その後、設定、権限、提供元、ファイル、通知の RPC を照合します。共通の参照契約が安定すれば、記録と RPC は独立した worktree で進められます。 7. 実物を読むときは対象パッケージ・ファイルを限定します。保護対象のパスにあるパッケージは読まず、許可された呼び出し側と隔離環境の動作で確認できる範囲を記録します。内部の保存形式や通知の引数を推測で埋めません。 8. 偽 controller・全機能の記録・設定を分けて総点検し、実物の拒否・寿命・通知を照合します。偽記録には独立した不正入力と実物の検査を当て、設定は共有入力を両方へ送ります。意図した簡略化と、そのために見逃す誤りを一覧に残します。 9. 読むレビューに加え、上の[試験の強さの確かめ方](#試験の強さの確かめ方)を実行します。成功件数が維持されても、確認が失われていないかを壊して確かめます。blocking の修正後は独立した再確認を受け、統合後にも全体から抜き取って監査します。 10. 統合したコードで `pnpm typecheck`、`pnpm test`、`pnpm build`、偽データ e2e を通し、実 DSH を連続して確認します。コマンドは [development.md](development.md#試験の使い分け) を参照します。期限つき質問は専用 preset の Host で確認します。削除・skip・条件の緩和で件数をそろえません。 11. この文書の集計表を更新し、README の各言語と引き継ぎから参照します。仕様との差、未検証、実機で利用者が判断することを残します。文書だけの修正では試験・ビルドを再実行せず、根拠・リンク・差分を確認します。