# 更新履歴（日本語 changelog）

- [更新日志（中文）](./CHANGELOG.md)
- [Changelog (English)](./CHANGELOG.en.md)
- [日本語 changelog](./CHANGELOG.ja.md)
- [한국어 changelog](./CHANGELOG.ko.md)

> **互換性の注意**：本プラグインは日本語ドキュメントを提供しますが、公式 DSH の `LocaleRuntime` が登録する言語は `zh` / `en` のみです。`ja` を選択すると `locale "ja" is not registered` となります。DSH を fork して `LOCALE_IDS` と `LOCALES` ラベルを更新し再ビルドすることで利用可能になります。

本ファイルは **0.12.0** リリースノートと現在の**未リリース**変更の日本語版です。全履歴は [CHANGELOG.md](./CHANGELOG.md)（中文）を参照してください。

## [0.26.11] — 2026-10-27

> 外部 issue #12 / #13 / #14 / #16 をまとめて解消。0.26.2〜0.26.10 の詳細は中国語版 CHANGELOG を参照（本ファイルは意図的に遅れています）。

### 修正
- `memory_room_review` が二階層 Room slug（`major/minor`）を受理するように（候補解析と `confirmReview` の両方）。注釈プロンプトも二階層を教えるよう修正。
- 再構築で、L0 廃止後に取り込んだ記憶が失われないように。取得元メッセージが今回のスナップショットに無いレコードは新しい `post-watermark` 理由で保全（時刻しきい値ではなく集合判定）。

### 追加
- 知識グラフの投影を概览パネルから切替可能に（`live.graphEnabled`、`graph.enabled` と OR）。初回有効化の前に未投影件数からコストを提示。

### 変更
- `workspaceSource.routes` の既定値を `[]` に変更（旧既定に依存する場合は `{path, anyOf}` を自前で設定）。
- 再構築に二段のゲートを追加：L0 に本文が無く検索庫が空でない場合は停止、水位より後のレコードが半数超なら `force` で再確認。

## [0.26.1] — 2026-10-15

### 追加

- **回填パネル「進行の自動復帰 + スキャン進捗 + 正直な要約」**：3 つの回填エンドポイントは「トリガー + 状態照会」の二合一で、アイドル時の裸呼び出しは**本当に走り出す**。新リクエストボディ `BackfillTriggerRequest { probe?: boolean }`——`probe:true` は現スナップショットのみ返し絶対に起動しない。`BackfillSection` はマウント時に resume で 3 つを偵察し、走っていればポーリングを再接続（概要区を離れて戻っても手動クリック不要）。`BackfillProgress` に `scanned/scanTotal` を追加（「ストック 1252/1252 行をスキャン中…」）；候補 0 のときは「キーワード欠落の記録なし、回填不要」のような**正直な要約**を返す（「成功 0 件」が失敗と読まれる問題を解消）。
- **3 つのバッチ操作に「中止」スイッチ（有界強制停止）**：契約に `cancel?: boolean` と `BackfillProgress.cancelled` を追加；各モジュールが `cancelXBackfill()`。中止は**有界**：信号後に一度きりの猶予タイマーが発火し `runAbort.abort()` で在飛リクエストを即断。ハード境界は `backfill.cancelGraceMs`（schema max 30_000、既定 15s）でクランプ——YAML に何を書いても越えられない。
- **スキルツール群の封印 `toolSkills`**：`memory_skill_*` の四件を宿主封印機構（`reg('skills', …)`）へ統合し、機能スイッチ `skillsEnabled` と AND。両方とも `loader/volatile-update` で**ホット反映**（パネルの切り替えが即時登録/解除、再起動不要）。従来は登録時に一度だけ判定し、有効化後は無条件にモデルのツール一覧へ常駐、切り替えてもホット更新されなかった。

### 変更

- **全 LLM バッチを「逐条直列」に統一**：残る 3 つの合併バッチ——wing（`labelWingOne`/`tagOne`）、`pipeline/relabel.ts`、`room-review.ts`（`roomCandidateOne`）——を変換；5 つのバッチ地点すべてが「1 リクエストに 1 件のみ、完了してから次」（`concurrency` 既定 1）。根拠：単条 35B は実測 ~2.6s、一方で複数条バッチは一度の截断/空出力でバッチ全体を失う。
- **整形の除外判定を「バージョン刻印」へ**：`dsh_reshape_ver`（=2）+ `isReshapedAtCurrentVersion(meta, content)`——刻印は**書き戻し成功時のみ**打つ；閘を通らなかった記録は原文のまま**マークなし**で次回も再試行可能（旧ブール `dsh_reshape_tried` はストック互換の読み取りのみ）。整形ルール更新時にバージョンを上げれば旧産物を自動再実行。
- **`backfill.maxRecords` 既定 300**（以前誤って 40 にしており、実機 251 件の対象が一回 40 件しか進まなかった）。

### 修正

- **ポーリング裸呼び出しの死循環（「開始しない」の真因）**：UI の tick が「トリガー + 状態照会」二合一エンドポイントを裸で呼び、アイドル時に 3 秒ごとに新一轮を開始、パネルが「スキャン中」のまま。tick を `{ probe: true }` に変更。
- **バッチスキャンの全空出力の真因：思考モデルを直答モデルとして使用**：`LlmCallOptions` に**呼び出し級 `reasoningEffort` オーバーライド**を追加し、5 つのバッチラベラが `'off'` を明示。従来は経路の effort が `""`（自動）だと思考モデルが既定で思考オン、予算を reasoning に食われ本文 0 文字（実機 162 回の失敗中 156 回が `local-9b` の空出力）。
- **`client/src/ui/MarkdownBody.tsx` の typecheck 赤**：0.26.0 が持ち込んだ 4 箇所の `string | undefined`（正規表現キャプチャ）が `noUncheckedIndexedAccess` でエラー、非 null アサーションを追加。

## [0.26.0] — 2026-10-14

### 追加

- **`dsh-memory/records-meta` 端点**：`record_id` の一括照会（≤50）で単条記憶の全量メタデータ＋本文（name/type/priority/content/maturity/createdAt/updatedAt/scene/scope/workspaceId/keywords/usageScenario/filePath/retired）を `stores.l1.getByIds` で SQLite から直接返す。記憶ビューアはこれで **`.memory.md` を読まなくてよい**——以前の fileViewer 方式（`<id>.memory` を偽装）は宿主 EditorHost に物理パスとして解決され必ず ENOENT。契約は `contract.ts`、端点数 62→63（`tests/contract-keys.test.ts` が固定）。
- **表示タイトルを本文から推測しない**：`memoryRecall` と槽位 `refViews` の title は `name`（名称蒸留の短題）を優先し、無い時だけ本文先頭行へ回退。`firstLine()` は markdown 対応になり、H1（`# xxx`）は文書タイトルとして保持、H2+（`## 結論/事実`）は分節マーカーとしてスキップ——以前は明らかに本文の `## 結論/事実` が記憶「名称」として表示されていた。
- **投射パスの単一事実源 `relPathFor()`**：`renderRecord`（ディスク書込）、`records-meta` の `filePath`、槽位 `refViews.filePath` の三箇所が同一アルゴリズムに集約。以前は投射側が独自のサニタイズ正規表現を写しており、同一記憶から二つの異なるファイル名が生じ得た——投射が示すアドレスとディスク上の実ファイルが一致せず、まさにこの三箇所が照合すべき事実そのもの。`refViews` は `filePath`/`workspaceId` も透出し、消費側は `<workspaceId>/.agents/memory/<filePath>`（workspace 範囲）または投射ルート（global）で絶対パスを組む。
- **検索パネルの本文を markdown 化**（client）：RecordsTab の展開本文は新し `client/src/ui/MarkdownBody.tsx`（見出し階層 / 太字 / インラインコード / リスト、外部依存ゼロ）を経由し、`## 結論/事実` は裸のテキスト行ではなくなる。

- **既存記憶の再蒸留整形（`redistill`）**：独立バッチスキャン `src/redistill-backfill.ts`（wing/keyword 回填を镜像：単飛/後台/有界/失敗時原記録不変）が、**アクティブかつ骨格不全**の L1 本文を G2 類型別の「前因後果」分節形式に再編し、同時に `metadata.dsh_keywords` / `metadata.dsh_usage_scenario` を産出。新端点 `dsh-memory/redistill-backfill`（`{started,running,enabled,updated,skipped,failed}` を即返）、パネル（WingWheel）に「再蒸留整形」ボタン。設定 `redistill.enabled` はデフォルト**关**——关時は整形せず content/FTS/投射が逐字不変（ゼロドリフト）。
  - **品質ゲート**：整形後 `scoreSkeleton` の命中数が**厳密に優れる**時だけ書き戻し、整形バージョン `dsh_reshape_ver` を刻印（次回以降は対象外）；未達なら原文を残し**刻印せず**、次回も再試行可能——「見かけ上フォーマット付き」のために偽ラベルを貼ったり捏造したりは一切しない。
  - **アクティブのみ**：退場/取代会済みは対象外。
- **本文変更の永続書込経路**：整形の書込は `L1Store.appendNew` を経由し、JSONL 事実源追記 + 埋め込み再計算 + `l1_fts` 再インデックス + `.memory.md` 投射上書き（エクスポータは库から再レンダし差分があれば上書き）を一度に完了。入口は `vectorsReady()` を要求——埋め込み未就绪時はラン全体をスキップし、ベクトルの静默消失を防ぐ。

### 修正

- **`client-session-recalled-bundle` 回帰ガード**：0.25.0 で「本会話召回」の pill レンダリングを dsh-brief-sidebar へ移管した後、このテストは依然 pill に召回文字列があると主張していた（リリース時の更新漏れ）。現在は prime-memory pill が召回を**重複レンダリングしない**ことを主張し、投影接線の主張は保持。

## [0.25.0] — 2026-10-14

### 追加

- **キーワード蒸留フィッシュバック（`metadata.dsh_keywords` の産出側）**：`l1_fts` に予約された `keywords` 检索軸は産出側がなく休止状態でした。新モジュール `src/keyword-backfill.ts`（wing 回填を镜像：単飛/後台/有界/失敗時原記録不変）で `dsh_keywords` 缺失の存量 L1 を chunk で LLM に贈り、`normKeywords`（≤5、重複除去、長さ鉗制）で正规化して書き戻す。新端点 `dsh-memory/keyword-backfill`、パネル（WingWheel）に「キーワード回填」ボタン。設定 `keyword.enabled` はデフォルト**关**——关時は回填なし、`l1_fts` 逐字不変（ゼロドリフト）。
- **`patchMetadataAndReindex`**：`patchMetadata` は `l1_records` のみ更新し `l1_fts` に触れないため、これで回填すると BM25 に永遠に見えない。行別 FTS 重索引（MemoryDb→L1Store→backend→InProc/Worker→worker 分派を貫通）を追加し、新キーワードが即座に检索軸に入る。テストは反向対照（純 patchMetadata は不命中 / AndReindex は命中）入り。

### 変更

- **输入区ポップアップで本会话召回リストの描画を廃止**：WingWheel から `SessionRecalledArea` を除去——召回表示は brief-sidebar が接管済みのため重复排除（コンポーネントファイルはロールバック用に保持）。

## [0.24.2] — 2026-10-14

### 追加

- **レコードパネルの投射アイデンティティ項目**：カードヘッドに「名称」「スコープ」バッジを追加、展開詳細に3行（名称 / キーワード / スコープ）を追加し、「記憶↔投射ファイル名」の対応を直接確認できるようにした。`UiRecord` 契約（`contract.ts`）にオプションの `name`/`scope`/`workspaceId`/`keywords` を追加、`stats.ts::hitToUiRecord` がレコード本体と `metadata.dsh_keywords` 予約キーから読み出す。
- **FTS キーワード独立検索軸（予約・休止）**：`l1_fts` を「keywords → content」の2列インデックスに並べ、キーワードを本文の語頻と混ざらない独立 BM25 軸として予約。現状は蒸留の産出側がなく当該列は常に空 ⇒ 検索挙動は改修前と逐字同一（ゼロドリフト）、蒸留実装時は表構造の変更不要（FTS5 は ALTER 不可）。

### 変更

- **フック収束コメントの整理**：退役した旧ファクトリ名 `makeSuffixSync` のリテラルが `src/` から消え（検収 grep ゼロ）、収束結論は単一の事実源のみ。

## [0.24.1] — 2026-10-14

### 追加
- **接尾語の不変式収束（`convergeDisabledSuffix`）**：`.memory.md` / `.memory.md.disable` は「その記録がライブラリで退場済みか」だけで決まる。`name` とも、どの経路で退場させたかとも無関係。各件を「ファイル存在 + 現在の接尾語 + 指紋一致」の三条件で照合する。人が作った `.disable` はファイル側の退場証拠なので ``both`` と報告するだけ。
- **ライブラリ→ファイルの鈎子を `L1Store` に集約（`store/memory-md-sync.ts`）**：`appendNew` / `retire` / `restore` / `rename` の四つの合流点で `setFileSyncHook` を発火。これまで 8 か所の呼び出し点に散っていたイベント鈎子は実測 920 件中 8 件しか `.disable` を作っていなかった（リコールパネルの 1 経路のみ）。機械側の退場（統合置換・衝突敗北）もモデル側 `memory_add` も自動的に追随する。
- **リネーム追随**：`rename()` 後に投射ファイルを新名へ移動（`.disable` も一緒に）、台帳キーも差し替え。旧パスに無い場合は新名で書き出し、移動先が埋まっていれば上書きせず報告のみ。
- **長タスクの滚动実行と進捗バー（`store/memory-md-run.ts`、新エンドポイント `dsh-memory/mem-run-status`）**：1 クリックでエクスポート游標を表の末尾まで、続けて収束游標を表の末尾まで。総限度 `maxPasses` / `totalBudgetMs` を超えた分は `notice` に正直に残す。
### 変更
- **1 クリックあたりのファイル更新予算**：`memExport.maxRecords` 既定 300 → **2000**、実行時つまみ `live.mdExportMaxRecords` を追加（0 = デプロイ既定、再起動不要）。パネルの「単次動作护栏」は **「単次ファイル更新予算」** に改称、単位は「個ファイル/回」、表示はサーバー側の `appliedMaxRecords` を採用。
### 修正
- 予算が「走査件数」を数えていた（未変も枠を消費）→ 1210 件の復元は 4 クリック必要だった。
- 台帳の逐件 flush = O(n²)（300 件 = 全文 JSON 再書込 300 回）→ ループ中は dirty フラグのみ、末尾で 1 回 flush。
- 立て続けの 2 回の発火が互いに踏み合う → 投射作業を裏で**直列化**。従来は「`appendNew` 直後の `retire`」で第二タスクの収束器が「ファイル無し」と判定し、退場記録が `.memory.md` に残っていた。
- 復権後に二重化が恒久化 → 「同一 id の台帳 + `.disable` が書き込み後未編集 + `.memory.md` が現在のレンダリングそのもの」の 3 条件が揃った時だけ古い証憑を削除。

## [0.24.0] — 未リリース（ローカルライン `0.24.0-local.0…3`、2026-10-13）

### 追加

- **タイプ語彙の単一情報源（`src/memory-types.ts`）**：ホストの記憶分類 29 類の原名 + プラグイン旧 7 類 + `unclassified` のフォールバック、合計 37 類。投射ディレクトリのホワイトリスト、`memory_add` の書き込みホワイトリスト、パネルのラベル、抽出と重複排除のプロンプト内の列挙文字列、memport の TS/Python 両実装のタイプコード——**すべてここから派生**。それまで「型の全集」は 4 箇所に手書き転写され、それぞれ別に変化していた：`memory_add` は外部分類を **黙って `episodic` に書き換え**、一方 memport の文言は「そのまま透過する」と約束していた——同じ件に対して二つの言い分。
- **名称蒸留（`cfg.naming`）**：抽出のその場で `title` を生成し、`content` とは**分離して定義**（title は「この項目は何を語るのか」に答える名詞句、content は完全な叙述本文）。重複排除の merge も併せて `merged_title` を生成。保存時 `title` はあくまで**名前の候補**で、`validateTitle` の形状ゲートを必ず通過する。不合格なら引き続きネーミング側に委ねる——名前の一意性の情報源が、由来が一つ増えたことで判定基準を二通りに分けることはない。
- **few-shot 標準フォーマットの例文集（`src/prompts/examples.ts`）**：タイプ別の正例 + 誤例、総長には予算上限あり（例文は毎ラウンドの蒸留で支払う固定コスト）。正例自体がゲートを通過し骨格が揃っていることが条件で、ユースケースは判定基準を手書き転写せず `auditFewShot()` を直接使う。
- **骨格判定の実行可能化（`SKELETON_ELEMENTS` + `scoreSkeleton`）**：「前後の因果がなければ、書き切れないものは実用に耐えないとみなさない」を、プロンプト内の願望から、計測できデフォルト値の設定に使える判定基準へ。限界の申告：キーワード ヒューリスティックであり、同一入力の二群の相対比較にのみ使えて、絶対的な品質点ではない。
- **ディレクトリ骨格 + 各タイプの `_index.md`（`memory-md-skeleton.ts`）**：各タイプディレクトリに索引ファイルを 1 つ（類名 + ライブラリ内の件数）。空ディレクトリは git と圧縮ファイルに捨てられ、「このディレクトリがない」と「この類は 0 件」は人の目では同じ見た目になる。冪等：内容が変わらなければ書き込みゼロで mtime も更新しない。投射面が閉じている間は動作ゼロ。

### 変更

- **三つのデフォルト値を A/B 実測で切り替え**（`narrativeTemplates.enabled` / `naming.enabled` / `naming.fewShot`）。根拠は**方向が逆の**二つの実測：実会話の蒸留経路では例文なしで骨格完全 **0.000**（0/23）、例文ありで **0.703**（26/37）。一方、既存項目の改名というネーミング課題では例文の追加が逆に **−0.113**（回答漏れ 18/160）。結論：**例文は課題をまたいで使えない**——抽出プロンプトには入れ、ネーミングスクリプトには入れない。
- **md 投射をデフォルト ON**（`memExport.enabled`）：本計画の大前提は「ファイルが内容の権威 + DB が索引」で、デフォルト OFF はデフォルト未使用と同じ。`mdSync.enabled` は**引き続きデフォルト OFF**——DB に書くためリスクが非対称。
- **workspace 帰属の設定面を改名 `workspaceHints` → `workspaceSource`**：互換エイリアスなしの強制改名（このキーは一度もリリースに伴って外部へ配信されておらず、エイリアス追加は第二の情報源を養うのと同じ）。デフォルト ON。ルーティングの `path` は **workspace ルート** を保存（旧値は `E:\test\rewrite-agently\.agents` と書かれており、`targetFor` がさらに `.agents/memory` を結合 → `.agents\.agents\memory\` の孤児ツリー。「ルートが存在しないときのみ単一ルートへ退避する」ガードレールはこの形を防げない）。実機で既存 **724/1166** 件に帰属を補填、`hashRecords` は 1 文字も変わらない。

### 修正

- **台帳ローダが絶対キーを `relPath` に上書きしていた**：N10 以降、台帳キーは絶対パス。読み込み時の「不一致ならキーを正として書き直す」一文が毎回必ず発火し、実測で **1167/1241** 件を汚染。下流の症状は、孤児アーカイブがコロンを含む不正ディレクトリを組み立て、75 件の移動がすべて ENOENT。`root` + キーからの導出に変更（`deriveRelPath` を追加）、アーカイブ側は保存済みの `relPath` を信用しない。
- **`--revert` が hooks のフォールバックを持たなかった**：`findArchivedOld` は `deps.hooks.exists` を直接触るが、`runCli` は revert 呼び出し時に hooks を渡さない（apply 側には `deps.hooks ?? defaultHooks` があり、revert 側で漏れた）。サンドボックス初回のロールバックで 74 件すべてエラー。問題は危害の非対称性：apply の事故は `--revert` で戻るが、**ロールバック自体が壊れていればバックアップが唯一の退路**。
- **ルート間の重複ファイルが「両側が変わったなら触らない」を回避していた**：`roots = レコードの着地ルート ∪ 台帳が記録したルート` なので、同一レコードが 2 つのルートに各 1 ファイル持ち得る。判定は旧ルートの分を使い、書き込みは `targetFor` が算出した新ルートの分に進む——旧ルート内で人が書いた編集が権威ある分を上書きし、レポートは完全に規則通りに見える。現在はその時点の着地ルートのみ認め、他は新フィールド `staleRootFiles` に数えてパネルに表示。
- **名前の衝突が記憶ごと検索ライブラリから追い出していた**：`{ ...旧レコード, id: 新 id }` の書き方は「他の行に属する名前」を帯びて DB に書く → 部分一意索引に衝突 → バッチ書き込みは 1 件ずつへ退避してもなお失敗 → その項目の統合成果が**黙って消える**（旧レコードはすでに退場済みで、この置換は何も残さない）。ネーミング判定を「name が空」から「**その名前は自分に属さない**」へ変更。
- **ベクトルの「補完待ち N 件」が決してゼロにならず、「索引再構築」はやることが無いと言う**：表示面の `missing = total − embedded` の分母に退場行が含まれるが、退場行は設計上正当にベクトルを持たない。補完を駆動する 2 本の SQL はどちらも退場行を除外するため、同一画面に「補完待ち 114」と「やることが無い」が並ぶ。分母の基準をアクティブ行に統一。
- **投射ガードレールが「動作」でなく「走査」を数えていた**：`maxRecords` は「変更なし」判定の件もクォータに計上し、2 回目のクリックは同じ先頭 N 件を再び掃う——パネルの「もう一度クリックで継続」は嘘（実機症状：`已写 9 · 未变 291 · 剩余 866` が常に不変）。ディスクに触れた件のみ数えるよう変更し、走査総量は `timeBudgetMs` が支える。
- **台帳のディスク書き込み O(n²)**：`set()` は 1 件ごとに台帳全体を JSON にシリアライズしてアトミックに再書き込み。1200 件を同一ディスクで実測 **9442ms → 1954ms**（ダートフラグ + バッチウィンドウ + `flush()` 強制）。
- **`NAME_MAX`(40) と `NAME_CLIP_MAX`(28) を二つの数に分離**：文字カウントは ASCII と漢字を同価に扱い、`dsh-agent-teams` / `Python-3.13` は一語で 15 枠を食い、意味上は一、二語の正当な名前が `too-long` と判定された。一律 40 なら `deriveName` が叙述文を文の末尾に写す（実測済み）。ついでに `validateTitle` 内のハードコード 28 も修正（同一閾値に二つの情報源）。
- **名前ゲートの三箇所の誤除外**：前置き列挙表と名前拒否表を**分離**（裸の主語「用户/团队」が「用户npm账号用户名」のような名詞句を誤って除外しなくなった、実機 10 件）。`has-id-fragment` を「非 ASCII 文字の後の 4 桁以上」に狭めた（`ADR-0006`、`Han-1413141` は通過、実機 4 件）。

### 既知の境界

- 反芻の締めの増分投射は `id→updatedAt` のベースライン diff に頼るが、relabel / 退場は `patchMetadata` を通り `updated_time` を触らない ⇒ **metadata のみの書き換えはそのラウンド再投射しない**。
- P2 の逆方向同期は依然 2 項目未達：起動時の自動フック（エンドポイント + ボタンのみに変更済み）、`pending` のあの一部が `conflicts` の裁定待ち面に入っていない。
- **翻訳版は 0.20.0 以降フォロー未**（今回は 0.22.0 以降のエントリを補っただけで、0.20/0.21 の空きは残ったまま。別途記録）。

## [0.23.0] — 未リリース（ローカルライン `0.23.0-local.1…8`、2026-10-12…13）

### 追加

- **md 権威投射面（P0/P1/U/N10/N11）**：`l1_records.name` 列（ファイル身分キー + 部分一意索引）。`renderRecord` + 双フィンガープリント台帳（`dbDigest`/`fileDigest`）+ `mem-export` / `mem-reconcile` エンドポイント。パネルの「外部アーカイブ」節。投射ルートを **workspace 優先**へ変更（`<ws>/.agents/memory/<类型>/<名>.memory.md`）。古さ判定は `.memory.md.disable` と連動。
- **P2 逆方向同期（ファイル → 索引）**：台帳の双 digest で**三者象限**を——ファイルのみ変化なら DB へ書き戻し正規レンダリングで書き直す（書き戻しループを解消）、DB のみ変化なら `exportRecords` を再利用してファイルを書き直す、**両側が変わったなら両側とも触らず** `pending` を掲げるのみ。`.disable` は退場経路でファイルは削除しない。出所不明の新ファイルは数えるだけで DB に入れない（インポートは書き込みカーネルを通過する必要がある）。エンドポイント `dsh-memory/mem-sync`。
- **P3 アーカイブ + 物理削除**：`exportThenPurge` のゲートを DB 全体のハッシュから**バッチレベルの投影**へ変更（並行蒸留でこのバッチと無関係なレコードを少しでも変えると、旧実装はクリーンアップを永久に削除不可にしていた）。削除後、人が読む `retired.md` を書き + このバッチの投射ファイル（`.disable` を含む）をスナップショットディレクトリへ移動。`cleanup-retired` のドライランは**削除待ちリストのプレビュー**を返す。図投影索引テーブルに `forgetRecords` を追加（これまで全リポジトリは追加のみで削除なし——スナップショットから復元したレコードは投影行が残るため「投影済み」とみなされ、**永久に再投影されない**。検索図は静かに 1 件欠けてもエラーを出さない）。
- **P4.1 デフォルト類 `unclassified` + P4.2 本文の書式正規化**（`normalizeContentMd`）。冪等は必須要件：冪でないと台帳の `fileDigest` が毎回変わり、書き戻しループをレンダラ自身が引き起こす。書式のみで意味は触らない（散文を bullet 化しない、H1 を挿入しない、本文にメタデータを詰めない）。
- **孤児投射ファイルのアーカイブ `dsh-memory/mem-orphans`**：「台帳が私たちの書き込みを記録し、現在どのレコードもこのパスを引き受けていない」ファイルのみ移動。台帳にない出所不明のファイルは**一切触らない**（人が投射ディレクトリに置き、同期戻りを待つ入力かもしれない）。削除せず移動のみで、相対の形と原文を保持。

### 動作修正（召回表示面）

- 召回項目はもう一瞬で消えない：view に `body` / `retired` を持たせ、`session_recalled` 行の摘出をやめ、pill に「古くなったと判定」の取り消し線傍注。
- 起動時に既存の退場残骸を清掃（手元実測で 725 行がまだ `l1_fts` に汚れて残存）。退場の不変条件に 2 本のバイパス書き込み経路を追加（「失効フラグ後に検索面が復活」を修正）。
- 召回スコアリングのエンドツーエンド：`-1..5`（0..5 は関連度。`-1` は古さ宣言と退場）、スコアは成熟度指標に入る（`-1/1/2` は下げて沈め、`4/5` は上げて浮上させる）。
- workspace 内容ルーティングの初実装（dsh エコシステム → `rewrite-agently`、非 dsh → `agent-no-dsh`。**`workspace_id` のみ書き、`scope` を触らず、`updated_time` も触らない**、`l1_fts` 行がそれぞれ持つ帰属列も同期）。

### 規律

- memport の巨大関数 2 本を 2 ラウンドで分割（Extract Function、動作保持、CLI ゴールデン標準は 1 バイト単位で回帰）。
- エンドポイント契約の**五箇所同時変更**規律は継続有効（`MEMORY_ENDPOINTS ≡ switch ≡ contract 双 map ≡ contract-keys 計数 ≡ config`）、計数チェーン 55→56→57→58→59。

## [0.22.2] — 2026-10-12

### 追加

- スキンの三状態（auto/light/dark）+ トークン上書きブロック。パネル 11 Tab を一行に圧縮。
- `memory_import` の `ext_key` 冪等（`l1_records.ext_key` + 部分一意索引 + `deduped` 受領）。
- **Memport Connect**：`.mem` の解析 / 事前絞り込み / スキャン + 出所レジストリ + Connect Tab（実装横断の sha256 ゴールデン標準整合）。
- **スキル結晶化**：skill-store（JSON sidecar）+ 候補検出 + スキル召回注入 + 看板スイッチ `skillsEnabled`。
- G4 図の因果エッジ（导致 / 因为 / 修复了 / 取代、`projectorVersion` を bump しない）。
- G3 成熟度の読み時派生（レコードカードのバッジ + 矛盾裁定ビューの傍注。自動裁定には参加しない）。
- G1 `usageScenario` のゲート付きエンドツーエンド（抽出 → `metadata.dsh_usage_scenario` に着地 → 召回の細目順位付け。off は 1 文字も変わらない）。
- G2 タイプ別叙述テンプレート（ゲート付きプロンプト変種。off は on の前綴）。
- wing / 認知 hall の二軸が混ざらない（直交アクセサ + 値域の非交わり回帰ロック）。
- **G-live 今セッションの活召回セット**：永続 sidecar + `session-recalled` 読み取り専用エンドポイント + pill の読み取り専用リスト。
- `memoryRecall` のセッション認識投影（brief サイドバー「今セッション召回」区分のデータ源、`init(header).id`）。
- `cfg.slots.migrateLegacy`（デフォルト off）：「常駐に固定され、内容は活 L1 がすでに担っている」rule スロットをゆるやかに退場。

### 修正

- 反芻の書き戻しで保留カウントが戻る / 増える（ruminate は空メッセージを渡すよう変更、`enqueueSessionSlices` と同義）。
- 反芻 finalize と `doLightRefresh` の L3 強制実走 + カウントゼロ化 + `state.save()` 書き込み（「保留 L2/L3 は反芻後も消えず、再起動で再び戻る」を修正）。

### 規律

- すべての新機能はデフォルト off。off 状態の成果物と注入は 1 文字も変わらない。プラグイン横断の表示契約（`memorySlots` 投影）は結線を維持。

## [0.22.1] — 2026-10-09

### 修正

- **フローティングレイヤーの下地を不透明に**：入力バーの記憶フローティング（`.dsh-mem-popover`）とドロップダウン / フィルターパネル（`.dsh-mem-pop`）は当初ホストの `--dsw-specific-menu` に追従していたが、ホストはそれを半透明ガラスの値に解決するため、パネルが背景を透かした。現在、**不透明な `bg-primary` 下地**の上にエイリアス層を重ねる（underlay 手法）——ホストの alpha がどうであれパネルは透けない。

## [0.22.0] — 2026-10-09

### 変更

- **宣言面の 15rc 適合**：9 本の dsh peers が公開済みホスト rc すべてをカバー（`0.1.0-rc.2..0.2.0-rc.2`、1 本ずつ `npm view` で立証し各ラインの集合も一致）、すべて optional。`engines >= 0.1.0-rc.2` は粗い柵（精密なゲートは peers）、`package.json` と `dsh.plugin.json` を同期。
- **双マニフェストのバージョンを正しい値へ戻す**：`dsh.plugin.json` はそれまで `0.20.0-beta.6-dsh0.2.0.1` にドリフト、本バッチで `package.json` と 1 文字単位で整合（V1 ゲート）。
- **`dsh.client.inject` を `ui-primitives` のみに縮小**：`dsh-client-connection` は 0.1.2 からパッケージとして存在し、宣言すると client エントリー全体が 0.1.0/0.1.1 でハングする（`rpc.ts` はとっくに当該コネクションを遅延 `ctx.get`）。

### 規律

- すべての build 型リポジトリに `prepack: npm run build` を注入——`npm pack` は prepack のみ発火し `prepublishOnly` は発火しない。これは stale-build 冤罪事件の三層防衛線のひとつ。

## [0.21.0] — 2026-10-04

### 追加

- **ツールグループ封印（記憶ライブラリパネル → 記憶 → ツール封印）**：5 系統のスイッチ（room 管理 / graph グラフ / ruminate 反芻 / conflict 衝突 / mutate 書き込み・削除、13 個のツールをカバー）。オフ＝当該グループのツールは**登録しない**、モデルのツール一覧から直接消える（実行時に拒否するのではない）。切替は volatile のホット更新で即時反映、再起動不要。コア読み取り（memory_search / memory_read_scene / memory_receipts / conversation_search）とスロット三件は制御対象外。背景：グループ化ツールの多く（Room 治理、反芻など）は日常的な使用頻度が極めて低く、一覧に常駐しても注意を無駄に奪い誤呼び出しを誘うだけ。
- **memory_slot_write の mem_ 参照の実在性検証**：refs 内の `mem_*` 形の L1 record_id は書き込み前に `getByIds` の実在性検証を通る。幻覚や綴り間違いの id は即座に拒否し memory_search を経由するよう促す——「search が起動した記憶」がスロット参照に入ったなら必ず実レコードであることが保証される（brief 側の名前略述解釈によって確かな入力が得られる）。ファイルパス/URL 系の refs は検証しない。

## [0.20.4] — 2026-10-04（ローカルビルド、未リリース）

### 修正

- **投射 refViews の解釈を全面的にフォールトトレラント化**：`resolveRefViews` 内の L1 `getByIds` 呼び出しに try/catch を追加——registry の drive に例外保護がなく、解釈層で何らかの例外が投げられると（sqlite ビジー / バックエンドの降格 / 記録状態の異常）、セッションイベント駆動の全経路、さらにはホストプロセスまで巻き崩す。失敗時は当該フレームが refViews を持たないよう降格（フロントエンドは元の refs にフォールバック）。

## [0.20.3] — 2026-10-03

### 修正

- **`memory_search` のレンダリングテキストに id を付与**：v0.20.2 は record_id を出力 JSON と schema に追加したが、モデルが見るのは render 成果物であって生の JSON ではない——レンダリング行に id が無く、モデルにとって返さないのと同じ（実機再測で発見）。各結果の末尾を `— id: mem_xxx` とし、そのままスロット refs に書き込める。

## [0.20.2] — 2026-10-03

### 修正

- **投射 `memorySlots` のダーティ判定を任意のイベントへ緩和**：これまで `tool/result`（settled かつ非 error）のときのみ store rev でダーティ判定していた——書き込み後に「たまたま次のツール結果が来る」のを待たないと更新せず、セッション横断の閲覧は閲覧側セッション自身のツール呼び出しを待つ必要があった。実機では書き込み後サイドバーが長いこと空フレームに留まる点が露呈した。現在は任意のコミット済みイベントで O(1) の rev 比較を行い、rev が変われば再構築してプッシュ。isError ガードは除去（rev は実際の変更後のみ増え、イベントはトリガーであってデータ源ではない）。
- **常駐注入を `<system-reminder>` タグフレームへ変更**（dsh-agent-instructions の AGENTS.md 注入 house style に合わせる）：user ロールの担い手は変えないが、タグ枠 + 権威宣言（応答不要 / 復述するな / システムプロンプトとユーザーの直接命令を上書きしない）で提示——弱いモデルがスロット内容をユーザーの発話としてそのまま復述し通常の返答を妨げる問題を修正。スロット本文内の閉じタグをエスケープ（`</system-reminder>`）し、スロット内容がフレーム境界を偽造するのを防ぐ。

### 追加

- **`memory_search` の結果に `id`（L1 record_id）を載せる**：「検索で id が取れない → スロット refs を書けない / memory_receipts に供給できない」のデッドロックを解除。schema の説明に id の二つの行き先を注記。
- **wire view に `refs` + `refViews` を載せる**：`mem_*` 系の参照は投射フレーム構築時に L1 `getByIds` で `[type] 名称简述`（content の先頭行、80 字で切り詰め）へ解釈され、brief-sidebar（≥0.5.0-beta.2）が直接描画。パス/URL 系の参照はリテラルのまま。欠落 / 退場済みレコードはエントリを作らない。解釈はフレーム構築時に行われる——参照集合はスロットを書き込む時点で凍結し、L1 レコードの事後編集は古いフレームへ流れ込まない。自前実装の schema は付加フィールドに対し「存在するときだけ検証」するため、古い checkpoint 行はそのまま全通過（stateVersion は動かさない）。

## [0.20.1] — 2026-10-03（正式版へ昇格。beta 渠道は beta.1 以降の全機能を確定版として収載）

Hall·Room 分類管理の全チェーン（二層レジストリ / merge / rename / retire / update / 編入 / 記録付き退場 / 未登録の退場は条目補記）、Hall と Room の独立管理ページ（検索絞り込み、デフォルト折り畳み、ポインタのドラッグで分類、退場フィルタ）、老化ウェイト表示 + 召回使用統計（topN に入って初めて used と数える）。正式化直前の最後の beta は 0.20.0-beta.26 で、内容は 0.20.1 と一致。`dsh-0.2.0-beta` 渠道は後続 beta を引き続き受け付ける。

## [0.20.0-beta.26] — 2026-10-03

### 追加（Hall/Room 増加後の使い勝手）

- **Hall/Room の名称検索絞り込み**：Hall ページに検索ボックスを新設（slug、表示名、別名、大文字小文字区別なし）——hall 自身のヒット時は全ての子 room を表示、そうでなければヒットした子 room のみ残し、グループ全体がヒットしなければ非表示。検索中は一致グループを自動展開（折り畳み状態が結果を隠さない）。自生・未登録区も同じく絞り込む。Room ページにも同型の検索ボックス、退場フィルタ chips と重ねて有効。
- **Hall グループの折り畳み、デフォルトは全折り畳み**：hall 頭部は「合計 N 件 · M 個 room」のみ表示し、頭部か ▸/▾ ボタンで子 room を展開/折り畳み。「全て展開 / 全て折り畳み」の一括ボタン。展開状態は localStorage に記憶（`dsh.memory.halls.open`）。クリック選択による分類（hall 頭部クリックで分類完了）の優先順位は不変。

## [0.20.0-beta.25] — 2026-10-02

> 自生 room の退場後に状態が見えなくなる修正 + Hall 子 room の表示規則（ユーザー裁定）。

### 修正 / 変更

- **自生・未登録の room は退場で即「退役 / 復元」に**：これまで退場はレコードをソフト削除するだけで、語彙に条目がなく変化する余地がなく、ボタンは常に「編入 / 退場」だった。現在は retire withRecords が未登録 slug に対し**自動で grown の登録条目を補い retired に設定**——パネル行が即座に「退役」状態へ切り替わり、「復元」（active:true）で語彙に復帰。永続化し、再起動でも消えない。
- **Hall ページの子 room は active のみ表示**：retired / 退場した room は hall グループ下に出さない（Room ページで「退役」フィルタ付きで閲覧）。グループ集計カウントもこれに伴い active 子類のみを含める。

## [0.20.0-beta.24] — 2026-10-02

### 修正

- **Hall ページの展開/退場を Room ページと揃える**：Hall ページの room 行展開もアクティブ記録のみ取得（`retired:false`）。退場確認後、当該 room が展開中なら展開区を自動更新。（beta.23 は Room ページのみ補い Hall ページの同期が漏れていた——ユーザー実測の「退場を押しても効果が見えない」のもう一つの箇所。）

## [0.20.0-beta.23] — 2026-10-02

> **Room ページの退場フィルタを補完**（beta.22 のフィルタ chips はパッチスクリプトの途中失敗でディスクに載らず、バッジのみがパッケージに入った——今回項目ごとに Edit で確定しすべて緑で検証）。

### 修正 / 追加

- **退場フィルタ chips**（Room ページ、登録フォーム上部）：すべて / アクティブ（語彙未退役） / 退役済み。
- **退場効果の即時反映**：展開エントリは**アクティブ**記録のみ取得（`retired:false`）——退場後、展開区は即「記憶条目なし」。退場確認後に当該 room が展開中なら**自動更新**。[退場済み] バッジ + グレー化フォールバック（beta.22 に含まれ済み）。

## [0.20.0-beta.22] — 2026-10-02

> 退場効果の可視性 + Room ページの退場フィルタ（実測フィードバック：退場確認後に画面が変わらず、絞りようも無かった）。

### 修正 / 追加

- **退場効果の即時反映**：Room ページでエントリを展開すると**アクティブ**記録のみ取得（`retired:false`）——退場後、展開区は即「この Room には記憶条目がありません」と表示。退場確認後に当該 room が展開中ならその条目を**自動更新**。混在表示のフォールバックとして、退場済み条目は [退場済み] バッジ + グレー化。
- **退場フィルタ**：Room ページに「すべて / アクティブ / 退役済み」chips を追加（語彙の退役状態フィルタ）。

## [0.20.0-beta.21] — 2026-10-02

> **記録付き退役**：room を退役するとき、オプションで**その配下の全アクティブ記憶も共に退場**させられる（従来は動詞表だけで、自生 room は特に処理手段が無かった）。

### 追加

- **`retire withRecords`**（Room/Hall ページの「退場」ボタン、赤）：語彙の退役 + 当該 room 配下の全**アクティブ**記録をバッチソフト削除（各バッチ ≤200、records-delete と同一プリミティブ。reason=manual）——記録は記憶ページの「退場済み」区画で一件ずつ復元可能。自生・未登録行にも「退場」を付ける（記録のみ退役、語彙条目は触らない）。レスポンスに `retiredRecords` 件数を伴う。
- 「孤児エクスポート」ボタンを**記憶クエリパネル**へ逆移転（孤児フィルタ行内にインライン）。

### 修正

- recall-usage のテスト分離（永続化往復ケースの並行競合）。RoomTab の退役確認ダイアログでリテラル `\n` が表示される修正。

## [0.20.0-beta.20] — 2026-10-02

> **Room 独立タブ**（Hall と分離）：room の存在・名称・条目はそれぞれ管理面を持つ。記憶ページはもう Room タグを積み上げない。

### 追加

- **「Room」タブ**（Hall の後）：全 room をフラット列挙（登録条目 ∪ 自生・未登録）——**存在**（二層 slug 登録 / grown を編入 / 退役・復元）、**名称**（表示名 + 分類説明を編集。改名は二層 slug が可で記録は随伴）、**条目**（▸ で当該 room の記憶条目を閲覧、デフォルト折り畳み、初回は先頭 10 件取得）。孤児エクスポート / 高権限スイッチはページに随行。
- **登録後の再編集**：新 `room-admin update`（label/description の書き換え、未指定のフィールドは触らない）+ store の `RoomRegistryStore.update` + ツール `memory_room_admin action=update` + パネルの「編集」入口——これまで登録後の label/説明は空欄補充のみで書き換え不可だった。
- **room 行のコンテンツ展開**（Hall ページ room 行と同型）：デフォルト折り畳み、▸ で展開し条目を表示。
- **記憶ページの Room ブロック分離**：slug chips / ページング / 展開ブロックを除去（Hall/Room ページと重複）、「無バインド · N」孤児フィルタと誘導文言のみ残す——room タグの閲覧/管理は Hall/Room ページに帰す。

### 変更

- 合併/分類/改名のフォームとプレビューを sticky で追従スクロール（hall が多いとき確認ダイアログを探す上下スライドが不要に）。
- ポインタ自作のドラッグ（ego-browser と同型の pointer 方式、一部の webview で HTML5 DnD が発火しないことへのフォールバック）。

## [0.20.0-beta.19] — 2026-10-02

> 分類インタラクションの再作（実測フィードバック：HTML5 ドラッグが一部の webview で発火しない。hall をクリック後もプレビューが元行に埋もれて「反応なし」に見える）。

### 変更

- **ポインタ自作ドラッグ**（ego-browser と同型の純 pointer 方式）：room / 自生 slug を長押し → 浮遊ゴースト chip が手に追従 → hall 頭部へホバーで破線ハイライト → 離して分類。HTML5 DnD に依存せず、あらゆる webview で有効。クリック選択による分類（「分類」/「割当」→ 選択態 → hall 頭部クリック）は保持。
- **グローバル操作バー**：合併/分類/改名のフォームと dryRun プレビューを**ページ先頭に常駐**（赤い確認ダイアログが行スクロールに連動せず、元 room 行に埋もれない）——hall クリック後は必ず目に入る。
- **room 行レイアウト**：ボタンを一行に固定し折り返さない（エクスポートがもはや孤行にならない）。名称/別名は左側情報区で自然改行（別名は語の途中でも改行可）。

## [0.20.0-beta.18] — 2026-10-02

### メンテナンス

- lint の帳消し：beta.17 の isTag→isRoomSlug 置換が stats.ts / rooms-registry.ts に残した二つの死 import（リリースゲートの見逃し——パイプ後 `$?` が取るのは tail の終了コード、D2 の穴の再発）。機能変更なし。

## [0.20.0-beta.17] — 2026-10-02

> **再起動後に hall/room 関係が失われる修正**：`rooms-registry.json` のローダはなお `isTag` で slug を絞っていた——再起動時のディスク読み込みで全ての `major/minor` 二層条目が不正として**黙って破棄**されていた（単段 hall は通るので生き残る）。これは isTag/isRoomSlug 混用の三箇所目。同バッチで `normTags` の同型の地雷も除去。

### 修正

- **ローダが二層条目を落としていた**（`store/rooms-registry.ts` init）：絞込みを `isRoomSlug` へ変更。**ディスク上の rooms-registry.json データは無傷**（二層条目は常にファイル内にあり、起動時のみ捨てられていた）——アップグレード後リロードすると関係は自動復帰し、修復操作は不要。
- **normTags が slash タグを洗い流していた**（`metadata-validators.ts`）：「あらゆる tags 書き戻し地点はここを通る」ゲートが isTag を使っており、分類が書き戻す `hall/minor` タグは次の蒸留/再ラベルで触れられたとき黙って剥がされる。二層 room slug は通す（三層は依然拒否）。`isRoomSlug` の事実源を当該ファイルへ近接移動（依存循環を回避）、rooms-registry の re-export は互換維持。
- **list-records の二層 tag 絞り込みが誤って拒否**（stats.ts tagSel と同型）：`isRoomSlug` へ変更——Hall ページで二層 room の記録絞り込みをクリックすると従来 400 エラーになっていた。
- 赤テスト先行 ×3（二層の永続化往復 / normTags 通過 / 統合の二層 tag 絞り込み）、赤を検証後に修正で緑へ。

## [0.20.0-beta.16] — 2026-10-02

> **自生・未登録 slug を即 hall へ分類**：下部「自生・未登録」区の各 chip を hall 頭部へドラッグ可能に——編入 + その子類への帰属を一手で完了。

### 追加

- **grown chip のドラッグ/クリック分類**：未登録 slug（例 `git-commits`）を hall 頭部へドラッグ（または chip の「割当」ボタンで選択態に入り、目標 hall をクリック）→ dryRun プレビュー → 確認して実走。意味 = **その場で編入（from, source=grown）→ `hall/子类` へ rename**：記録 tags は随伴、旧名は目標の別名に入り、条目は active で ⭐ を付けない（編入身分）。自分の hall 配下へ戻る二層 slug（例 `dsh-plugin/xxx`）= その場で編入。
- 組合せ順序は統合テストで固定（markMered は未登録 from だと早退——まず from を編入してから rename）。execMerge は未登録 from に対し自動で編入を補う。

## [0.20.0-beta.15] — 2026-10-02

> 分類の実測フィードバックへの二件連続修正：①改名後の条目が誤って「退役済み」を帯びる（標注語彙から落ちる）。②HTML5 ドラッグが一部の webview で効かない → **クリック選択による分類**の主経路を追加。

### 修正

- **分類（改名）後の条目が誤って retired 表示**：renameRoom は merge のオーケストレーションを再利用しており、`markMerged` の「旧条目を退役へ転じる」が引っ張られていた——分類後の新 room が「退役済み」を表示し**標注器語彙から落ちていた**（listActive 絞り込み）。現在は rename の締めで先行状態を復元（active 条目は改名後も active）。真の merge（和集合セマンティクス）は影響なし。赤テスト先行（unit + HTTP 面の統合）。

### 変更

- **クリック選択による分類を主経路に**：room 行の「分類」クリック → 選択態に入る（ボタンが「hall を選択…」に変わり、全 hall 頭部が破線ハイライト）→ 目標 hall 頭部クリック → dryRun プレビュー → 確認して実走。ドラッグは保持（対応環境では引き続き使える）が、もはや依存しない。

## [0.20.0-beta.14] — 2026-10-02

> 記憶カードに**老化ウェイト**と**召回使用**表示を追加し、「老化ウェイト効果統計」のデータ蓄積を開始。口径（ユーザー裁定）：**topN（コンテキストへ注入された）に入って初めて使用と数える**。topN に入らなかった参加試行 = 試行のみ計上。

### 追加

- **カードフィールド**：「老化 N%」chip（読み取り経路の減衰係数 `max(0.5, 0.5^(Δ天/半衰期))`、召回順位付けと同式同源。≤60% は赤=老け）+「用 used/attempts」カウント（title に最近使用/試行時刻）。ツールバーに集約「召回使用 used/attempted(rate%)」を追加。
- **統計面**：`RecallUsageStore`（recall-usage.json sidecar、rooms-registry と同族の規律——破損時は読み取り専用降格のみで、召回読み取り経路を絶対にブロックしない）。毎ラウンドの召回を注入/全抑制/予算ゼロ化の三終態で記録（候補 attempts++、注入 used++、タイムスタンプは最新を採用）。メモリ即時 + デバウンス 5s でアトミック書き込み、5 万件で最新試行順に淘汰。未組込み＝ゼロコストのバイパス。
- 契約：UiRecord に `agingWeight`/`usage`、ListRecordsResponse に `usageSummary`（任意フィールド、旧クライアントは断裂ゼロ）。契約キー数は不変。

### 効果統計の口径（後続分析用）
- usageSummary: tracked（統計のある記憶数）/ attempted（Σ試行）/ used（Σ使用）/ rate（使用率%）
- 細粒度分析（タイプ/年齢帯別の使用分布、半減期チューニングの根拠）のデータは本版から蓄積、分析ビューは別途協議。

## [0.20.0-beta.13] — 2026-10-02

> 分類ロジック補完：room を既存 hall 配下へ寄せる（従来は新 hall 追加、または別 room へ合併して身分を抹消するのみ）。パネルは**ドラッグ分類**に対応——room をドラッグして hall 頭部に置くだけ。

### 追加

- **Hall ページのドラッグ分類**：room 行をドラッグ可（hiPriv オン時はグリップカーソル）、hall 頭部がドロップ先（破線ハイライト）。離す = リネームをプリフィル（major/minor）し直接 dryRun プレビュー、確認で実走——記録は随伴し、旧名は別名へ、グループビューは即当該 hall 配下へ掛かる。タッチ/ドラッグ非対応環境は room 行「分類」ボタンか改名フォーム内の hall クイック選択 chips でフォールバック。
- バックエンド修正：`renameSlug` の目標検証 `isTag` → `isRoomSlug`——従来二層目標（major/minor）は誤って拒否され「hall 配下へ分類」の道が実際には通っていなかった（かつ rename のオーケストレーションは先に記録を書き戻してからレジストリ改名で例外を投げ、半端な状態を残す）。C3 の除去/変更規律に従い：赤テスト先行（unit + HTTP 面統合各 1）、赤を検証後に修正で緑へ。

### 修正

- 同上：`renameSlug` 二層目標の検証（beta.5 で導入した欠落）。

## [0.20.0-beta.12] — 2026-10-02

> lint の帳消し + 除去規律を明文化（ENGINEERING-NOTES に C3 追加）。**機能変更なし**。

### メンテナンス

- **eslint の帳消し（13 error → 0）**：longtask 除去の残渣（stats.ts の死 import ×2、RecordsTab の死 state）+ より古いバッチの滞納（recluster.ts の死 interface と let、rooms-registry.ts / ruminate.ts / room-review.ts / テスト二ファイルの死 import と let）。残る 4 つの warning はベースライン既存（primitives/tools の any）。
- **ENGINEERING-NOTES に C3「除去も TDD」を追加**：除去は先にテストで新期待を表現（赤）→ 実装除去（緑）。lint は削除型変更で必ず走らせるゲート（unused import = 除去漏れの自動探知器）。

## [0.20.0-beta.11] — 2026-10-02

> Hall·Room **統合テスト**入庫（`tests/hall-room.integration.test.ts`：HTTP 面全チェーン × 実ストレージのユーザージャーニー、9 ケース）。統合初走りで単体テストのブラインドスポットを一つ捕捉し修正。

### 修正

- **rooms-get の合併ビュー source が `pre-registered` 固定**（beta.4 で導入）：レジストリ条目をカウント一覧へ併合する際 source を書き込んでおり、編入された（source=grown）条目はパネルのカウント chips 上で常に ⭐ 事前登録バッジを被る——身分の改竄。現在は条目の実 source を使用（⭐ は事前登録のみ。編入は grown を表示）。単体テストのブラインドスポットの原因：rooms-registry の単体テストは store 層のみで、エンドポイントの合併行が grown 条目の source をアサートしていなかった。

### テスト

- `hall-room.integration.test.ts`：空表からの自生カウント → 二層登録/不正 slug 拒否 → 編入 → 三 kind エクスポート → merge dryRun 書き込みゼロ → 実走（バックアップ書き込み / 退場行の書き換え / metadata 保全 / シーン再計算 enqueue source='room-merge'）→ rename 別名 → retire/復元 → 大類 200 上限 + 小類は枠を食わない → 破損時の読み取り専用降格レッドライン（rooms-get はブロックせず、ディスクへ書き戻さない）。

## [0.20.0-beta.10] — 2026-10-02

> **longtask（長任務モード）の全量除去**：この機能群の帰属はもと context-compression 側にある（「圧縮起動を建議」はそちらの領域）。pm への実装は誤載——beta.8 で浮遊ボールを除去し、本版で残ったバックエンドを除去し切る。pm は純記憶領域へ回帰。将来「末尾を即時蒸留」等が必要なら pm 本位で再設計して再起案する。

### 除去

- **エンドポイント `longtask-hint-get` / `longtask-compress-tail`**（契約キー 48 → 46）および `compressTailTurns` / デバウンス ruminate の閉ループ：コンテキスト計量（`ContextUsageStore`）、todo ドリフト検出（`TodoRefStore`）、建議判定も共に除去。`hooks/long-task.ts`、`store/context-usage.ts`、`store/todo-ref.ts` の三ファイルを削除（todo/write イベントの declare module 拡張を含む）。
- **`cfg.longTask.*` 設定ブロック**（デフォルト値 + 二箇所の Schema）：旧設定ファイル内の longTask キーは schema が無視するため移行不要。
- **セッションレベルの `longTask` フラグと末尾圧縮ウォーターマーク `lastTailCompressedTurn`**（session-modes）：旧 session-modes.json の残留キーは読込フィルタで自然に無視される。
- **`session-mode-set` の `mode` を必須に復帰**（当該の省略化は longtask の二者択一のために存在）。`longTask` のリクエスト/レスポンスフィールドは削除。
- 保持：beta.9 の roomRegistry RPC 結線修正（独立して成立）。Hall 管理ページと Room 分類管理面は不変。

## [0.20.0-beta.9] — 2026-10-02

> パネル RPC の全経路で deps が漏れていた問題を修正：`roomRegistry` と `longTaskDeps` が rpcHandler の sources 組み立て時に失われ、パネル側の Room 管理 / 長任務エンドポイントが常に「未組込み」になっていた（ツール面は直接渡すため影響なし、ゆえに beta.4 以来ツールは動くがパネル登録はエラー続きだった）。

### 修正

- **`registerMemoryRpc` の rpcHandler が `roomRegistry`/`longTask` を漏らしていた**（beta.4 で導入）：HTTP ディスパッチは統一して `buildEndpointDeps` を通るが、sources は 7 項目のみ帯同——`rooms-get` は registry を返さず、`room-register`/`room-admin` は「Room レジストリ未組込み（初期化にはプラグイン再読込が必要）」を投げ、`longtask-hint-get`/`longtask-compress-tail` は常に disabled。現在は sources と共に配信。回帰テストが HTTP 面全経路を固定（register → rooms-get 合併 → room-admin、rpc.test.ts）。

## [0.20.0-beta.8] — 2026-10-02

> 浮遊ボール UI を降ろす：懸浮建議パネルの帰属は context-compression 側にある（「圧縮起動を建議」はそちらの領域）。pm への実装は誤載——beta.1 以来同梱されていた FAB を本版で除去。

### 除去

- **浮遊ボール + 建議カード（`client/src/longtask-fab.ts`、beta.1 以来同梱）**：まるごと除去し、クライアントは二座に戻る——`settings.section`（記憶パネル）+ `conversation.input.left`（段階 pill）。もはやアプリ全体の懸浮 UI は無い。長任務モード本体（コンテキスト計量 / todo 参考 / 末尾 turn 圧縮）は影響なし。`longtask-hint-get`/`longtask-compress-tail` エンドポイントはバックエンド面として保持し、長任務スイッチと手動圧縮入口は確定版時に記憶設定分節へ落とす。

## [0.20.0-beta.7] — 2026-10-02

> Room 分類管理第三船（**管理パネル巻**）：専用「Hall」タブで hall（大類）+ room（小類）を一緒に管理——Room の手動閲覧/管理は以後 agent ツールを借りない。

### 追加

- **「Hall」管理タブ**（「シーン」の後）：hall グルーピングツリー——`major/minor` はその prefix 大類に帰し、standalone slug は自が hall（hall であり配下唯一の room）。hall 頭行は集約カウント + ワンクリック「+小類」（`hall/` をプリフィル）。room 行は ⭐事前登録 / source / 状態 / 別名 / カウントを表示し、retired はグレー化。UI 用語 Hall/Room はグループビューで、Wing（`metadata.hall` 領域）および認知 hall とは無関係（ADR-0020 §7 曖昧さ解消）。
- **全操作の UI 入口（高権限 memoryMutate ゲート）**：二層 slug 登録（制御されたフォーム、placeholder `dsh-plugin` / `dsh-plugin/merge`）。自生 slug の**編入**（`source=grown`）。**改名/合併**は新 RPC 経由——dryRun プレビュー（影響件数+サンプル）→「確認実行」で実走、memory_room_admin ツールと同一オーケストレーション（実行前自動バックアップ + 完了後 scene 再計算 enqueue）。退役/復元はワンクリック（復元は二次確認なし、退役は確認）。room ごとの記録リスト CSV エクスポート。語彙/孤児エクスポートは本ページへ集約。合併/改名には「反芻がアイドル時に実行」ヒントを付す。
- **新エンドポイント `dsh-memory/room-admin`**（merge/rename/retire。memoryMutate ゲート、エンドポイント側 throw セマンティクス）：契約キー 47 → 48。`rooms-export` に `kind='records'`（Room 別に記録リストをエクスポート、`tag` 必須）。`room-register` に任意の `source`（編入は `grown` を渡す）。
- 記憶 Tab の Room ブロックのスリム化：管理サブパネルを除去（孤児エクスポートは頭部行へ上方移動）、示唆は Hall ページを指す。

### 修正

- `rooms-export` records 分岐の kind 型絞り込み（TS2322）と歴史的な文字化けエラー文言。CHANGELOG beta.1-beta.5 の重複見出し行の修正。

## [0.20.0-beta.6] — 2026-10-01

### 修正

- **標注器語彙をレジストリへ接続（beta.5 の漏項補完）**：beta.5 の merge/rename/retire は実装済みだったが、候補標注器（`annotateOrphanCandidates`）の語彙は依然として純自生集約だった——事前登録の Room は候補に全く入らない。現在は OrphanAnnotateIO が registry を帯同：合併語彙 = レジストリ条目を先頭に並べ（count=0、label/description 付き）+ 自生ディレクトリ、上限 120。ruminate と memory_room_admin annotate の両経路が引数を渡す。**事前登録 Room がこの瞬間から候補標注に実質的に影響する**。

## [0.20.0-beta.5] — 2026-10-01

> Room 分類管理第二船（**破壊的面**）。dryRun デフォルト true——merge/rename は先に影響面をプレビューし、確認後に実走。実行前に `rooms-merge-backups/` へ自動バックアップ。

### 追加

- **Room レジストリの二層制**：slug が `major` または `major/minor` の二層に対応（例 `dsh-plugin`、`dsh-plugin/merge`）。**大類上限 200**、小類の細分は大類枠を食わない（総量保険 2000）。isTag 語彙は緩和しない（slash はレジストリ層でのみ許可）。
- **merge/rename/retire（ツール `memory_room_admin`、高権限）**：merge はカーソルで一致レコード全件の tags を書き換え（書き込み前 read-merge-write、roomCandidates/roomReview/hall/anchors 等のキーは保全。退場済み行も含みカウント口径と一致）。rename = merge 1:1 + レジストリ改名（aliases は旧名を吸収）。retire は語彙退役のみ（存量は触らない）。merge/rename と反芻の並行は相互上書き——実行時間をずらす（ツールヒントと ADR-0020 にいずれも宣言済み）。
- **書き換え安全三点セット**：dryRun はデフォルト affected+プレビューのみで書き込みゼロ。実行前に一致レコードを `rooms-merge-backups/<ts>-<slug>.json` へ自動バックアップ。完了後自動で `invalidateRooms` + 影響された (family, scene) 別に scene 再計算を enqueue（`source='room-merge'`）。
- **パネル Room 管理サブパネル**（高権限オンのあと表示）：登録フォーム（slug/名称/説明、新 RPC `room-register` 経由）、孤児リストのエクスポート。合併/退役の建議は agent ツール経由（dryRun プレビューの方が詳しい）。
- エンドポイント面 46 → 47（`room-register`）。

## [0.20.0-beta.4] — 2026-10-01

> Room 分類管理第一船（**ゼロドリフト面**）：レジストリが空 = beta.3 の挙動と一字一句一致。merge/rename/retire の破壊的面は beta.5 に伴う（dryRun デフォルト true は一版温存）。

### 追加

- **Room レジストリ（`rooms-registry.json` sidecar）**：事前に企画済みの Room を登録（slug/label/description）。破損/空 → 純自生ディレクトリへ降格フォールバック、パネルと標注器を絶対にブロックしない。上限 200 で乱造を防ぐ。`rooms-get` はエンドポイント層で合併：登録条目は count=0 でも語彙に入り `source`/`label` を帯同、レスポンスに全量フィールド `registry` を追加（クライアントは任意で読み取り）。
- **エクスポートエンドポイント `dsh-memory/rooms-export`**（kind=rooms|orphans、CSV 直接出力）：rooms = レジストリ ∪ 自生語彙をカウント付きで。orphans = Room バインドの無いアクティブ記録リスト（候補/復査状態列を含む）。
- **ツール `memory_room_admin`**（action=list|register）：list はレジストリ + 自生の総覧。register は Room を事前登録（高権限ゲート、冪等な補完）——`memory_room_review` の逐件復査と合わせ、agent に「登録→事前マーク→一件ずつ確認」の完全な分類管理入口を与えた。
- クライアント：Room chip に「事前登録/自生」の source 標識。孤児 chip に復査待ちセマンティクス。

## [0.20.0-beta.3] — 2026-10-01

### 追加

- **記録パネル Room 分類の改善**：①展開/折り畳み（折り畳み = 頭部 + 高頻度上位 8 Room のプレビュー、開閉状態は永続化）。②展開時は全量ページング（各ページ 40、◀▶ で頁送付）、従来の「先頭 40 のみ表示」のハード切り捨てを置換。③**孤児記憶フィルタ**——首位の「無バインド · N」chip は Room バインドが皆無の記憶のみ表示（`list-records` に `untagged` 絞り込みチャネル追加、`rooms-get` に `orphanCount` 追加、Room カウントと同口径）。④絞り込み条件の即時表示 + ワンクリッククリア。検索経路も同型の孤児フィルタ。

## [0.20.0-beta.2] — 2026-10-01

> dsh-0.2.0-beta 渠道 +1：反芻の完全 context 最適化（repo ソフトフェンス / プロジェクト別 scene 移行 / 閉ループ）。longtask（beta.1 参照）と同パッケージで、実機フィードバックをマージ集約。

### 追加

- **repo ソフトフェンス（ADR-0015、`recall.scopeFence.*`、デフォルト off）**：repoKey=basename（正規化 cwd）を書き込み時に算定して L1 metadata に入れる（repo_key_name/repo_key_owner/applicability、DEFAULT はゼロ補填、FTS とスナップショットハッシュに入らない）。召回と memory_search の出口は `this-repo`/`cross-project` でソフトに重みを下げ並べ替える（×0.2 チューニング可、**下げるのみで排除しない**、chat 族と未帰属記録はフェンスしない、重複排除経路のセンチネルが誤進入を防ぐ）。ゼロドリフト：デフォルト off 時は召回順の sha1 突き合わせ一致。
- **scene のプロジェクト別移行（L2 repo 認識 + 再クラスタ）**：L2 統合 prompt が repoKeyName/applicability を見る——this-repo 記録はもはやプロジェクトをまたぐ scene に併合しない。`scene_recluster_jobs` ジョブキュー + ruminate アイドル時の消費者（スナップショット→要約投射削除→失敗時は全体ロールバック、新規 LLM 経路ゼロ）。repo 帰属補修後は repoKey で逆引きした影響 scene を自動 enqueue して再計算。
- **圧縮閉ループ**：末尾圧縮 enqueue 成功後、10 分デバウンスで一度反芻を起動（フラッシュ→L2→L3→relabel→再クラスタ消費）。「圧縮記録が蒸留樽に取り残される」断点を修正。

## [0.20.0-beta.1] — 2026-10-01

> dsh-0.2.0 線初の beta 渠道リリース（`dsh-0.2.0-beta` tag）：長任務モードの実機プレビュー。下記以外に、本版はそれ以前 `[Unreleased]` に parked だった全 main 変更（アクティベーションスロット / 出所アンカー / 証拠リーダ / 記憶退場閉ループ / 三軸衝突など）を同時に帯同——これらは 0.1.7 線でリリース済みだが main 線に対応バージョン番号が無かった。

### 追加

- **長任務モード（`longTask.*`、デフォルト off）——「長走りセッション」の三点セット：コンテキスト計量、タスク参考、末尾圧縮、加えて非ブロッキングの懸浮建議パネル。**
  - **コンテキスト使用量（`store/context-usage.ts`）**：`assistant/message` の公式 `usage` の入力側（input + cache 読み/書き）を監視し、**最新値**セマンティクスを取る（毎ターンの入力側は既に全履歴を含むため累計しない）。`compaction/summary` 後はゼロ化して再計。純メモリ per-session Map——再起動後の最初の assistant メッセージで再構築できるため、永続化は期限切れサンプルを蘇らせるだけ。
  - **todo 参考（`store/todo-ref.ts` + `hooks/long-task.ts`）**：ホストの構造化 `todo/write` イベント（全量スナップショット。パッケージ型は 0.2.0-rc.1 でも未宣言のため、プラグインは declare module で自己拡張——§E の dsh-compaction の先例と同様）を監視。**長任務セッションのみ**：スナップショットを一つの pinned `todo` スロットへ流し込む（`SlotStore.refreshByTitle` 管理下の刷新——同一主体の反復書き込みは必ずその場で更新しないと、≤8 スロット上限内で閉じたスロットの軌跡が積み上がる）。slot-recall 経由で常駐注入——圧縮が旧コンテキストを追い出した後も、タスクの北極星は残る。隣接スナップショットに対して文字面の Jaccard ドリフト検出（同一スナップショットの反復書き込みはシグナルを希釈しない）。body ≤512 バイト、切り捨ては明示。
  - **末尾 turn 圧縮（`longtask-compress-tail` エンドポイント + `compressTailTurns`）**：（圧縮ウォーターマーク, 最新捕捉済みターン] 内の直近 N ターンを即 `enqueue(force:true)` で記憶へ蒸留——蒸留閾値を待たず、末尾の会話を即検索可能な記憶へ落とす。ウォーターマーク（`SessionModeStore.lastTailCompressedTurn`）は前進のみ、反復押下は天然的に冪等。off 档は完全に隠れる。アンカーの無い旧データは初の圧縮（ウォーターマーク 0）時のみ取り込み——多く取って再蒸留するより少なく取る。
  - **建議状態（`longtask-hint-get`）+ 浮遊ボール（`client/src/longtask-fab.ts`）**：ego-browser 式の vanilla overlay（FAB+パネル、ドラッグ/位置永続化/ビューポートクランプ）。**建議はブロッキングしない**——「コンテキスト占有が `contextThresholdPct` に到達」または「todo ドリフトが `driftThreshold` に到達」かつ長任務 off のときだけ呼吸するような発光を灯す。パネル内：長任務スイッチ（一時的、per-session、**mode を伴わない**——スイッチ切替はユーザー段階をリセットしない）、占有/ドリフトのプログレスバー、手動末尾圧縮ボタン（長任務オンのときのみ使用可）。ポーリングは忙碌 2s / アイドル 5s、RPC 失敗は無言。座席契約は不変（settings.section はちょうど一つ、body 単独インスタンスは席を占めない）。
  - **`session-mode-set` の `mode` を省略可へ**：`mode` と `longTask` の二者択一で必須——長任務スイッチだけ切替するとき段階送信を強制されない（旧クライアントは常に mode を送信、挙動不変）。レスポンス `mode` は現在有効値へ戻す。

## [0.19.0] — 2026-09-29

### 変更

- **DSH 0.2.0 適応（compat/0.2.0）**：peerDependencies と engines.dsh（package.json + dsh.plugin.json）を `>=0.2.0-rc.1 <0.2.1-0` へ一括更新（単一レンジ置換。0.1.7 系は compat/0.1.7 ブランチが継続サポート）；dsh-* devDependencies 9 件を 0.1.1-rc.2 → 0.2.0-rc.1 に固定し直し、type-only 依存 `@deepseek-ai/dsh-compaction` を追加。コード面では 0.2.0 ホスト API の変化に対応：`agent/session-start` イベントを `agent/created` に統合（serial 契約に合わせリスナーを async 化）；Session イベント読み取りを `session.events` → `session.snapshotEvents()` に変更（ホストが同期全量読み取りを非推奨化。フォールバックチェーンは維持）；テストスタブ更新（projection カーソルの offset セマンティクス）。
- **リリースメタデータ**：バージョン 0.18.4 → 0.19.0；publishConfig.tag `dsh-0.1.7` → `dsh-0.2.0`；dsh.plugin.json version → `0.19.0-dsh0.2.0.1`。

## [0.18.4] — 2026-09-28

### 追加

- **クラッシュ復元（§A）**：ホストがターン途中でクラッシュすると、それまで当該ターンの会話はメモリバッファとともに永久失われていました（resume 時のコールドスタート保護が全履歴を破棄するため）。現在は resume 時にホストの永続化イベントログと突き合わせます：L0 記録済み最大 turn をウォーターマークとして、その後の完全なターンを最大 2 件まで補収（クラッシュ孤児ターンはホストが `turn/end{reason:'interrupted'}` で閉じます——実機で 98 件確認）。冪等性 = ウォーターマーク + ターン単位の存在チェック。ホストの読み取りサービスが利用不可の場合は段階的に縮退（`sessionQuery.readSession` → `sessionPersistence.readFrom` → 従来動作 + 一回限りの通知）し、常に fail-open でセッション起動を阻塞しません。
- **ペイロード赤字化（§C、`capture.redactSecrets`、デフォルト有効）**：捕获書き込み境界で 8 種の秘密（PEM 秘密鍵 / Authorization ヘッダー / Bearer・JWT / Cookie / ベンダー API キー形式 / メールアドレス / 9 桁以上の数値（日付は除外）/ 高エントロピー ID）を `[REDACTED:<KIND>]` 型付きプレースホルダーに置換——L0 JSONL・L0 SQLite・蒸留入力・手動 `memory_add`/`memory_import` を単一点でカバー。安全値（`example` / `$VAR` / `${{…}}` 等）は対象外。プレースホルダーはカテゴリ意味を保持し検索可能。注意：有効化後は L0 原文が変わります（再構築でも原文は取得不可）。`false` で平文に戻せます。
- **蒸留プロンプト耐注入（§B）**：6 つの蒸留プロンプトファイル（L1 抽出 ×3 / L1 重複排除 ×3 / L2 シーン ×2 / L3 ペルソナ ×2 / グラフ投影 / 突き合わせ器）すべてに「内容境界（耐注入）」宣言とデータスロット界定を追加——会話原文・既存記憶プール・シーン全文等の埋め込み内容はデータであり指令ではない。判定語彙と出力契約は不変。

### 改善

- **注入確認（§D）**：リコール注入は返却時に即マークしなくなりました。「pending → ログ受領」の二段式——ホストが注入メッセージを実際にセッションログへ書き込んだ（`plugin:memory` 署名と安定 id を持つ `user/message`）時点で `dedupe.mark` します。上書き・取消された注入は記憶を誤抑制しなくなり（次ターンで再注入可能）、5 分受領なしで通常マークに縮退（確認経路故障による重複排除無効化を防ぐ）、未確認の期限切れは破棄。
- **圧縮後の精密再注入（§E）**：`compaction/end`（error なし）の後、当該セッションの次ターンで一回の拡張リコールを実施——重複排除抑制をスキップ（圧縮が旧注入をコンテキストから追い出したため）、ペルソナを即時再注入、占有台帳をリセット。使用時に消費。既存の compact/clear 全量リセットはフォールバックとして保持し、両経路は冪等。
- **構造化トレース（§F、`trace.*`）**：リコールと蒸留のイベントを日次 JSONL に永続化（`<dataDir>/trace/`、既定保持 14 日、日次 5MB 上限で停止 + マーカー）。リコールイベントは query 指紋（既定は metadata-only：長さ + sha256、`trace.captureContent` で原文 ≤200 文字）、ヒット/注入 id、スコア、所要時間と 4 結果を記録。蒸留イベントは runId・6 値の決定集計（`l1_receipts` と同源で交差監査可能）・所要時間と成否。新エンドポイント `dsh-memory/trace-tail`、設定ページの「ログ」Tab に 3 データソース切替（システムログ / リコールトレース / 蒸留トレース）。

## [0.18.2] — 2026-09-27

### 修正

- **セッション形式 v4 署名対応（ホスト >= 0.1.7-rc.1）**：記憶 recall 注入 2 箇所（セッション横断 recall `hooks/recall.ts`、スロット常駐注入 `hooks/slot-recall.ts`）で、v4 ホストが拒否する旧署名 `source: { kind: 'plugin', plugin: 'memory', form: 'recall' }`（`SessionFormatError` でラウンド全体が失敗——「記憶呼び出し時のエラー」の原因）を廃止し、producer-owned 署名 `{ kind: 'plugin:memory', form: 'recall' }` に変更。`form`・内容・タイミングは不変。根拠：`@deepseek-ai/dsh-session-format-v3-to-v4@0.1.7-rc.2` の `source()` は kind が非空かつ `'plugin'` でないことのみ検証し、随伴フィールドは検証しない。
- **読み取り側の双形状互換**：recall 份额推定の署名判定 `isOwnRecallSource` は新署名と v3 旧行の両方を受け付ける——書き側だけ直すと占有パネルの「記憶 recall 份额」が静かに 0 になる。`MessageSourceMap` はモジュール拡張で `plugin:memory` を登録（dsh-llm 0.1.7 の map は `user|model|tool|'system-prompt'` で plugin catch-all なし、producer ごとの merge-extensible）。
- **tool-result v4 native 対応（N1）**：`store/evidence-source.ts` の取证テキスト読み取りに native 分岐を追加（v4 の一等 `role:'tool'` メッセージ：content は text/reasoning ブロック直接、`isError` は message 最上位。ホストの `assertBlock` は旧 `tool-result` wrapper ブロックを硬拒否）。旧ブロック経路は歴史互換として残存——未対応だと v4 で取证テキストが静かに空になる。`projection/slots.ts` の isError ガードも native 化。

## [Unreleased]

### 追加

- **ソースアンカー（R7）——記憶をセッション内の実座標まで遡れるようになりました。** これまで追跡チェーンは途切れていました：L1 は `source_message_ids` を持っていますが、それは **L0 メッセージ id**（`msg_<epoch_ms>_<hex>`）であり、L0 テーブルには `turn`/`step` 列がありませんでした。さらに id リストは**検索 DB に一切書き込まれていません**でした（書き込み側は `metadata` のみを保存し、フィールドは黙って破棄）。結果：**どの記憶も原文に位置特定できません**でした。
  - `l0_conversations` に `turn`/`step` 列を追加（冪等な `ALTER TABLE`。旧行は NULL のまま = アンカー無し。**推測での埋め戻しは行いません**）。あわせて `(session_id, turn)` インデックスを追加。
  - キャプチャ側に `step/start` の fold を追加：`user/message` はカーネル payload に `step` を含まないため、同じターンの `step/start` から導出します。`assistant/message` はイベントが持つ `{turn, step}` を使用。**最初の `step/start` より前のメッセージは `step` を空のまま**にします——座標が無いときに座標を捏造しないことが既定です。
  - アンカーは `metadata_json` の予約キー `dsh_source_anchors` に保存（UI では `t12 s3`）。新しい列もディスク契約の変更もありません。**新規保存経路と「マージ/更新」経路の双方**がアンカーを持ちます——片方だけだとマージ一回で座標が失われます。
  - ホスト側の新 API `MemoryDb.l0ByAnchor(sessionId, turn, step?)`：**座標で** L0 メッセージを取得します（時間順ではない）。今後の「証拠リーダー」の唯一の入口です。
- **記録パネルがソースアンカーを表示**（従来は常に「-」でした）。

- **記憶の退場（ソフト削除）とクリーンアップの往復：削除はデータ喪失ではなくなりました。** 従来の「削除」は**物理削除**で、誤削除は `records/*.jsonl` の事実源から手作業で拾い直すしかありませんでした。現在は二段階で、**可逆な側が既定**です。
  - **退場（ソフト削除）**：主テーブルの行は残し、`valid_to` を閉じ、取代マーカー（`metadata` の予約キー `dsh_superseded`：時刻 / 理由 / 裁定結果 / 衝突ペア id）を書き込み、`l1_fts` と `l1_vec` の行だけを落とします。**検索側 SQL は一字も変えていません**（クエリのドリフトゼロ）。三つの退場経路（裁定敗北 / 重複排除による取代 `update`·`merge` / 手動削除）は**同一プリミティブを共有**します。
  - **エンドポイント 33 → 38**：`records-retired` / `records-restore` / `cleanup-retired` / `snapshots-list` / `snapshot-restore`。三つの一覧（`contract.ts` のマップ / `stats.ts` の `MEMORY_ENDPOINTS` 許可リスト / ディスパッチャの `case`）と端点総数のアサーションを同時に更新——どれか一つでも漏れると端点は恒久的に 404 になり、クライアント `rpc` の catch が黙って握り潰しパネルが丸ごと消えます。
  - **`memory_delete` の既定は 1 件のみ退場**（従来 3 件）。意味的マッチを行わない `ids` **厳密経路**を追加。旧実装の意味的 top-N 一括削除は、実測で**無関係な実記憶を 2 件誤削除**しました——「正確に消す」は類似度ではなく厳密 ID で担保すべきものです。
  - **物理クリーンアップは既定でドライラン**（`dryRun` 省略 = `true`）。明示実行でも**全庫スナップショット**を先に書き、**内容ハッシュで検証**し、不一致なら中止して 1 件も削除しません。これを回避不能にするため `deleteL1Batch` を**単一の呼び出し元**（`exportThenPurge`）に収束させ、ソースレベルのガードテストで固定しました。
  - **復路が欠けていました。** `restoreL1Snapshot` は**プロダクションからの呼び出しが皆無**で、「クリーンアップ前にエクスポート」は半分しか成立していませんでした（エクスポートは在るが戻り道が無い）。`snapshots-list` / `snapshot-restore` で接続：受け付けるのはスナップショットの**ディレクトリ名のみ**（パスと `..` は拒否）、既定はドライラン、`stillRetired` を正直に報告します。この項目は必須です——クリーンアップは**既に退場した**記録しか消さず、スナップショットは削除**前**に撮るため、戻せる記録はすべて退場マーカー付きです。**主テーブルに戻った ≠ 検索に戻った**。黙っていると「復元完了」と誤解されます。完全な一発ロールバックは `unretire: true`（既存の `restore` を再利用、新しい書き込み経路は作りません）。
  - **パネル**：記録タブに「退場済み（復元可能）」区画を追加（既定は折り畳み、展開時のみ取得）。削除確認の文言は「復元可能」に変更。**物理クリーンアップは意図的にパネル入口を作りません**——不可逆操作は RPC / モデル側の出口だけに残します。
- **§C 矛盾凍結：同一バッチ内の矛盾も凍結できるようになりました（「モデルが唯一言うことだけが必ず拒否される」の修正）。** 調査の結果、`validateConflictPair` の第③条件は「相手が候補プール内の既知レコードであること」を要求していましたが、**同一バッチで生成された新記憶の id はそこに含まれません**（まだ保存されていないため）。つまり最も典型的な「機械には判定できない」ケース（同一バッチの矛盾した二つの新記憶）は、モデルが正しく `conflict` を出しても**必ず不成対と判定され `store` にフォールバック**していました。証拠：モデル層では 7/7 で出力されるのに、その一歩は一度も DB に到達していません（`conflict_pending` は DB 作成以来 0 行、`l1_receipts` の `conflict` は `store 381 / merge 204 / update 172 / skip 7` の中で 0 件）。修正：`validateConflictPair` に任意の `batchIds` を追加（省略 = 従来動作）。ただし「必ず一方が本条の記録」は維持し、ペアが一意になるようにします。さらにキュー満杯ガードを追加し、**敗方が当バッチの新記憶である場合は自動了結しない**（抽出直後の産出が誰にも知られず即退場するのを避ける）ようにし、単に停放置せず通常どおり格納します。

- **§C 矛盾凍結が「三軸時間」を理解できるようになりました——内容が矛盾していても時間的な前後があるものを、一律に人手へ回さなくなります。** 記憶レコードには元々、互いに代替できない三つの時間軸（記録時刻 `createdAt/updatedAt`、事実の有効期間 `validFrom/validTo`、持続性 `persistence`）がありましたが、矛盾検出は記録時刻しか使っていませんでした。検出器は `conflict` を判定する際に有効期間と持続性を見られないため、「古い事実が新しい事実に置き換わった」ケースが人手裁决の対象として停放置されるのが常態化し、裁决パネルも双方の本文しか表示しないため人は盲判を強いられていました。今回、凍結の両端に三軸を接続しました：
  - **検出側**：凍結**開啟時**、統一候補プールが各記憶の `valid_from_ms` / `valid_to_ms` / `persistence` を検出器へ渡し、`conflict` 動作条項に「三軸の補助判定」を追加——内容が矛盾する場合はまず有効期間と持続性を比較し、一方が期限切れ、または明らかに遅い場合は `update` / `merge` を優先します。**三つのキーと条項はいずれも `conflictFreeze` でゲートされます**：關閉態の user prompt は変更前と**バイト単位で同一**です（下記「修正」および [ADR-0012](./docs/adr/0012-conflict-3axis-advisory-time-axes.md) 参照）。
  - **裁决側**：`ConflictPairView` に任意の `winner_*` / `loser_*` 三軸フィールドを追加（後方互換）。待裁决リストとその描画は各ペアに「有効期間の起/止、持続性」の比較を付し、どちらが新しいか・どちらが期限切れかを一目で分かるようにします。
  - 機械は**依然として自動裁决しません**：三軸は補助事実にすぎず、最終結論は従来どおり人（または安全弁のタイムアウト／満杯による自動了結）が書きます——`ConflictResolution` の値は変わりません。

### 修正

- **關閉態の prompt に三軸フィールドが黙って混入していました（凍結 OFF＝デフォルトのデプロイに影響）。** 初版は `valid_from_ms` / `valid_to_ms` / `persistence` を候補プールへ**無条件**に注入していましたが、この LLM 呼び出しは system prompt にしかスイッチを読んでいませんでした。そのため `conflictFreeze=false`（デプロイ既定）ではモデルが候補ごとに 3 つのキーを余分に見ており、しかも**それを説明する条項が一切ありません**でした——トークンが増え、入力が変わっていました。三つのキーを `conflictFreeze` でゲートし、關閉態の user prompt は変更前と**バイト単位で同一**にしました。判据も「特定の部分文字列を含まない」から **sha1 golden アンカー + 反証検証**（ゲートを壊すと当該ケースが赤くなる）へ格上げしています。
- **スイッチは明らかに ON なのに、パネルは「矛盾凍結は未開啟」と表示していました。** `conflicts` / `conflict-resolve` 端点は**デプロイ時の静的設定** `cfg.conflictFreeze.enabled` を読んでいたのに対し、パネルは**実行時設定**（live）に書き込んでいました。デプロイ既定値は常に `false` のため、スイッチが ON で `settings.yaml` に `true` が保存されていても未開啟と表示されます。`effectiveCfg(cfg, live)` 経由に変更し、重複排除パイプラインと同じ解決に統一しました——真実の源は**一つ**であり、読み手と書き手が同じ状態を見る必要があります。
- **`dsh-memory/embedding-reindex` は宣言されているのに恒久的に 404。** 契約には存在するものの `MEMORY_ENDPOINTS` 許可リストにもディスパッチャの `case` にも無く、`startReindex()` は**死んだコード**でした（設定の「ベクトル索引」ブロックに「開始」が無く「キャンセル」だけだった理由）。許可リスト + `case` + テストを追加。
- **`UiRecord.sourceMessageIds` は死んだフィールドでした。** `l1_records` に**存在しない列**を読んでいたため常に `[]` になり、パネルの来源行は**一度も描画されていません**でした。実データを読む `sourceAnchors` に置き換えました。

## [0.12.0] — 2026-09-17

### 追加

- **ベクトルインデックスの手動再構築（`dsh-memory/embedding-reindex` エンドポイント + 設定画面の「ベクトルインデックス」ブロック）**。従来、再構築のきっかけは起動時の `db.init` 変更検出チェーンと、欠落ベクトルを補う定期 backfill の二つだけで、**手動の入口が存在しませんでした**。設定画面に見えるのは「キャンセル」のみ（しかも再構築が実行中のときだけ）で、「開始」も、どこまで埋まったか／何が残っているかも分かりませんでした。
  - **エンドポイント面 31 → 32**。`EmbeddingReindexStartResponse`（`{accepted:true}`）を新設。**受理して即座に返し、進捗はここでは返しません**——クライアントは従来どおり `embedding-state-get` の `reindex` をポーリングします。進捗の語彙が二系統あればいずれ食い違うため、意図的に一つに絞っています。4 か所（`contract.ts` のマップ / `MEMORY_ENDPOINTS` 許可リスト / ディスパッチャの `case` / エンドポイント総数のアサーション）を同時に更新しました。**どれか一つでも欠けるとエンドポイントは恒久的に 404** となり、クライアントの `rpc` catch がそれを無言で握り潰すためパネルごと消えます。
  - **`EmbeddingStateView` に `vectors` を追加**：L1 / L0 それぞれの `embedded` / `total` / `missing` / `skipped`。「X / Y 埋め込み済み」はここから来ています。db 層の **`-1` センチネルはそのまま透過**させます——「ベクトル機能が使えない」と「一件も埋め込んでいない」は UI 上で別の文でなければならず、一つの数値に畳むと、決して反応しないボタンをユーザーに押させ続けることになります。

### 修正

- **「受理したが実際には走らない」再構築要求を拒否**。`L1Store.reindex` / `L0Store.reindex` の先頭行は、ベクトル機能が未準備のとき**無言で `0/0/0` に短絡**します。入口にゲートが無ければ UI は「再構築完了・未処理ゼロ」と表示しますが、実際には**一度も開始していません**。この罠は `src/index.ts:240` に既にコメントがありましたが、それは起動チェーンのみを対象にしており、手動入口は新たな破口でした。`startReindex()` は五つのゲートをすべて前倒しし、それぞれ**行動可能な**文言を与えます：アンロード済み / 再構築実行中 / ソース切替がロック保持中 / **埋め込みソースが無効**（`currentInfo` が空）/ **サービス未準備**（「先に有効化」と「もう少し待つ」は別の指示であり、一つにまとめてはいけません）。このため両ストアに `vectorsReady()` アクセサを追加しました——`helper` は private で、外部から問い合わせる手段が無かったためです。
- **`embedding-subsystem.test.ts` の `db` スタブが不完全**。`swapProvider` / `markEmbeddingSynced` の二つしか持たず、`as never` で型検査を迂回していたため欠落が露見していませんでした。`snapshot()` がベクトル件数を含めるようになった時点で即座に落ちます（`getVecSkipSet is not a function`）。**`vectorCounts` を防御的にするのではなく、スタブを補完**しました：型シグネチャは完全な `MemoryDb` を宣言しており、欠落メソッドを握り潰すことは実際の配線ミスをも一緒に隠すことだからです。

### テスト

- 新規 5 件：無効時の拒否 / 未準備時の拒否 / 受理して L1+L0 を駆動しかつ並行の二回目が即座に拒否される / アンロード後の拒否 / `snapshot` の件数口径。**すべての拒否経路で「例外を投げる」と「下流が一度も呼ばれない」の両方をアサート**します——例外だけをアサートすると、「先に下流を呼んでから投げる」実装でも通ってしまいます。
- **反証**：準備完了ガードを一時的に外すと `向量能力未就绪 → 拒绝` が確かに赤くなり（`expected [Function] to throw an error`）、戻すと再び緑になります。
- 全量 **39 ファイル / 403 ケース**が通過。`typecheck`（3 つの tsconfig）、`build`、`smoke` すべて緑。

## [未リリース]

### 追加

- **§E ストレージスコープ `scope`（可視範囲、`family` と直交）**。これまで全プロジェクトが 1 つの記憶庫を共有しており、プロジェクト A で蒸留した `work` 族の記憶がプロジェクト B の会話でも検索されていました。新しい `scope` 設定（`global` 既定 / `workspace`）を追加し、既存の `family` と**直交**させます——`family` は「これはどんな内容か」、`scope` は「どこまで可視であるべきか」に答えます。「`workspace` モードでは `work` 族をワークスペース単位で隔離し、`chat` 族は既定でグローバルのまま」は**既定値であり導出規則ではありません**（個人的な記憶はプロジェクトをまたぐべきで、汚染面はプロジェクト間にこそあります）。
  - **ゼロドリフトは比較ではなく構造で保証**：`cfg.scope` が `workspace` でなければ共通の `scopeFilterOf` が常に `undefined`（＝フィルタなし）を返すため、どの呼び出し点も誤ってワークスペース識別子を渡せません。既存デプロイ（キー未指定）の挙動は**バイト単位で同一**です。
  - **隔離は族隔離と同一層**に置きます：検索の出口だけでなく**重複排除の候補召回**もフィルタします。候補プールは次の重複排除判断を決めるため、ここがワークスペースをまたぐと「プロジェクト B では見えないのに、すでにプロジェクト A の記憶の行き先を決めてしまった」記憶が生まれ、隔離しないより悪くなります（[`ADR-0008`](./docs/adr/0008-storage-scope-vs-family.md)）。グラフ路は**来源レコード**の帰属で同層フィルタし、書き込み経路（抽取パイプライン / `memory_add` / `memory_import`）は同一の `resolveRecordScope` を共有します。
  - **ワークスペース識別子は canonical cwd を取り、宿主 `dsh-workspace` の `WorkspaceId`（uuid）は取りません**：§A の `parentSession` と同じ header 経路で同期取得でき、`inject` を宣言すると当該サービスを持たない宿主でツリー全体のロードが失敗し、宿主自身の成員判定も「session header の canonical cwd == workspace path」であり、uuid は「登録済みワークスペース」を要求するため未登録ディレクトリでは隔離が静かに失效します。既知の境界：**シンボリックリンクは解決しません**——結果は過剰隔離（安全側）であり漏洩ではありません（[`ADR-0009`](./docs/adr/0009-workspace-identity-source.md)）。
  - **移行は帰属を記すだけで移動も削除もしません**：`l1_records` / `l1_fts` に `scope` + `workspace_id` を追加し、既存データは `ALTER` の既定値で `global` に分類されます——件数・id・content・created_time はバイト単位で不変です。
  - **実行中に見つかった 2 件の実不具合**：① FTS 再構築の回灌が scope を落とすと**隔離が静かに消える**（列数の不一致が行ごとの `catch` に飲まれ、`count=0` の空インデックスになる）。② 書き込み側の**形状正規化漏れ**により「書き込めたのに二度と検索できない」状態が生じる（検索側は正規化済みの小文字パスを渡し、保存側は呼び出し元の大文字文字列をそのまま保持するため、文字列一致が必ず外れる）。いずれも端到端テストと変異プローブが捕捉しました。
- **§F グラフ節点ベクトル列 `graph_node_vec`（記憶と降格の土台）**。グラフは従来語彙加重スコアのみで、意味的に等価でも字面が異なる実体（「云深处」と「DeepRobotics」）を相互解決できませんでした。`l1_vec` と**同パターン**の vec0 仮想表を追加し（同一の符号化、同一の `float[N] distance_metric=cosine` 宣言）、次元は**既存の能力探測結果を再利用**して二重の探測を作りません。
  - **降格は内側の `try/catch` で消化**：vec0 が無いとテーブル作成が例外を投げ、それが `GraphStore.init` の外側の catch に届くとグラフは「ベクトル路が使えない」から「**グラフ領域全体が使えない**」へと降格し、語彙検索・投影・裁定を道連れにします（[`ADR-0011`](./docs/adr/0011-graph-node-vector-storage-and-degradation.md)）。
  - **本波は扉のみで、生産者と消費者は未接続**：投影パイプラインはまだ埋め込みを計算しません。未完了として記録します——§F の起点であり終点ではありません。

- **§B L1 決定証跡チェーン（追跡可能性の基盤）**。L1 レコードはすべて重複排除判断の**結果**ですが、判断自体は痕跡を残していませんでした（結果は見えるが、何に基づいたかは見えない）。新テーブル `l1_receipts` が判断ごとに証跡を残します（`run_id` / `record_id` / `kind` / **候補プールの順序付き sha256 ダイジェスト** / `decided_at`）。新ツール **`memory_receipts`** と RPC 端点 **`dsh-memory/receipts`** で、レコード単位・バッチ単位の**二次元遡及**ができます。証跡はイベントの**前に**存在しなければなりません——入力スナップショットは**後から補填できない**ためです（[ADR-0006](./docs/adr/0006-l1-decision-receipts.md)）。
  - 保持方針は **run 数**単位（`RECEIPTS_MAX_RUNS = 1000`）——時間窓では行数の上界を与えられません。またトリミングは **run 単位であり行単位ではありません**（行単位では「半端なバッチ」が生まれ、完全に見えて実は欠落した結論を出してしまいます——「見つからない」より有害）。
  - レッドライン:トリミングは **`l1_receipts` のみに触れ、`l1_records` には絶対に触れない**。
  - 失敗隔離:証跡は側路インフラであり、書き込み失敗は `warn` のみで **L1 蒸留を絶対に中断しません**。

- **§C 矛盾凍結（オプション、既定オフ）**。従来の重複排除**決定語彙**は `store` / `update` / `merge` / `skip` のみ——「衝突検出器」が矛盾を検出しても **LLM が直接裁定して書き込み**、**「止めて人に聞く」という選択肢がありませんでした**。`conflictFreeze.enabled` を有効にすると語彙に `conflict` が加わり、どちらも正しそうで機械には判定できない場合にペアを `conflict_pending` に**待機**させます——**新しい記憶は通常どおり保存され、双方の内容は書き換えられません**。裁定は新ツール **`memory_resolve_conflict`**（RPC: `dsh-memory/conflict-resolve`）で行い、結論は `winner` / `loser` / `both` です。
  - **凍結は「書き込みを止める」ではなく「自動裁定しない」**——前者は情報を失い、解こうとした問題より悪くなります。
  - **安全弁**:`maxPending`（キュー上限）/ `timeoutDays`（タイムアウト降格）。意味は「**新しいものを受け取らない**」であり「古いものを黙って消す」ではありません——自動決着したペアも**キューの行として残り**、`resolution = auto` で人の結論と区別されます。
  - **グラフ側**:凍結された記録をソースに含むノードは `disputed` になります（既存状態。検索候補には残るため「通常どおり召回されるが状態が見える」中間状態）。この付与は**派生同期**であり片方向フラグではありません——裁定は争いを**取り消す**ため、片方向だと解決済みノードが永久に `disputed` のままになり、**派生グラフが事実と食い違います**。
  - **ゼロドリフト**:無効時、重複排除プロンプトは変更前と**バイト単位で同一**。これは**構造的**な保証（無効パスは base 定数をそのまま返す）であり、人手の比較ではありません（[ADR-0010](./docs/adr/0010-conflict-freeze-default-off-and-timeout.md)）。

### 変更

- **新設定** `conflictFreeze.enabled`（既定オフ）/ `conflictFreeze.maxPending`（100）/ `conflictFreeze.timeoutDays`（30、`0` = タイムアウト降格なし）。**新端点** `dsh-memory/receipts` と `dsh-memory/conflict-resolve`（端点面 26 → 28）。
- **`L1ReceiptKind` に `conflict` を追加**。動作語彙を拡張する際は**その語彙を消費するすべての箇所**（証跡の正規化・統計ログ・描画文言・schema 記述）を同時に確認する必要があります——実行時に実測:登録漏れがあると「モデルが**明確に**判定不能と言った」が `skip_missing`（=「モデルが**答えなかった**」）として記録され、§C の監査可能性は**完全に**証跡チェーンに依存するため、監査結論が事実と**正反対**になります。

### 修正

- **未認識のアクションがフォールバック分岐に静かに吸収される**。`pipeline/l1.ts` の適用ループは `store` / `skip` だけを明示分岐し、**他のアクションはすべて update/merge 分岐に落ちます**。conflict 判断は設計上 `target_ids` を持たないため `targets=[]` となり、「0 件を置換した」マージ産物として追記され `version` が **1** になっていました。**エラーもなくデータ損失もなく、痕跡は version という数字だけ**——すなわち conflict が黙って merge/update に降格していた、§C がまさに排除したい挙動です。**修正**:明示的な `conflict` 分岐を追加し、検証失敗またはスイッチ無効時は **`store` にフォールバック**、フォールバック分岐には絶対に落としません。
- **端点ゲートが手書きの写しだった**。`tests/contract-keys.test.ts` は真の登録表を import せず複製していたため、両方の断言が写し自身としか整合していませんでした。§B が `receipts` を追加して真の登録表が 27 になっても写しは 26 のままで、件数断言も `toBe(26)` のまま——**緑のままでした**。今回 `conflict-resolve` を追加しても**依然として緑**でした。**修正**:ローカル一覧が `MEMORY_ENDPOINTS` と項目単位で一致することを断言します。

## [0.11.0] — 2026-09-13

### 互換性（DSH プラグインフレームワークドキュメントへの適合）

- **settings 登録のクロスバージョン対応（0.1.1-rc.2 ～ 0.1.5-rc.2）**。`src/settings.ts` は以前、`@deepseek-ai/dsh-settings` から `settingsNamespace()` を**値インポート**していましたが、v0.1.3+ ではこのエクスポートが削除されており、新しいホストではモジュールのロード時に `Failed to load plugins` が発生してプラグインツリー全体が巻き込まれます。現在は：
  - 名前空間は文字列リテラル `'dsh-memory'`（ブラウザ側は生の文字列のみを読み、新旧ホストで等価）。型インポートのみ残し（コンパイル時に消去、ロードリスクなし）。
  - 登録は 3 分岐のランタイム判定：まず `settings.register()`（全対象バージョンに存在、get/watch/update スコープを返し、ライブ切替と UI 書き込みのすべてがこれ経由）；フォールバックは `settings.installSection()` ブリッジ（v0.1.2+ のサービスマフェース、`register` がない場合のみ。ランタイム書き込みはビジネスエラーで明示拒否）；いずれも存在しなければ常時オンへ縮退——「settings 障害でホストを落とさない」原則は不変。
  - `SettingsScope` はローカル構造型に変更し、パッケージレベルの型エクスポートに依存しない。
- **`dsh.plugin.json` を追加**（DSH 発見マニフェスト：id / `engines.dsh` `>=0.1.1-rc.2 <0.2.0-0` / components は `dist/` 成果物を指す）。`dsh-plugin-template` 標準ファイル構成に準拠。
- **`@deepseek-ai/dsh-*` peerDependencies を optional 化し範囲を拡大**（`^0.1.1-rc.2 || ^0.1.2-rc.1 || ^0.1.3-rc.1 || ^0.1.5-rc.2`）。`@deepseek-ai/cordis` は必須のまま——awesome-dsh-plugin 投稿要件 B.3 に準拠。
- **`screenshots.json` を追加**（`assets/img/` 参照の 8 枚）、投稿カードに表示可能。

### 変更

- `package.json` のバージョンを 0.11.0 に更新。npm `files` に `dsh.plugin.json` を追加（`screenshots.json` は awesome-dsh-plugin の探知規約に従い git リポジトリのみ、npm パッケージには含めない）。

### 実地検証待ち

- v0.1.5-rc.2 での `conversation.input.left` / `settings.section` スロットと Session V3 の `session.surface.nodes` セマンティクス（occupancy 推定）は未検証。README の互換性マトリクスを参照。
