# 変更履歴

`dsh-session-guard` の主な変更を記録します。バージョンはセマンティックバージョニングに従います。

- [English changelog](./CHANGELOG.md)
- [日本語 changelog](./CHANGELOG.ja.md)
- [한국어 changelog](./CHANGELOG.ko.md)
- [Changelog en français](./CHANGELOG.fr.md)
- [Changelog auf Deutsch](./CHANGELOG.de.md)
- [Changelog in italiano](./CHANGELOG.it.md)
- [Changelog на русском](./CHANGELOG.ru.md)
- [Changelog en español](./CHANGELOG.es.md)

## 4.2.1 — 2026-10-17（ホスト列挙の更新：0.2.1-rc.1 を追加）

### Fixed
- `engines.dsh` と 4 つの `@deepseek-ai/dsh-client-*` peer に `|| 0.2.1-rc.1` を追加（16 ホストの正確な列挙）。ホスト互換ゲートが DSH `0.2.1-rc.1` を受け入れるように。
- `dsh.plugin.json` の `engines.dsh` を同じ 16 ホスト列挙に統一（従来は範囲 `>=0.2.0-rc.1 <0.2.1-0`。ゲートは `package.json` のみを読むが、両リストは一致すべき）。
- README の互換記述を列挙に同期（zh/de/es/fr/it/ru）。このリリースに動作変更はありません。

## 4.2.0 — 2026-10-17

### 追加
- 法定祝日対応（src/holidays.js + src/holiday-store.js）。内置 2026 確定スナップショット：39 行 = 33 休日 + 6 振替出勤日（出典 holiday-cn、国務院公告）。厳格 parse（ゼロ埋め日付、isOffDay 真偽、跨年拒否）；判定字段のみ sha256 指紋（上流の文言/順序変更は偽差異を出さない）。キャッシュファイル $DSH_HOME/.dsh/session-guard/holidays/<year>.json はロード時に指紋照合、不一致は破棄して内置フォールバック + 再取得。自動更新：起動時 + 每小时 ensureFresh；対象年は北京当年、11/12 月は翌年も（年末公告はリリース無しで反映）；jsDelivr 主 / raw.githubusercontent 副、10s タイムアウト；指紋変化時のみ原子的書込；24h 再取得抑制；全链路 fail-open。DSH_SESSION_GUARD_HOLIDAY_FETCH=0 で離线内置固定。
- 宣言式開关 holidayMode / holidayAutoFetch（どちらも既定 ON）。/session-guard/status に holidayMode + holidays[]（年/出典/指紋/取得时刻/件数）を追加。

### 変更
- weekendMode を休息日语义へ昇格：法定祝日は终日オフピーク、振替出勤周末は通常どおりピーク判定、nextOffPeakInstant の先読み 7 -> 14 日で表対応。holidayMap は readCfg 経由で cfg に載り、shouldPause 消费链（scheduler tick / request-guard / step-gate / wiring）はシグネチャ不変で自动生效。

### 修正
- family claim rank 1 -> 2、冻结权重表（唯一真源 _tools/family-rank.mjs）と整合。

## 4.1.16 — 2026-10-14（マニフェスト整合／欠落していた 4.1.15 の補記）

### 修正

- `dsh.plugin.json` の版数を `package.json` と一致させた。公開済みの 4.1.15 ターボールは
  まだ 4.1.14 と書かれていた（レジストリから実際にダウンロードして確認）。
- 動作変更なし。
- テストの構造ピンが退役済みの歯車入口をまだ要求しており、4.1.15 以来スイートが赤だった。
  不在を断言する側へ修正した。

## 4.1.15 — 2026-10-08（補記：リリース当時この項が書かれていませんでした）

### 削除

- シェルレベルの `shell.overlay` シート注入を廃止：右下固定の歯車ボタンと浮層レイヤーを除去
  （`src/client/shell-overlay.tsx` を削除）。設定への入口はホストの設定ページのみを頼る。

## 4.1.14 — 2026-10-08

### 削除

## 4.1.13 — 2026-10-08

### 修正 — ≤0.1.5 でのブリッジ記述子スケルトン（5セルゲートで発覚）

- **≤0.1.5 ホストの describe `value` はフィールドスケルトン**（実測：`{enabled:{},…}`、実値は `base`＋`user` 層）。旧世代で `descriptor.value` をそのまま消費すると `officialProviders` が `{}` になり `?? []` を素通りして `ListRow` の `values.join` が throw、`dsh-family.tab` スロット全体が殉葬していた。`descriptorPlainValue()` がスケルトンを検出して `{...base, ...user}` を再構築。
- **カード字段消毒（多層防御）**：スロットは一つの描画エラーで全族タブが死ぬため、`ListRow` 入力を `toList()` で無毒化、`拦截方式` セレクトは非 `error` 値を `hold` にフォールバック。
- 5セルファームゲートで検証：0.1.0/0.1.5 はブリッジ経由、0.1.7 は configForms 経由でシード値 `321123` の読み返しを確認。

## 4.0.0 — 2026-09-29

### Changed
- **DSH 0.2.0 ライン対応**: `engines.dsh` と 4 つの `@deepseek-ai/dsh-client-*` peer を `>=0.2.0-rc.1 <0.2.1-0` に更新（0.1.7 系レンジを置き換え）。npm dist-tag は `dsh-0.2.0`、manifest バージョンは `4.0.0` に統一。プラグインが利用する API 面（manifest / settings / HMR / slots / セッション v4）は 0.1.7 から変更なし — 実行コードの変更はありません。
- `@deepseek-ai/cordis` peer の下限を `^4.0.4` に整合（0.2.0-rc.1 ホストの UI パッケージは `~4.0.4` を宣言。旧 `^4.0.1` は衝突しないものの下限が実態より低かった）。

### Fixed
- `src/client/family-section.tsx` をバージョン管理に取り込み（3.2.x から作業ツリーのみに存在し、クリーンな checkout ではビルドできなかった）。
- eslint flat config: TS 型シグネチャの引数を誤検出するコア `no-unused-vars` を削除（typescript-eslint 版は維持）。lint ベースラインが再びグリーンに。
- v4 source-kind 静的ゲート（`tests/source-kind.test.mjs`）を追跡下に置き、`npm test` で実行（248 テスト）。

## 3.2.4 — 2026-09-27

### Fixed
- **セッション形式 v4 対応（ホスト >= 0.1.7-rc.1）**: セッション書き込み 3 箇所で、v4 ホストが拒否する旧署名 `source: { kind: 'plugin', plugin: 'session-guard' }` を廃止し、プロデューサー所有 kind に変更しました（`SessionFormatError` でラウンド全体が失敗する問題を修正）：
  - 遅延再開の notice 注入（`src/wiring.js`）
  - 自動リトライの notice 注入（`src/retry.js`）
  - 一時停止からの再開 followup（`src/pause-gate.js`、```kind: `plugin:${pluginId}````）
  - **tool-result v4 native 対応（N1）**: `src/pause-gate.js` の `findToolOutcome` は、v4 の一等 `role:'tool'` メッセージ（`toolCallId`/`isError` が message 最上位）を優先して読みます。v3 の `tool-result` ブロック経路は歴史互換として残存。未対応だと一時停止中の失敗ツールが再開時に「完了済み」と誤判される静かな誤判定を修正。`src/tool-call-id.js` も native 最上位 id を最優先に。0.1.1/0.1.2 時代のヘッダ注記を三形状世代表に訂正。
  `form` など他フィールドは不変。既存の旧署名行はホスト自身の v3→v4 移行が昇格するため、履歴データは書き換えません。根拠: `@deepseek-ai/dsh-session-format-v3-to-v4@0.1.7-rc.2` は `source.kind` が非空かつ `'plugin'` でないことのみ検証します。

## 0.4.0 — 2026-09-18（誤ったバージョン番号。3.0.0 に置き換え）

### 修正

- **バージョン識別**：本ラインは `0.4.0` として公開されましたが、`dsh.plugin.json` と本変更履歴は
  すでに `3.0.0` を名乗っており、1 つの成果物に 2 つのバージョン番号が存在していました。
  `package.json` を `3.0.0` に統一し、パッケージ版・マニフェスト版・変更履歴が一致しました。
  npm のバージョンは不変のため `0.4.0` は歴史的記録として残します。`3.0.0` 公開後は
  `dist-tag dsh-0.1.5` を `3.0.0` に向け直すべきです。
- **ドキュメント**：README/INSTALL（zh/en/ja/ko）が兄弟ラインを `main` にあると説明していたのを
  修正。0.1.2 ラインのリリースブランチは **`legacy/0.1.2`**（npm dist-tag `dsh-0.1.2`、
  バージョン `0.3.1`）で、`main` は `0.2.0-beta.1` で凍結されています。INSTALL.zh/ja/ko の
  重複したブランチ断片を修正し、dist-tag を明示したインストールコマンドを
  記載。「2.x / 3.x」は**ラインの通称**でありバージョン番号ではないことを明記しました。

### 備考

- **ソース変更なし**（`3.0.0` 比）。`0.4.0` は同一ツリーのパッケージングのみの公開です。

## 3.0.0 — 2026-09-14

### 変更

- **DSH v0.1.5-rc.2 専用ライン（`compat/0.1.5`）。** `engines.dsh` と `dsh-client-*` の peer
  範囲を `>=0.1.5-rc.2 <0.2.0-0` に狭めました（semver のプレリリース規則上、旧
  `>=0.1.0-rc.7` は `0.1.5-rc.2` に一致しません）。`dsh.plugin.json` に `engines.dsh` を追加。
  旧ホスト向けには `main` 上の 2.x / 0.2.x ラインが継続します。
- **`session.events` → `snapshotEvents()`。** DSH 0.1.5 で `session.events` 配列アクセサが
  削除されたため（compatibility-guide §20.3）、`pause-gate.js` はデュアルパスのヘルパーで
  セッションイベントを読みます：まず `snapshotEvents()`、防御的に旧 `events` 配列へフォール
  バック、どちらも無ければ `null`（fail-open）。対象は `findToolOutcome` と `lastUserPrompt`
  のみで、イベント型のマッチングは不変です。

### 変更なし

- その他の接続面は一切変更なし：自前の webServer prefix ルート（`/session-guard/rpc`）、
  `settings.register`、`settings.plugin.item` スロット、クライアント注入、
  `llm.listConfigurableProviders()` は公開済み 0.1.5-rc.2 バンドルに対して検証済み
  （`tools/check-api-drift.ps1`、必須アサーション 12/12）。

### 未実施

- 実機 DSH 0.1.5-rc.2 ホストでのライブスモーク（perm-gate の 0.1.5 ラインと同じ状態）。

## 0.2.0-beta.2 — 2026-09-13

### 修正（DSH 0.1.5 互換 — `compat/0.1.5` ブランチ）

- **レジューム入隊のデュアルパス。** DSH 0.1.5 では Inbox が agent-loop の読み取り専用
  投影に変わるため、`agent.followup` が存在しない可能性があります。レジューム時は
  `agent.followup` → `agent.send` → warn 降級（例外は投げない）の順で試行します。
- **レジュームメッセージの `source` に `form: 'instructions'` を追加**（0.1.5 の
  `ContextFormed` 契約。旧バージョンは未知フィールドを無視します）。
- **`webServer.register` を try/catch で保護**：ルート登録の失敗はログのみで、
  `apply` から例外を投げてホストのプラグイン読み込みを壊しません。
- 0.1.5-rc.2 ソースに対し `WebRoute`（exact/prefix + SSE）契約が不変であることを確認。
  クライアントの `fetch('/session-guard/...')` に `/api` プレフィックスは不要です。

## 0.2.0-beta.1 — 2026-09-10

### 追加

- **step 級ゲート（`agent/pre-step`）**：ピーク時、ターン境界で中断するのではなく、**次の step のモデルリクエスト前**にターンを保留します。セッションは次の `agent/pre-step` まで走り、そこでゲートが閉じます（設定 `stepLevelPause`、既定 on）。退峰時は**その場で**再開し、followup メッセージは不要。ゲート条件：ピーク（北京時間）+ 非週末 + `step > 1` + 対象 provider が公式（`providerGuard`）+ リクエスト級 hold なし + このピーク期間でスキップなし。新規モジュール `src/step-gate.js`（純関数 `decideStepHold` + hold / release / abort / timeout エンジン）。
- **`stepResume` ポート + RPC + `/resume`**：`sessionGuard.stepResume(sessionId, {bypass})`、`POST /session-guard/rpc {action:'stepResume'}`、`/resume` のいずれでもゲートを解放。手動再開はそのピーク期間中のゲートを停止します。
- **タイムアウト昇格**：`stepGateTimeoutMs`（既定 300000）でゲートを解放し**ターン級 force 一時停止へ昇格**。長時間ピークでもデッドロックせず、「5 分ごとに 1 step」の滴漏も起きません。
- **「⏸ 一時停止」ボタン**（クライアント、slot `conversation.input.right`、id `session-guard-pause`、order 20 — input-traffic の凍結ボタンの左）。1 秒ごとに `/session-guard/state` をポーリングし、未保留時は無効、保留時は `stepResume` を呼びます。バッジは order 40 へ移動し、step 保留数を表示。
- **新規設定**：`stepLevelPause`、`stepGateTimeoutMs`。
- **新規状態**：`GET /session-guard/state` が `paused: { step, turn }` と `stepGate: { held, since, bypass }` を返し、`/status` は `stepHeld`、`/diag` は `stepGate` を返します。サービス側 `state().paused` は互換のため真偽値のまま（新フィールド `pausedStep`）。

### 修正

- **step 保留とターン級一時停止のデッドロック**：`pauseTask` / `resumeTask` / `cancelTask` が先に step ゲートを解放します。step 保留は `agent/pre-step` 上にあり `assistant/message` / `tool/result` が永遠に来ないため、`safe` 一時停止が永久に待ち、`paused` も永続化されませんでした。

### 変更

- **ピーク入りで実行中ターンを中断しなくなりました**（`stepLevelPause` 有効時、`onEnterPeak` は `stopNextTurn` ではなく step ゲートを arm）。無効時は従来のターン級動作のままです。
- input-traffic の凍結ボタンのラベルは **「凍結して追加」** になりました（`冻结追加` / `Freeze & append` / `동결 후 추가`）。再開ラベルは **「再開して追加」**（`恢复追加` / `Resume & append` / `재개 후 추가`）——ターンを凍結しつつキューを保持する動作で、一時停止ボタンとは別物です。
- **一時停止ボタンはトグルになりました**：「一時停止」/「再開」（グレー無効状態は廃止）。「一時停止」は新規 `stepPause` を呼び、**次の step 境界**でセッションを保留します（step 1 も対象、峰谷 / provider の制限なし）。「再開」は `stepResume`。新ポートメソッド `sessionGuard.stepPause(sessionId)`。
- **SSE プッシュ**：新ルート `GET /session-guard/events?session=<id>` が step ゲート状態の変化を即時配信——ピークで自動的に閉じた瞬間にボタンが「再開」へ変わります。10 秒ポーリングはフォールバックとして残ります。`/state` は `paused.manual` と `stepGate.manual` を返すようになりました。
- **スタイルを input-traffic のコンポーザーボタンに揃えました**（高さ 24px / 角丸 6px / 12px フォント / 同じ border・hover・pressed トークン）。ボタンとステータスバッジの両方。スタイルは `<style data-plugin-css="session-guard-client">` で一度だけ注入。

## Unreleased

### 追加

- **公式ソース二次判定（ピーク × 対象 provider）**：ピーク時は対象ルートが DeepSeek 公式ソースの場合のみ遮断し、ローカル/第三者 provider は通常実行。判定順は明示 `officialProviders` id リスト → 実時間 `baseURL` エンドポイント → catalog 内蔵エンドポイント（pi-ai の `deepseek`）→ 内蔵 id（`deepseek-official`）で、`matchedBy` を返します。新規モジュール：`src/provider.js`（純関数）、`src/provider-directory.js`、`src/deferrals.js`、`src/request-guard.js`、`src/targets.js`、`src/wiring.js`。
- **リクエスト級バックストップ（`agent/request`）**：ピーク入場後に起動したセッション、途中で公式ソースへ切り替えたセッションを捕捉（30s tick は遷移時に `running` だったセッションのみ処理）。既定 `hold` はエラーなしで保留し、退峰の瞬間に解放（`msUntilOffPeak`）；`error` は識別可能な `PEAK_DEFERRED` を投げ延後キューに記録。
- **新しい設定**：`providerGuard`、`officialProviders`、`officialBaseURLs`、`deferredResume`、`deferredResumeText`、`deferredMode`、`deferredMaxHoldMs`（既定 6h）、`guardSubagents`。
- **新しいルート**：`GET /session-guard/provider?provider=<id>`（判定診断）。`/session-guard/status` は `providerGuard` / `held` / `deferred` を返します。
- **ドリフトガード** `tools/check-api-drift.ps1`（4 つの tag で必須 API の存在を検証）。

### 変更

- **DSH 二重バージョン対応（0.1.0-rc.7 … 0.1.2-rc.1）**：`dsh-v0.1.1-rc.2` と `dsh-v0.1.2-rc.1` を 1 つの成果物でカバー。
- **設定面は共通 API のみ**：`settings.register` + `settings.get`。`installSection`（0.1.2+）と削除された `installSettingsSection` は使用しません。任意 API は特性検出して降格。
- **`src/retry.js` は正確な `PEAK_DEFERRED` のみ短絡**：429 / `RATE_LIMIT` / `TRANSPORT` / タイムアウトは引き続き瞬時扱い。DSH のグローバルリトライ（`dsh-llm-retry`）は不変。
- バッジが「ピーク・公式のみ」と「ピーク・全停止」を区別。

## 0.1.4 — 2026-09-09

### 変更

- **公開ベータ**（`0.1.4-beta.1`）：二重バージョン系のベータチャネル向けにバージョン表記・README 互換表・パッケージメタデータを整備。

## 0.1.1 — 2026-08-24

### 追加

- **バックエンド自動リトライ（D9）**：`turn/end` の瞬時失敗（error/429/max-tokens）はアダプティブバックオフの `followup(retryText)` で自動再開。永久失敗（認証/残高/モデル/コンテキスト上限）は停止。ユーザー介入または成功ターンで連続失敗カウントをリセット。
- **凍結/ゲート譲歩**：`isFrozen(sessionId)` が真のときリトライをスキップ、セッションゲートを迂回しません。

### 変更

- `sessionGuard` 冗余ポートが `state(sessionId)` を公開し、`{ queueLocked, lockReason, paused, taskControlAvailable, taskControl }` を返すように。
- HTTP ルート `GET /session-guard/diag` がリトライ状態を含むランタイム診断を返すように。

### 修正

- 週末検出を裸 `getUTCDay()` から `Intl.DateTimeFormat`（設定タイムゾーン使用）に変更し、北京タイムゾーンの 8 時間境界バグを修正。

## 0.1.0 — 2026-08-18

### 追加

- 初回リリース：ピーク自動一時停止（グローバル）、週末モード、`sessionGuard` 冗余ポート + RPC ブリッジによるセッションごとの凍結/再開、カスタムセッションゲート、設定パネル。
