dsh-switchman 1.9.0 → 1.10.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.ja.md CHANGED
@@ -14,7 +14,7 @@ DSHで長く作業していると、悩みが2つ出てくる。1つはセッシ
14
14
 
15
15
  dsh-switchman は [DeepSeek Harness](https://github.com/deepseek-ai/deepseek-harness)(DSH)のプラグインだ。入れると主モデルは「自分で作業する」役から運転指令へ変わる:水位を測り、レーンを選び、タスクを投げ、受け入れを確認する。新モデルではない。DSHに取り付けるディスパッチ規程と設定ページであり、8つのことを行う。
16
16
 
17
- **1. コンテキスト水位:長いセッションを破裂させない。** 毎ターンリアルタイムでセッショントークンを数え、3本の水位線が段階的に締め上げる:80k(soft、調整可)は「そろそろ委譲を」、120k(hard)は1回の読み取り予算を引き締めて収束へ導き、150k(force)で自動引き継ぎ——セッションをフォークして記録に残し、コンテキストを圧縮し、後継を起こして継続する。タスクは切れない。引き継ぎの瞬間に走っているバックグラウンドのサブエージェントも失われない:id・タスク・レポートパスを引き継ぎドキュメントに書き込み、再開したセッションはどこでレポートを受け取るか分かっていて、同じ仕事を二度投げない。各サブエージェントは独立のハード上限を持ち、到達したら HANDOFF サマリを書いて退場する。自動介入が手に合わないときは、いつでも一時的に手動で引き取れる:`/ctx-pause` は水位の動作をすべて止める(計測は走り続け、末尾のリアルタイム水位線は paused に切り替わる、ただ手を出さなくなるだけ)、`/ctx-resume` でいつでも復帰。DSH を再起動しても介入は自動で戻る。一時的に手を離すだけで、恒久的なオフではない。`/ctx-handover` は水位が満ちるのを待たず、同じ引き継ぎを自分から起こす:フォークしてバックアップを残し、コンテキストを圧縮し、後継を起こす(セッションはまずアイドル境界まで導かれるため、結果には数分かかることがある)。
17
+ **1. コンテキスト水位:長いセッションを破裂させない。** 毎ターンリアルタイムでセッショントークンを数え、3本の水位線が段階的に締め上げる:80k(soft、調整可)は「そろそろ委譲を」、120k(hard)は1回の読み取り予算を引き締めて収束へ導き、150k(force)で自動引き継ぎ——引き継ぎドキュメントを書き(追加型のセッションログ自体が完全なバックアップ)、コンテキストを圧縮し、セッションを起こして継続する。タスクは切れない。引き継ぎの瞬間に走っているバックグラウンドのサブエージェントも失われない:id・タスク・レポートパスを引き継ぎドキュメントに書き込み、再開したセッションはどこでレポートを受け取るか分かっていて、同じ仕事を二度投げない。各サブエージェントは独立のハード上限を持ち、到達したら HANDOFF サマリを書いて退場する。自動介入が手に合わないときは、いつでも一時的に手動で引き取れる:`/ctx-pause` は水位の動作をすべて止める(計測は走り続け、末尾のリアルタイム水位線は paused に切り替わる、ただ手を出さなくなるだけ)、`/ctx-resume` でいつでも復帰。DSH を再起動しても介入は自動で戻る。一時的に手を離すだけで、恒久的なオフではない。`/ctx-handover` は水位が満ちるのを待たず、同じ引き継ぎを自分から起こす:引き継ぎドキュメントを書き、コンテキストを圧縮し、セッションを起こす(セッションはまずアイドル境界まで導かれるため、結果には数分かかることがある)。
18
18
 
19
19
  **2. 6つのディスパッチプール:仕事に合ったモデルを。** economy(小口の雑務のバッチ)、mechanical(テンプレート化された書き換え)、main(日常のコーディング)、hard(難問推論と大規模リファクタリング)、vision(画像)、review(独立検証)。設定ページで候補にチェックを付け、優先順を決め、S/A/B/C のグレードを付け、さらにルートごとに思考強度をピン留めできる——強度のドロップダウンはそのモデルが実際に対応するレベルから立ち上がり、汎用の3段ではない。主モデルの毎ターンのプロンプトには必ず `[SWITCHMAN:POOLS]` 推薦表が載り、表に従って投げる。実行モードは3態:オフ / アドバイス / 強制(強制=プール外のモデルは即拒否)。
20
20
 
@@ -23,7 +23,7 @@ dsh-switchman は [DeepSeek Harness](https://github.com/deepseek-ai/deepseek-har
23
23
  - **エージェントチーム**——オンにするとチーム規程(デフォルト委譲+段階的検証+共有タスクボードの規律)を注入し、DSH の Agent Teams を自動で有効にする:主モデルは常駐のチームメイトを引く(`spawn_teammate`)、共有タスクボードに仕事を置く(`team_task_*`)、チームメイトとメッセージをやり取りする。チームを組むべき場面は規律で決まっている:並列化できる独立サブタスク、量が多く自己完結した作業、主コンテキストの水位が既に高い、役割の分離が必要——使い捨ての単発調査は引き続きサブエージェントへ。トグルを戻せばチーム条項は跡形なく消え、実行中のセッションからチームツールを引き上げることもない。
24
24
  - **サブエージェントモデルのホワイトリスト同期**——DSH には「エージェントにサブエージェントのモデル選択を許可する」認可リストがある:プールで選んだのに認可されていないルートは、名指しでの発令が拒否される(チームモードでは ⚠ 表示)。このトグルを入れると、6プールの和集合がまるごとそのリストへ書き込まれる——switchman が唯一の情報源になり、二重管理は不要。リストは「新規セッション」単位のスナップショットで効き、同期はそれ以降に開いたセッションにだけ効く。
25
25
 
26
- セッションヘッダーには即座に分かるフィードバックがある:⚡「自律チーム」バッジ、◇ 現在セッションの実際のモデル。自動引き継ぎの実行中は「引き継ぎ実行中 ・ バックアップセッション / コンテキスト圧縮 / 後継の起動」のライブ表示が出る。
26
+ セッションヘッダーには即座に分かるフィードバックがある:⚡「自律チーム」バッジ、◇ 現在セッションの実際のモデル。自動引き継ぎの実行中は「引き継ぎ実行中 ・ 引き継ぎ文書の作成 / コンテキスト圧縮 / 後継の起動」のライブ表示が出る。
27
27
 
28
28
  **4. 言語設定:一度聞けば、ずっと守る。** 返信・コードコメント・ドキュメントの3言語にそれぞれドロップダウンが1つ。スコープはグローバルまたはプロジェクト単位(`.switchman/lang.json`)。未設定のままでもよい——初回使用時に DSH インターフェースの言語で一度だけ尋ね、覚えれば以後すべてのセッションが守る。
29
29
 
@@ -75,7 +75,7 @@ dsh-switchman は [DeepSeek Harness](https://github.com/deepseek-ai/deepseek-har
75
75
  - **ディスパッチプール**——六枚のカードが三列二段(上段 economy・mechanical・main、下段 hard・vision・review)。カードはプロバイダーごとに候補モデルにチェックを付ける。「手動順」にチェックすると番号付きの優先リストになり、↑ ↓ × で並べ替える。各ルートには思考強度をピン留めできる(既定「レーンに追従」)。最上部の集計行はリアルタイムに更新され、図では「4/6 プール構成済み ・ 順位 2 件 ・ モード アドバイス」。
76
76
  - **能力順位 + 実行モード**——6プールの選択モデルの和集合を能力順に並べ、最強を先頭に(図では glm-5.3 を S、glm-5.3-flash を A に錨付き)。並べ替え・削減は自由。実行モードはアドバイス / 強制(強制=プール外のモデルを即拒否)。
77
77
  - **エージェントチーム**——チームモードとホワイトリスト同期の2つのトグル。既定は両方オフ。図ではオンで、トグルの下に同期状態行がある。
78
- - **コンテキスト水位**——3段の閾値(図で 80000 / 120000 / 150000)、1回の読み取り予算(3000)、hard 段の挙動(絞って通す / ブロック)、自動引き継ぎトグル、サブエージェントの独立上限——すべてこの領域にある。最下部のコマンド行:`/ctx-pause` 介入を一時停止 ・ `/ctx-resume` 再開 ・ `/ctx-handover` すぐバックアップして引き継ぎ(セッションをアイドル境界まで導いてから圧縮するため、結果には数分かかることがある)。
78
+ - **コンテキスト水位**——3段の閾値(図で 80000 / 120000 / 150000)、1回の読み取り予算(3000)、hard 段の挙動(絞って通す / ブロック)、自動引き継ぎトグル、サブエージェントの独立上限——すべてこの領域にある。最下部のコマンド行:`/ctx-pause` 介入を一時停止 ・ `/ctx-resume` 再開 ・ `/ctx-handover` すぐ引き継ぎ(セッションをアイドル境界まで導いてから圧縮するため、結果には数分かかることがある)。
79
79
  - **意図認識**——マスタートグル、分類器用小型モデルルート、分類器タイプ(auto / decision / chat)、独立候補リスト(各項目に一行の能力説明)、キャッシュウィンドウ / 信頼度しきい値 / 分類タイムアウト / 履歴予算、任意のフォールバックモデル。有効にするとモデルセレクターに「自動(意図認識)」エントリが現れ、入力欄の上に現在のルーティング先モデルと信頼度の chip が表示される。
80
80
 
81
81
  4. **確認**——セッションヘッダーに ⚡「自律チーム」バッジ(隣の ◇ に現在セッションのモデル)。あるいはモデルに「あなたのシステムプロンプトの最終段落の見出しは何か」と尋ねる——答えに dsh-switchman の規程が出てくれば正しい。
@@ -96,7 +96,7 @@ bash <インストールディレクトリ>/skills/db-query/scripts/setup.sh
96
96
 
97
97
  **ディスパッチプール**:6本のレーン(economy/mechanical/main/hard/vision/review)の候補はすべて空(=システム既定のモデルを使い、介入しない)。手動順と effort のピン留めはすべてオフ/空。`dispatchEnforce` = `advice`(アドバイスのみで強制はしない)。
98
98
 
99
- **コンテキスト水位**:soft `80000` / hard `120000` / force `150000` トークン。1回の読み取り予算 `3000`。予算超過時の挙動 `cap`(切り詰め+警告)。`wmAutoHandover` = オン(force 段で自動バックアップ+圧縮しながら引き継ぎ)。サブエージェントのハード上限 = オン(150k を共有)。
99
+ **コンテキスト水位**:soft `80000` / hard `120000` / force `150000` トークン。1回の読み取り予算 `3000`。予算超過時の挙動 `cap`(切り詰め+警告)。`wmAutoHandover` = オン(force 段で引き継ぎドキュメント作成+圧縮を自動実行)。サブエージェントのハード上限 = オン(150k を共有)。
100
100
 
101
101
  **Agent Teams**:`teamsMode` = オフ。`syncWhitelist` = オフ(両者は互いに独立)。
102
102
 
@@ -104,7 +104,7 @@ bash <インストールディレクトリ>/skills/db-query/scripts/setup.sh
104
104
 
105
105
  **コンテキストトリム**:`trimEnabled` = オン;`trimMode` = `auto`(完全自動);成長ゲート `22500` + インクリメント `50000` トークン;圧力 `60%` / 緊急 `95%`;保護テール `6` 件;fold ペース上限は毎時 `6` 回;サイドモデルは未設定(セッションモデルを継承)——詳細は下の「自動コンテキストトリム」節で。
106
106
 
107
- **初期状態のポイント**:① 意図認識が既定で使えないのは意図的な設計で、有効化は3ステップ(分類器、候補、トグル)。② Auto の実効ウィンドウは既定で 200000——ガードレールにより 0.8×ウィンドウ ≥ force 段(150000)が保証され、コア圧縮線(160000)は常にスムーズ引き継ぎ線(150000)より後ろにある。③ 既定でいちばん体感できるのは水位の3点セット:80k で委譲を促し、120k で読み取りを収束させ、150k で自動バックアップ引き継ぎ。設定は一切不要。
107
+ **初期状態のポイント**:① 意図認識が既定で使えないのは意図的な設計で、有効化は3ステップ(分類器、候補、トグル)。② Auto の実効ウィンドウは既定で 200000——ガードレールにより 0.8×ウィンドウ ≥ force 段(150000)が保証され、コア圧縮線(160000)は常にスムーズ引き継ぎ線(150000)より後ろにある。③ 既定でいちばん体感できるのは水位の3点セット:80k で委譲を促し、120k で読み取りを収束させ、150k で自動引き継ぎ(文書作成+圧縮)。設定は一切不要。
108
108
 
109
109
  ## 自動コンテキストトリム
110
110
 
@@ -114,7 +114,7 @@ bash <インストールディレクトリ>/skills/db-query/scripts/setup.sh
114
114
 
115
115
  - **`off`**——計測のみ:使用量とキャッシュヒットのサンプリングは動作;バナーなし、fold なし。
116
116
  - **`advisory`**——セッションモデルが自ら fold する:`ctx_trim_fold` と `ctx_trim_status` のツールとプロトコルヘッドを公開。
117
- - **`auto`**(既定)——advisory のすべてに加え、アイドル境界での自動 fold が3段階で動く:成長ゲート(前回の折り返し後の低点から測定した成長 ≥ `trimGrowthTokens`——高位で折り返してもゲートが有効であり続けるためのアンカー——かつ連続圧縮可能インクリメントが `trimIncrementTokens` 以上)、圧力段(コンテキストウィンドウの `trimPressurePercent`)、緊急段(`trimEmergencyPercent`——独自クールダウン付きの機械 fold)。
117
+ - **`auto`**(既定)——advisory のすべてに加え、アイドル境界での自動 fold が3段階で動く:成長ゲート(前回の折り返し後の低点から測定した成長 > `trimGrowthTokens`——高位で折り返してもゲートが有効であり続けるためのアンカー——かつ連続圧縮可能インクリメントが `trimIncrementTokens` 以上)、圧力段(コンテキストウィンドウの `trimPressurePercent`)、緊急段(`trimEmergencyPercent`——独自クールダウン付きの機械 fold)。
118
118
 
119
119
  すべてのキーは「設定 → dsh-switchman」にあり、既定値は `host/config.js` 由来:
120
120
 
@@ -131,16 +131,19 @@ bash <インストールディレクトリ>/skills/db-query/scripts/setup.sh
131
131
  | `trimMaxFoldsPerHour` | `6` | ローリング1時間あたりのサイドモデル fold ペース上限(緊急段は対象外)。 |
132
132
  | `trimSideModel` | 未設定 | サマリを書くサイドモデルのルート。空欄 = セッションの現在モデルを継承。 |
133
133
  | `trimStateDir` | 未設定 | fold 状態ディレクトリの上書き。空欄 = `<dshHome>/.dsh-switchman/state/trim/`。 |
134
+ | `surfaceFold` | `true` | コミット済みの fold をセッション表面へ出荷します(shadow-price 計量イベント + `surfaceOp` replace イベントのペア)。OFF はスプライスのみの view を維持。 |
134
135
 
135
- **トリガーパス。** 段階チェックはアイドル境界で走り、アイドル状態イベントが届かないホストへのフォールバックとして、各モデルストリーム完了後にも走る(セッションごとに 60 秒につき 1 回の評価へスロットル)。すべての決定——fold も no-op も同様に——は、fold 状態ディレクトリ(`trimStateDir` を参照)内の `decisions.log` へ 1 行の JSON として追記され、fold にオフラインの監査証跡を与える。
136
+ **トリガーパス。** 段階チェックはアイドル境界で走り、アイドル状態イベントが届かないホストへのフォールバックとして、各モデルストリーム完了後にも走る(セッションごとに 60 秒につき 1 回の評価へスロットル)。すべての決定——fold も no-op も同様に——は、fold 状態ディレクトリ(`trimStateDir` を参照)内の `decisions.log` へ タイムスタンプ付きの 1 行の `key=value` として追記され、fold にオフラインの監査証跡を与える;行の語彙(`view-applied`、fold の決定/結果行、`surface-replace`、`surface-replace skipped reason=…`)は [docs/context-trim.md](./docs/context-trim.md) に一覧化されています。
136
137
 
138
+ **回線の真実と定常状態。** 決定行は `view=<n>` を持ち、応答が着地した後は `wire=<n>` も持つ——実際のプロバイダプロンプト(非キャッシュ入力 + キャッシュ読み取り + キャッシュ書き込み、ストリームの usage イベントからサンプリング)である。view の推定はメッセージ配列だけを数えるため、固定オーバーヘッド(実測 ≈ 17.3k:システムプロンプト + ツールスキーマ + persona)の分だけ常に回線より小さく読める。したがって圧力段と緊急段は `max(view, wire)` で評価し、プロンプトサイズの計測となるのは `wire` だけである。150k ウィンドウでは、健全なノコギリ波は fold 直後に回線 ≈ 40k ↔ 次の fold で 88–90k(ウィンドウの ≈27%–60%)を往復し、生の成長 ~50k ごとに fold 1 回、天井はウィンドウではなく圧力段によって 90k 付近に固定される。`surface-replace` 行が一度も現れないのに `view` が上昇する場合は、スキップ行(`incomplete-seqs`, `no-service`, `compaction-lock`)を読む。
139
+
140
+ **ホスト圧縮エポック。** fold の参照はメッセージ id と内容ハッシュにアンカーされるため、ホスト側の圧縮が再送履歴を置き換えると帳簿全体が一度に老化します。すべてのブロックが位置を特定できなくなり、view は元の履歴へ静かにフォールバックし(fail-open —— 決定ログには `view-applied applied=0` が記録されます)、プラグインは次のリクエストで成長ベースラインを圧縮後のビューに再アンカーします。ホスト圧縮は最後のバックストップとなるトリム層であり、プラグインの fold は単一ホストエポック内のきめ細かい作業を担います。 一部のディスパッチは、完全に凍結されたリクエスト配列やオプションオブジェクトを渡されます(現在のエージェントループは組み立て済みリクエストをディープフリーズします)。そのようなディスパッチについて、`injectView` は結果を決定ログに報告します:`nothing-to-apply`(位置特定できた fold ブロックがない——生履歴こそが view)、`in-place`/`swapped`(fold 済み view は出荷済み)、または `none`(fold は存在したが凍結されたディスパッチでは運べなかった——回線には生履歴が流れる)。**Surface replace は利用可能なときの出荷経路です**(`surfaceFold`、デフォルトで有効):直列の `agent/turn-stopping` 境界にアイドルスイープを加えた時点で、プラグインはホスト式の shadow-price 計量イベントと、`surfaceOp {op:'replace', startSeq, endSeq}` を運ぶ 1 件の `user/message` 置換イベントを追記します。`sourceEventSeqs` は影となる表面ノードをすべてカバーします——ホスト自身の圧縮と同じ機構なので、コミット済みの fold はソース層から回線へ届き、凍結ディスパッチも例外ではありません。セッションの最近のディスパッチが `none` を記録している間、プラグインは view を計測専用と扱います:水位は代わりにプロバイダ報告の集計を測り(force 段階と自動引き継ぎは働き続け)、fold サイクルはサマライザ呼び出しを空焼きせず一時停止し、トリムバナーは当該行に `wire=raw`(folds not shipping; watermark reads the tally)の印を付けます。surface 機構を持たないホスト(またはフラグが off の場合)は、まさにこの従来動作を保ちます。
137
141
 
138
- **ホスト圧縮エポック。** fold の参照はメッセージ id と内容ハッシュにアンカーされるため、ホスト側の圧縮が再送履歴を置き換えると帳簿全体が一度に老化します。すべてのブロックが位置を特定できなくなり、view は元の履歴へ静かにフォールバックし(fail-open —— 決定ログには `view-applied applied=0` が記録されます)、プラグインは次のリクエストで成長ベースラインを圧縮後のビューに再アンカーします。ホスト圧縮は最後のバックストップとなるトリム層であり、プラグインの fold は単一ホストエポック内のきめ細かい作業を担います。 一部のディスパッチはリクエスト配列やオプションオブジェクトがホストによって凍結されています。その場合プラグインは fail-open し(決定ログに `injected=none` を記録)、モデル応答を実際に生成する可変ディスパッチには折り畳み済みビューが届きます。
139
142
  **fold がキャッシュヒットを守る仕組み。** fold は毎回プレフィックスを一度払い戻す。目指すのは償却コストであり、満点のヒット率ではない。エンジンはキャッシュ契約を守る:fold は追記専用——frontier は前進するだけで、凍結ゾーンは二度と編集されない。view は(履歴, fold 状態)から決定論的に再構築されるため、fold 間でシリアライズ済みプレフィックスはバイト同一のまま立ち、プロバイダキャッシュはヒットを続ける。fold 境界が assistant の tool-call をその tool 結果から切り離すことは決してなく、最後の `trimProtectedTail` メッセージは免除、そしてすべてが fail-open——内部エラーはパススルーに退化し、壊れたリクエストは生まれない。
140
143
 
141
144
  **コンパクション仲裁。** 同じ履歴を巡る2つの自動トリマーは互いに二重要約し合い、frontier を破壊し合う。そこで `cordis.patch.yml` はホストの `dsh-compaction-basic` 行に `auto: false` を設定:context-trim が唯一のセマンティックトリマーになる。手動 `/compact` はそのまま使え、force 段の引き継ぎ(同じ手動パスを借用している)も無傷。オーバーフロー回復はトリムに移る:ウィンドウ超過の試行は一度失敗し、その後緊急段が view を fold して次の試行が収まる。
142
145
 
143
- **fork 継承。** fork されたセッション(サブエージェント fork または引き継ぎバックアップ)は copy-on-fork で親の fold 状態を継承——ただし親の状態が存在し、子の履歴が実際に親の frontier を解決する場合のみ。さもなければ子はクリーンに開始する。子ごとに継承は一度きりで、再起動を跨いで冪等。
146
+ **fork 継承。** fork されたセッション(サブエージェント fork)は copy-on-fork で親の fold 状態を継承——ただし親の状態が存在し、子の履歴が実際に親の frontier を解決する場合のみ。さもなければ子はクリーンに開始する。子ごとに継承は一度きりで、再起動を跨いで冪等。
144
147
 
145
148
  **水位は view を読む。** 水位バナーは保存側の集計ではなくアウトバウンド view のトークン数(fold 後にモデルが実際に見るもの)を報告するので、fold が進んだセッションが水位を hard 段に釘付けにすることはもうない。
146
149
 
@@ -155,7 +158,7 @@ bash <インストールディレクトリ>/skills/db-query/scripts/setup.sh
155
158
 
156
159
  - DSH のアップグレードで出荷プリセットのプラグイン一覧が変わったら、新しい `presets/*.patch.yml` から `cordis.patch.yml` を再同期(doctrine suffix と、`compaction-basic` 行への `auto: false` によるコンパクション仲裁も保持)し、入れ直す。
157
160
  - プロトコル行(`[SWITCHMAN:LANG|POOLS|WATERMARK|TEAMS]`)は意図的に英語のままバイト安定——ローカライズしない。
158
- - `npm pack --dry-run` は監査済みの 50 ファイル / ~205 kB の形状を保つこと(`docs/` のスクリーンショットはパッケージに入らない)。
161
+ - `npm pack --dry-run` は監査済みの 60 ファイル / ~380 kB の形状を保つこと(展開後 ~1.26 MB、`docs/` は含まれない)。
159
162
 
160
163
  ## License
161
164
 
package/README.ko.md CHANGED
@@ -14,7 +14,7 @@ DSH로 오래 일하면 귀찮은 일이 두 가지 생긴다. 첫째, 세션이
14
14
 
15
15
  dsh-switchman은 [DeepSeek Harness](https://github.com/deepseek-ai/deepseek-harness)(DSH) 플러그인이다. 설치하면 주 모델은 '직접 일하기'에서 디스패처로 바뀐다: 수위를 재고, 차선을 고르고, 태스크를 던지고, 인수를 검수한다. 새 모델이 아니다. DSH에 얹는 디스패치 규정과 설정 화면이며, 여덟 가지 일을 한다.
16
16
 
17
- **1. 컨텍스트 수위: 긴 세션도 터지지 않게.** 매 턴 세션 토큰을 실시간으로 세고 세 단계 수위선이 순서대로 조인다: 80k(soft, 조정 가능)은 '이제 위임할 때', 120k(hard)은 1회 읽기 예산을 조이고 마무리로 유도하며, 150k(force)은 자동 인계다 — 세션을 fork해 기록으로 남기고, 컨텍스트를 압축하고, 후속을 깨워 이어 달린다. 태스크는 끊기지 않는다. 인계 순간에 돌고 있던 백그라운드 서브에이전트도 잃지 않는다: id, 태스크, 보고서 경로를 인계 문서에 적어 두어 재개된 세션은 어디서 보고를 받을지 알고 중복 발령하지 않는다. 서브에이전트마다 독립 하드 상한이 있어 도달하면 HANDOFF 요약을 쓰고 퇴장한다. 자동 개입이 손에 맞지 않으면 언제든 임시로 직접 맡을 수 있다: `/ctx-pause`는 수위 동작을 전부 멈춘다(측정은 계속 돌고 뒤에 오는 실시간 수위선은 paused로 바뀐다, 그냥 손을 놓을 뿐), `/ctx-resume`으로 언제든 복구한다 — DSH를 재시작해도 개입은 자동으로 돌아온다. 잠시 손을 놓는 것이지 영구 끄기가 아니다. `/ctx-handover`는 수위가 차오르기를 기다리지 않고 같은 인계를 직접 시작한다: fork로 백업을 남기고, 컨텍스트를 압축하고, 후속을 깨워 이어 달린다(세션은 먼저 유휴 경계로 유도되므로 결과까지 몇 분 걸릴 수 있다).
17
+ **1. 컨텍스트 수위: 긴 세션도 터지지 않게.** 매 턴 세션 토큰을 실시간으로 세고 세 단계 수위선이 순서대로 조인다: 80k(soft, 조정 가능)은 '이제 위임할 때', 120k(hard)은 1회 읽기 예산을 조이고 마무리로 유도하며, 150k(force)은 자동 인계다 — 인계 문서를 적고(추가 전용 세션 로그가 그대로 완전한 백업이다), 컨텍스트를 압축하고, 세션을 깨워 이어 달린다. 태스크는 끊기지 않는다. 인계 순간에 돌고 있던 백그라운드 서브에이전트도 잃지 않는다: id, 태스크, 보고서 경로를 인계 문서에 적어 두어 재개된 세션은 어디서 보고를 받을지 알고 중복 발령하지 않는다. 서브에이전트마다 독립 하드 상한이 있어 도달하면 HANDOFF 요약을 쓰고 퇴장한다. 자동 개입이 손에 맞지 않으면 언제든 임시로 직접 맡을 수 있다: `/ctx-pause`는 수위 동작을 전부 멈춘다(측정은 계속 돌고 뒤에 오는 실시간 수위선은 paused로 바뀐다, 그냥 손을 놓을 뿐), `/ctx-resume`으로 언제든 복구한다 — DSH를 재시작해도 개입은 자동으로 돌아온다. 잠시 손을 놓는 것이지 영구 끄기가 아니다. `/ctx-handover`는 수위가 차오르기를 기다리지 않고 같은 인계를 직접 시작한다: 인계 문서를 적고, 컨텍스트를 압축하고, 세션을 깨워 이어 달린다(세션은 먼저 유휴 경계로 유도되므로 결과까지 몇 분 걸릴 수 있다).
18
18
 
19
19
  **2. 6개 디스패치 풀: 일에 맞는 모델.** economy(잔일 배치), mechanical(템플릿 개작), main(일상 코딩), hard(고난도 추론과 대규모 리팩터링), vision(이미지), review(독립 검증). 설정 페이지에서 후보에 체크하고, 우선순위를 정하고, S/A/B/C 등급을 매기고, 루트별로 추론 강도를 고정할 수도 있다 — 강도 드롭다운은 그 모델이 실제 지원하는 수준에서 오고, 범용 3단이 아니다. 주 모델의 매 턴 프롬프트에는 항상 `[SWITCHMAN:POOLS]` 추천표가 실리고, 표대로 발령한다. 실행 모드는 세 가지: 끔 / 조언 / 강제(강제 = 풀 밖 모델은 즉시 거절).
20
20
 
@@ -23,7 +23,7 @@ dsh-switchman은 [DeepSeek Harness](https://github.com/deepseek-ai/deepseek-harn
23
23
  - **에이전트 팀** — 켜면 팀 규정(기본 위임 + 단계별 검증 + 공유 태스크보드 규율)을 주입하고 DSH의 Agent Teams를 자동으로 켠다: 주 모델은 상주 팀원(`spawn_teammate`)을 뽑고, 공유 태스크보드(`team_task_*`)에 일을 올리고, 팀원과 메시지를 주고받는다. 팀을 꾸릴 때는 명확한 규율이 있다: 병렬로 돌릴 수 있는 독립 서브태스크, 양이 많고 자립적인 작업, 주 컨텍스트 수위가 이미 높음, 역할 분리 필요 — 한 번 쓰고 끝내는 단발 조사는 여전히 subagent로. 토글을 끄면 팀 조항은 흔적 없이 사라지고, 돌고 있는 세션에서 팀 도구를 걷어 가지도 않는다.
24
24
  - **서브에이전트 모델 화이트리스트 동기화** — DSH에는 '에이전트가 서브에이전트 모델을 고르도록 허용' 인가 화이트리스트가 있다: 풀에서 골랐지만 인가되지 않은 루트는 지명 발령이 거절된다(팀 모드에서는 ⚠ 표시). 이 토글을 켜면 6개 풀의 합집합이 통째로 그 화이트리스트에 기록된다 — switchman이 유일한 원천이 되어 이중 설정이 없어진다. 화이트리스트는 '새 세션' 스냅샷으로 적용되고, 동기화는 그 이후에 새로 연 세션에만 적용된다.
25
25
 
26
- 세션 헤더에는 바로 보이는 피드백이 있다: ⚡ '자율 팀' 배지, ◇ 현재 세션의 실제 모델. 자동 인계가 진행 중일 때는 '인계 진행 중 · 백업 세션 / 컨텍스트 압축 / 후속 기상' 실시간 표시가 뜬다.
26
+ 세션 헤더에는 바로 보이는 피드백이 있다: ⚡ '자율 팀' 배지, ◇ 현재 세션의 실제 모델. 자동 인계가 진행 중일 때는 '인계 진행 중 · 인계 문서 작성 / 컨텍스트 압축 / 후속 기상' 실시간 표시가 뜬다.
27
27
 
28
28
  **4. 언어 기본 설정: 한 번 물으면 평생 기억.** 답장, 코드 주석, 문서 세 가지 언어에 각각 드롭다운 하나. 범위는 전역 또는 프로젝트별(`.switchman/lang.json`). 안 두어도 된다 — 처음 쓸 때 DSH 인터페이스 언어로 한 번 물어보고, 기억하면 이후 모든 세션이 따른다.
29
29
 
@@ -75,7 +75,7 @@ dsh-switchman은 [DeepSeek Harness](https://github.com/deepseek-ai/deepseek-harn
75
75
  - **디스패치 풀** — 두 줄에 세 장씩 여섯 카드(위 economy/mechanical/main, 아래 hard/vision/review). 카드는 공급자별로 묶은 후보 모델에 체크. '수동 순서'에 체크하면 번호 매긴 우선 목록이 되고 ↑ ↓ ×로 순서를 정한다. 루트별로 추론 강도를 고정할 수 있다(기본 '레인 따름'). 맨 위 요약 줄은 실시간 갱신되고 그림에서는 '4/6 풀 구성됨 · 순위 2건 · 모드 조언'.
76
76
  - **능력 순위 + 실행 모드** — 6개 풀에서 선택한 모델의 합집합을 능력순으로, 최강이 맨 앞(그림에서 glm-5.3은 S, glm-5.3-flash는 A에 고정). 순서 조정과 삭제가 가능하다. 실행 모드는 조언 / 강제(강제 = 풀 밖 모델 즉시 거절).
77
77
  - **에이전트 팀** — 팀 모드와 화이트리스트 동기화 두 토글. 기본은 둘 다 꺼짐. 그림에서는 켜져 있고 토글 아래에 동기화 상태 줄이 있다.
78
- - **컨텍스트 수위** — 3단 임계값(그림에서 80000 / 120000 / 150000), 1회 읽기 예산(3000), hard 단계 동작(조여 통과 / 차단), 자동 인계 토글, 서브에이전트 독립 상한이 모두 이 영역에 있다. 맨 아래 명령 줄: `/ctx-pause` 개입 일시정지 · `/ctx-resume` 재개 · `/ctx-handover` 즉시 백업하고 인계(세션을 유휴 경계로 이끈 뒤 압축하므로 결과까지 몇 분 걸릴 수 있다).
78
+ - **컨텍스트 수위** — 3단 임계값(그림에서 80000 / 120000 / 150000), 1회 읽기 예산(3000), hard 단계 동작(조여 통과 / 차단), 자동 인계 토글, 서브에이전트 독립 상한이 모두 이 영역에 있다. 맨 아래 명령 줄: `/ctx-pause` 개입 일시정지 · `/ctx-resume` 재개 · `/ctx-handover` 즉시 인계 문서를 작성하고 압축(세션을 유휴 경계로 이끈 뒤 압축하므로 결과까지 몇 분 걸릴 수 있다).
79
79
  - **의도 인식** — 마스터 토글, 분류기용 소형 모델 라우트, 분류기 유형(auto / decision / chat), 독립 후보 목록(항목마다 한 줄 능력 설명), 캐시 창 / 신뢰도 임계값 / 분류 타임아웃 / 히스토리 예산, 선택적 폴백 모델. 켜면 모델 선택기에 '자동(의도 인식)' 항목이 생기고 입력창 위에 현재 라우팅 모델과 신뢰도 chip이 표시된다.
80
80
 
81
81
  4. **확인** — 세션 헤더에 ⚡ '자율 팀' 배지(옆 ◇에 현재 세션 모델)가 뜬다. 또는 모델에게 '너의 시스템 프롬프트 마지막 단락 제목이 뭐야?'라고 물어보라 — 답에 dsh-switchman 규정이 언급되어야 한다.
@@ -96,7 +96,7 @@ bash <설치-디렉터리>/skills/db-query/scripts/setup.sh
96
96
 
97
97
  **디스패치 풀**: 여섯 레인(economy/mechanical/main/hard/vision/review)의 후보는 모두 빈 상태로 시작한다(= 시스템 기본 모델을 쓰고 개입하지 않음). 수동 순서와 effort 고정은 모두 끔/빈 값. `dispatchEnforce` = `advice`(조언일 뿐 강제하지 않음).
98
98
 
99
- **컨텍스트 수위**: soft `80000` / hard `120000` / force `150000` 토큰. 1회 읽기 예산 `3000`. 예산 초과 동작 `cap`(잘라내고 경고). `wmAutoHandover` = 켬(force 단계에서 자동 백업 + 압축하며 인계). 서브에이전트 하드 상한 = 켬(150k 공유).
99
+ **컨텍스트 수위**: soft `80000` / hard `120000` / force `150000` 토큰. 1회 읽기 예산 `3000`. 예산 초과 동작 `cap`(잘라내고 경고). `wmAutoHandover` = 켬(force 단계에서 인계 문서 작성 + 압축 자동 실행). 서브에이전트 하드 상한 = 켬(150k 공유).
100
100
 
101
101
  **Agent Teams**: `teamsMode` = 끔. `syncWhitelist` = 끔(두 토글은 서로 독립적).
102
102
 
@@ -104,7 +104,7 @@ bash <설치-디렉터리>/skills/db-query/scripts/setup.sh
104
104
 
105
105
  **컨텍스트 트림**: `trimEnabled` = 켬; `trimMode` = `auto`(완전 자동); 성장 게이트 `22500` + 증분 `50000` 토큰; 압력 `60%` / 비상 `95%`; 보호 테일 `6`건; fold 케이던스 상한 시간당 `6`회; 사이드 모델 미설정(세션 모델 상속) — 자세한 내용은 아래 "자동 컨텍스트 트림" 절에서.
106
106
 
107
- **기본 상태에서 알아둘 점**: ① 의도 인식이 기본으로 불가능한 것은 의도된 설계고, 세 단계로 켠다(분류기, 후보, 토글). ② Auto의 실효 창은 기본값이 200000이다 — 가드레일이 0.8×창 ≥ force 단계(150000)를 보장하므로, 코어 압축선(160000)은 언제나 부드러운 인계선(150000)보다 뒤에 있다. ③ 기본 상태에서 가장 체감되는 건 수위 3종 세트다: 80k에 위임 알림 / 120k에 읽기 수렴 / 150k에 자동 백업 인계 — 설정은 아무것도 필요 없다.
107
+ **기본 상태에서 알아둘 점**: ① 의도 인식이 기본으로 불가능한 것은 의도된 설계고, 세 단계로 켠다(분류기, 후보, 토글). ② Auto의 실효 창은 기본값이 200000이다 — 가드레일이 0.8×창 ≥ force 단계(150000)를 보장하므로, 코어 압축선(160000)은 언제나 부드러운 인계선(150000)보다 뒤에 있다. ③ 기본 상태에서 가장 체감되는 건 수위 3종 세트다: 80k에 위임 알림 / 120k에 읽기 수렴 / 150k에 자동 인계(문서 작성 + 압축) — 설정은 아무것도 필요 없다.
108
108
 
109
109
  ## 자동 컨텍스트 트림
110
110
 
@@ -114,7 +114,7 @@ bash <설치-디렉터리>/skills/db-query/scripts/setup.sh
114
114
 
115
115
  - **`off`** — 측정만: 사용량과 캐시 히트 샘플링은 계속 돌아간다; 배너 없음, fold 없음.
116
116
  - **`advisory`** — 세션 모델이 스스로 fold 한다: `ctx_trim_fold`와 `ctx_trim_status` 도구와 프로토콜 헤드를 노출.
117
- - **`auto`**(기본값) — 위의 모든 것에 더해 유휴 경계에서 자동 fold가 세 단계로 동작한다: 성장 게이트(지난 접기 후 저점부터 측정한 성장 ≥ `trimGrowthTokens` — 높은 지점에서 접은 후에도 게이트가 계속 작동하도록 유지하는 앵커 — + 연속 압축 가능 증분이 `trimIncrementTokens` 이상), 압력 단계(컨텍스트 창의 `trimPressurePercent`), 비상 단계(`trimEmergencyPercent` — 독립 쿨다운을 가진 기계 fold).
117
+ - **`auto`**(기본값) — 위의 모든 것에 더해 유휴 경계에서 자동 fold가 세 단계로 동작한다: 성장 게이트(지난 접기 후 저점부터 측정한 성장 > `trimGrowthTokens` — 높은 지점에서 접은 후에도 게이트가 계속 작동하도록 유지하는 앵커 — + 연속 압축 가능 증분이 `trimIncrementTokens` 이상), 압력 단계(컨텍스트 창의 `trimPressurePercent`), 비상 단계(`trimEmergencyPercent` — 독립 쿨다운을 가진 기계 fold).
118
118
 
119
119
  모든 키는 설정 → dsh-switchman에 있고, 기본값은 `host/config.js` 기준이다:
120
120
 
@@ -131,16 +131,19 @@ bash <설치-디렉터리>/skills/db-query/scripts/setup.sh
131
131
  | `trimMaxFoldsPerHour` | `6` | 롤링 1시간당 사이드 모델 fold 케이던스 상한(비상 단계는 제외). |
132
132
  | `trimSideModel` | 미설정 | 요약을 쓰는 사이드 모델 라우트. 비어 있으면 세션의 현재 모델을 상속. |
133
133
  | `trimStateDir` | 미설정 | fold 상태 디렉터리 재정의. 비어 있으면 `<dshHome>/.dsh-switchman/state/trim/`. |
134
+ | `surfaceFold` | `true` | 커밋된 fold를 세션 표면으로 발송(shadow-price 계량 이벤트 + `surfaceOp` replace 이벤트 쌍). OFF는 스플라이스 전용 view를 유지. |
134
135
 
135
- **트리거 경로.** 단계 검사는 유휴 경계에서 돌아가고, 유휴 상태 이벤트가 도달하지 않는 호스트를 위한 폴백으로 각 모델 스트림 완료 후에도 돌아간다(세션당 60초에 한 번 평가로 스로틀링). 모든 결정 — fold든 no-op든 마찬가지 — 는 fold 상태 디렉터리(`trimStateDir` 참조) 안의 `decisions.log`에 한 줄의 JSON으로 추가되어 fold에 오프라인 감사 추적을 제공한다.
136
+ **트리거 경로.** 단계 검사는 유휴 경계에서 돌아가고, 유휴 상태 이벤트가 도달하지 않는 호스트를 위한 폴백으로 각 모델 스트림 완료 후에도 돌아간다(세션당 60초에 한 번 평가로 스로틀링). 모든 결정 — fold든 no-op든 마찬가지 — 는 fold 상태 디렉터리(`trimStateDir` 참조) 안의 `decisions.log`에 한 줄의 `key=value`(타임스탬프 포함)로 추가되어 fold에 오프라인 감사 추적을 제공한다; 행 어휘(`view-applied`, fold 결정/결과 행, `surface-replace`, `surface-replace skipped reason=…`)는 [docs/context-trim.md](./docs/context-trim.md)에 정리되어 있다.
136
137
 
138
+ **회선의 진실과 정상 상태.** 결정 행은 `view=<n>`를 담고, 응답이 도착한 뒤에는 `wire=<n>`도 담는다 — 실제 프로바이더 프롬프트(비캐시 입력 + 캐시 읽기 + 캐시 쓰기, 스트림의 usage 이벤트에서 샘플링)이다. view 추정은 messages 배열만 세므로 고정 오버헤드(실측 ≈ 17.3k: 시스템 프롬프트 + 도구 스키마 + persona)만큼 항상 회선보다 작게 읽힌다. 따라서 압력 단계와 비상 단계는 `max(view, wire)`로 평가하며, 프롬프트 크기 측정은 `wire`뿐이다. 150k 창에서 건강한 톱니파는 fold 직후 회선 ≈ 40k ↔ 다음 fold에서 88–90k(창의 ≈27%–60%)를 오가고, 원시 성장 ~50k마다 fold가 한 번 일어나며, 상한은 창이 아니라 압력 단계에 의해 90k 근처로 고정된다. `surface-replace` 행이 한 번도 나타나지 않는데 `view`가 오르면, 스킵 행(`incomplete-seqs`, `no-service`, `compaction-lock`)을 읽어라.
139
+
140
+ **호스트 압축 에포크.** fold 참조는 메시지 id와 내용 해시에 고정되므로, 호스트 자체의 압축이 재전송 기록을 대체하면 장부 전체가 한꺼번에 노후됩니다. 모든 블록이 위치를 찾지 못하고, view는 조용히 원본 기록으로 폴백하며(fail-open — 결정 로그에 `view-applied applied=0`가 기록됨), 플러그인은 다음 요청에서 성장 기준선을 압축 후 뷰에 다시 고정합니다. 호스트 압축이 최후의 트림 계층이고, 플러그인 fold는 하나의 호스트 에포크 안에서 세밀한 작업을 담당합니다. 일부 디스패치는 완전히 동결된 요청 배열이나 옵션 객체를 건네받습니다(현재 에이전트 루프는 조립된 요청을 딥프리즈합니다). 이런 디스패치에 대해 `injectView`는 결과를 결정 로그에 보고합니다: `nothing-to-apply`(위치를 찾은 fold 블록이 없음 — 원본 기록이 곧 view임), `in-place`/`swapped`(fold된 뷰를 실어 보냄), 또는 `none`(fold가 존재했지만 동결된 디스패치는 그것을 실을 수 없음 — 회선에는 원본 기록이 흐름). **Surface replace는 사용 가능할 때의 발송 경로입니다**(`surfaceFold`, 기본값 켬): 직렬 `agent/turn-stopping` 경계에 유휴 스윕을 더한 시점에, 플러그인은 호스트 방식의 shadow-price 계량 이벤트와 `surfaceOp {op:'replace', startSeq, endSeq}`를 실은 단 한 건의 `user/message` 치환 이벤트를 덧붙입니다. `sourceEventSeqs`는 가려진 표면 노드 전부를 커버합니다 — 호스트 자체 압축이 쓰는 바로 그 메커니즘이라, 커밋된 fold는 소스 계층에서 회선까지 도달하며 동결 디스패치도 예외가 아닙니다. 세션의 최근 디스패치가 `none`을 기록하는 동안, 플러그인은 view를 계측 전용으로 취급합니다: 수위는 대신 프로바이더가 보고한 집계를 재고(force 단계와 자동 인계는 계속 동작하며), fold 사이클은 요약기 호출을 태우지 않고 일시 중지하며, 트림 배너는 해당 줄에 `wire=raw`(folds not shipping; watermark reads the tally) 표식을 붙입니다. surface 메커니즘이 없는 호스트(또는 플래그가 꺼진 경우)는 정확히 이 구동 동작을 유지합니다.
137
141
 
138
- **호스트 압축 에포크.** fold 참조는 메시지 id와 내용 해시에 고정되므로, 호스트 자체의 압축이 재전송 기록을 대체하면 장부 전체가 한꺼번에 노후됩니다. 모든 블록이 위치를 찾지 못하고, view는 조용히 원본 기록으로 폴백하며(fail-open — 결정 로그에 `view-applied applied=0`가 기록됨), 플러그인은 다음 요청에서 성장 기준선을 압축 후 뷰에 다시 고정합니다. 호스트 압축이 최후의 트림 계층이고, 플러그인 fold는 하나의 호스트 에포크 안에서 세밀한 작업을 담당합니다. 일부 디스패치는 요청 배열이나 옵션 객체가 호스트에 의해 동결되어 있습니다. 이 경우 플러그인은 fail-open 하고(결정 로그에 `injected=none` 기록), 모델 응답을 실제로 생성하는 가변 디스패치에는 폴드된 뷰가 전달됩니다.
139
142
  **fold가 캐시 히트를 지키는 방식.** fold는 매번 프리픽스를 한 번 재지불한다; 목표는 완벽한 히트율이 아니라 상각 비용이다. 엔진은 캐시 계약을 지킨다: fold는 append-only — frontier는 앞으로만 가고 동결 구역은 다시 편집되지 않는다. view는 (히스토리, fold 상태)에서 결정론적으로 재구성되므로 fold 사이에 직렬화된 프리픽스는 바이트 동일을 유지하고 프로바이더 캐시는 계속 히트한다. fold 경계는 assistant의 tool-call과 그 tool 결과를 절대 분리하지 않고, 마지막 `trimProtectedTail`개 메시지는 면제되며, 모든 것은 fail-open — 내부 오류는 패스스루로 퇴화하고 깨진 요청은 생기지 않는다.
140
143
 
141
144
  **컴팩션 중재.** 하나의 히스토리 위에 자동 트리머가 둘이면 서로 이중 요약하고 서로의 frontier를 부수므로, `cordis.patch.yml`은 호스트의 `dsh-compaction-basic` 행에 `auto: false`를 설정한다: context-trim이 유일한 시맨틱 트리머가 된다. 수동 `/compact`은 그대로 동작하고, force 단계 인계(같은 수동 경로를 빌려 쓴다)도 무사하다. 오버플로 복구는 트림으로 이동한다: 창을 넘은 시도는 한 번 실패하고, 그다음 비상 단계가 view를 fold해 다음 시도는 들어간다.
142
145
 
143
- **fork 상속.** fork된 세션(서브에이전트 fork 또는 인계 백업)은 copy-on-fork로 부모의 fold 상태를 상속한다 — 단, 부모 상태가 존재하고 자식 히스토리가 실제로 부모 frontier를 해석할 때만. 그렇지 않으면 자식은 깨끗하게 시작한다. 자식당 상속은 한 번뿐이며 재시작을 넘어 멱등이다.
146
+ **fork 상속.** fork된 세션(서브에이전트 fork)은 copy-on-fork로 부모의 fold 상태를 상속한다 — 단, 부모 상태가 존재하고 자식 히스토리가 실제로 부모 frontier를 해석할 때만. 그렇지 않으면 자식은 깨끗하게 시작한다. 자식당 상속은 한 번뿐이며 재시작을 넘어 멱등이다.
144
147
 
145
148
  **수위는 view를 읽는다.** 수위 배너는 저장 측 집계가 아니라 아웃바운드 view의 토큰 수(fold 후 모델이 실제로 보는 것)를 보고하므로, fold가 많이 진행된 세션이 수위를 hard 단계에 못 박는 일은 이제 없다.
146
149
 
@@ -155,7 +158,7 @@ bash <설치-디렉터리>/skills/db-query/scripts/setup.sh
155
158
 
156
159
  - DSH 업그레이드 후 출고 프리셋 플러그인 목록이 바뀌면 새 `presets/*.patch.yml`에서 `cordis.patch.yml`을 다시 동기화하고(doctrine suffix와 `compaction-basic` 행의 `auto: false` 압축 중재도 유지) 재설치한다.
157
160
  - 프로토콜 행(`[SWITCHMAN:LANG|POOLS|WATERMARK|TEAMS]`)은 의도적으로 영어 그대로 바이트 안정으로 둔다 — 현지화하지 않는다.
158
- - `npm pack --dry-run`은 감사된 50 파일 / ~205 kB 형태를 유지해야 한다(`docs/` 스크린샷은 패키지에 들어가지 않는다).
161
+ - `npm pack --dry-run`은 감사된 60 파일 / ~380 kB 형태를 유지해야 한다(~1.26 MB 해제, `docs/`는 제외된다).
159
162
 
160
163
  ## License
161
164
 
package/README.md CHANGED
@@ -14,7 +14,7 @@ Two pains creep in once you've worked in DSH for a while. First, sessions get he
14
14
 
15
15
  dsh-switchman is a plugin for [DeepSeek Harness](https://github.com/deepseek-ai/deepseek-harness) (DSH). Once installed, the main model stops doing and starts dispatching: measure the watermark, pick a lane, hand out tasks, check acceptance. It's not a new model — it's a dispatch doctrine hooked onto DSH plus a settings page, and it does eight things:
16
16
 
17
- **1. Context watermark: long sessions don't blow up.** Every turn counts session tokens in real time, and three escalating lines tighten the screws: 80k (soft, adjustable) nudges "time to delegate"; 120k (hard) shrinks the single-read budget and steers toward wrap-up; 150k (force) hands over automatically — forks the session for the record, compacts the context, wakes the fork to continue, task unbroken. Background subagents still running at handover aren't lost either: their ids, tasks, and report paths go into the handover document, so the resumed session knows where to collect reports and never dispatches twice. Every subagent carries its own hard cap and exits after writing its HANDOFF summary. When the automatic intervention doesn't suit you, take over manually: `/ctx-pause` stops all watermark actions (measurement keeps running, the live watermark line switches to paused — it just stops acting), `/ctx-resume` restores them at any time — after a DSH restart the enforcement also comes back on its own, a temporary let-go, not a permanent off; `/ctx-handover` doesn't wait for the watermark to hit the ceiling and starts the same handover on demand: fork a backup, compact the context, wake the continuation (the session is first steered to an idle boundary, so the result can take a few minutes).
17
+ **1. Context watermark: long sessions don't blow up.** Every turn counts session tokens in real time, and three escalating lines tighten the screws: 80k (soft, adjustable) nudges "time to delegate"; 120k (hard) shrinks the single-read budget and steers toward wrap-up; 150k (force) hands over automatically — writes the handover document (the append-only session log is the full-fidelity backup), compacts the context, wakes the session to continue, task unbroken. Background subagents still running at handover aren't lost either: their ids, tasks, and report paths go into the handover document, so the resumed session knows where to collect reports and never dispatches twice. Every subagent carries its own hard cap and exits after writing its HANDOFF summary. When the automatic intervention doesn't suit you, take over manually: `/ctx-pause` stops all watermark actions (measurement keeps running, the live watermark line switches to paused — it just stops acting), `/ctx-resume` restores them at any time — after a DSH restart the enforcement also comes back on its own, a temporary let-go, not a permanent off; `/ctx-handover` doesn't wait for the watermark to hit the ceiling and starts the same handover on demand: write the handover document, compact the context, wake the continuation (the session is first steered to an idle boundary, so the result can take a few minutes).
18
18
 
19
19
  **2. Six dispatch pools: the right model for every job.** Economy (batch small chores), mechanical (template rewrites), main (day-to-day coding), hard (hard reasoning and large refactors), vision (images), review (independent verification). On the settings page you tick candidates, order priorities, grade S/A/B/C, and pin a per-route thinking effort — the effort dropdown lists the levels that model actually supports, not a generic three. Every turn's prompt carries a `[SWITCHMAN:POOLS]` recommendation table, and the main model dispatches by it. Three enforcement modes: off / advice / force (force = out-of-pool models get rejected outright).
20
20
 
@@ -23,7 +23,7 @@ dsh-switchman is a plugin for [DeepSeek Harness](https://github.com/deepseek-ai/
23
23
  - **Agent teams** — once on, the team doctrine is injected (delegate by default + tiered verification + shared task-board discipline) and DSH's Agent Teams is enabled automatically: the main model can pull standing teammates (`spawn_teammate`), put work on a shared task board (`team_task_*`), and message teammates. When to form a team follows clear discipline: parallelizable independent subtasks, bulky self-contained work, high main-context watermark, need for role separation; one-off single-point investigations still go to a subagent. Turn the toggle off and the team clauses vanish without residue, and team tools are never yanked from sessions still running.
24
24
  - **Subagent model whitelist sync** — DSH keeps an authorization whitelist "allow agents to pick models for subagents": routes chosen in a pool but not authorized get rejected when dispatched by name (marked ⚠ in teams mode). Flip this toggle and the union of all six pools is written into that whitelist wholesale — switchman becomes the single source of truth, no double configuration. The whitelist takes effect as a per-new-session snapshot; the sync only affects sessions started afterwards.
25
25
 
26
- The session header gives at-a-glance feedback: the ⚡ "autonomous team" badge and ◇ with the session's actual model; while an auto-handover runs, a live indicator shows "handover in progress · backup session / compacting context / waking the successor".
26
+ The session header gives at-a-glance feedback: the ⚡ "autonomous team" badge and ◇ with the session's actual model; while an auto-handover runs, a live indicator shows "handover in progress · writing handover doc / compacting context / waking the successor".
27
27
 
28
28
  **4. Language preferences: ask once, remember forever.** One dropdown each for replies, code comments, and documents; scope is global or per-project (`.switchman/lang.json`). Skipping is fine — on first use you're asked once in your DSH interface language, and every session obeys the answer afterwards.
29
29
 
@@ -75,7 +75,7 @@ Worth installing even with a single model — watermark control and tiered verif
75
75
  - **Dispatch pools** — six cards in two rows of three: economy, mechanical, main on top; hard, vision, review below. Tick candidate models grouped by provider; tick "manual order" and a card becomes a numbered priority list reorderable with ↑ ↓ ×; every route can pin a thinking effort (default "follow lane"). The summary line at the top updates live — in the shot: "4/6 pools configured · 2 ranked · mode advice".
76
76
  - **Capability ranking + enforcement mode** — the union of selected models across the six pools, ranked by capability, strongest first (the shot anchors glm-5.3 at S and glm-5.3-flash at A), reorderable and removable; enforcement mode advice / force (force = out-of-pool models rejected outright).
77
77
  - **Agent teams** — the two toggles for team mode and whitelist sync, both off by default; in the shot they're on, with a sync status line beneath the toggle.
78
- - **Context watermark** — the three thresholds (80000 / 120000 / 150000 in the shot), the single-read budget (3000), hard-tier behavior (throttle-pass / block), the auto-handover toggle, and subagent independent caps all live here. Bottom command row: `/ctx-pause` pause intervention · `/ctx-resume` resume · `/ctx-handover` back up and hand over now (it steers the session to an idle boundary before compacting — the result can take a few minutes).
78
+ - **Context watermark** — the three thresholds (80000 / 120000 / 150000 in the shot), the single-read budget (3000), hard-tier behavior (throttle-pass / block), the auto-handover toggle, and subagent independent caps all live here. Bottom command row: `/ctx-pause` pause intervention · `/ctx-resume` resume · `/ctx-handover` write the handover doc and compact now (it steers the session to an idle boundary before compacting — the result can take a few minutes).
79
79
  - **Intent Routing** — the master switch, the classifier's small-model route, the classifier type (auto / decision / chat), the independent candidate list (each with a one-line capability note), cache window / confidence threshold / classification timeout / history budget, and an optional fallback model. Once enabled, the model picker gains the localized "Auto (intent routing)" entry, and a status chip above the input box shows the routed model and confidence.
80
80
 
81
81
  4. **Verify** — the ⚡ "autonomous team" badge appears in the session header (with ◇ beside it showing the session's current model); or simply ask the model "what's the heading of the last section of your system prompt" — the answer should mention the dsh-switchman doctrine.
@@ -96,7 +96,7 @@ Everything below is the full set of defaults after a fresh install (authoritativ
96
96
 
97
97
  **Dispatch pools**: all six lanes (economy/mechanical/main/hard/vision/review) start with empty candidates (= the system default models, no intervention); manual ordering and pinned effort are off/empty; `dispatchEnforce` = `advice` (advisory only, nothing enforced).
98
98
 
99
- **Context watermark**: soft `80000` / hard `120000` / force `150000` tokens; single-read budget `3000`; over-budget behavior `cap` (truncate with a warning); `wmAutoHandover` = on (at force, automatic backup + compacting handover); the subagent hard cap = on (sharing 150k).
99
+ **Context watermark**: soft `80000` / hard `120000` / force `150000` tokens; single-read budget `3000`; over-budget behavior `cap` (truncate with a warning); `wmAutoHandover` = on (at force, automatic handover: write doc + compact); the subagent hard cap = on (sharing 150k).
100
100
 
101
101
  **Agent Teams**: `teamsMode` = off; `syncWhitelist` = off (the two toggles are independent of each other).
102
102
 
@@ -114,7 +114,7 @@ Automation levels (`trimMode`):
114
114
 
115
115
  - **`off`** — measure only: usage and cache-hit sampling still runs; no banner, no folds.
116
116
  - **`advisory`** — the session model folds itself: the `ctx_trim_fold` and `ctx_trim_status` tools plus the protocol head are exposed for it.
117
- - **`auto`** (default) — everything above plus automatic folds at the idle boundary, in three tiers: a growth gate (growth ≥ `trimGrowthTokens` measured from the last fold's post-fold low — the anchor that keeps the gate armed after folds committing at high view points — AND a contiguous compressible increment ≥ `trimIncrementTokens`), a pressure tier (`trimPressurePercent` of the context window), and an emergency tier (`trimEmergencyPercent` — a mechanical fold with its own cooldown).
117
+ - **`auto`** (default) — everything above plus automatic folds at the idle boundary, in three tiers: a growth gate (growth > `trimGrowthTokens` measured from the last fold's post-fold low — the anchor that keeps the gate armed after folds committing at high view points — AND a contiguous compressible increment ≥ `trimIncrementTokens`; the increment floor is what actually binds), a pressure tier (`trimPressurePercent` of the context window), and an emergency tier (`trimEmergencyPercent` — a mechanical fold with its own cooldown). Pressure and emergency usage is measured on `max(view, wire)`, i.e. on the real provider prompt when it is known.
118
118
 
119
119
  All keys live in Settings → dsh-switchman; defaults from `host/config.js`:
120
120
 
@@ -131,16 +131,19 @@ All keys live in Settings → dsh-switchman; defaults from `host/config.js`:
131
131
  | `trimMaxFoldsPerHour` | `6` | Side-model fold cadence cap per rolling hour (emergency folds are exempt). |
132
132
  | `trimSideModel` | unset | Route for the summary side model. Empty = inherit the session's current model. |
133
133
  | `trimStateDir` | unset | Fold-state directory override. Empty = `<dshHome>/.dsh-switchman/state/trim/`. |
134
+ | `surfaceFold` | `true` | Ship committed folds onto the session surface (shadow-price + `surfaceOp` replace event pair). OFF keeps the splice-only view. |
134
135
 
135
- **Trigger paths.** Tier checks run at the idle boundary and, as a fallback for hosts where idle status events are unreachable, after each model-stream completion (throttled to one evaluation per 60 s per session). Every decision — folds and no-ops alike — is appended as one JSON line to `decisions.log` in the trim state directory (see `trimStateDir`), giving folds an offline audit trail.
136
+ **Trigger paths.** Tier checks run at the idle boundary and, as a fallback for hosts where idle status events are unreachable, after each model-stream completion (throttled to one evaluation per 60 s per session). Every decision — folds and no-ops alike — is appended as one timestamped `key=value` line to `decisions.log` in the trim state directory (see `trimStateDir`), giving folds an offline audit trail; the row vocabulary (`view-applied`, fold decision/outcome rows, `surface-replace`, `surface-replace skipped reason=…`) is catalogued in [docs/context-trim.md](./docs/context-trim.md).
136
137
 
138
+ **Wire truth and steady state.** Decision rows carry `view=<n>` and, once a response has landed, `wire=<n>` — the real provider prompt (uncached input + cache read + cache write, sampled from the stream's usage event). The view estimate counts the messages array only and always reads smaller than the wire by the fixed overhead (measured ≈ 17.3k: system prompt + tool schemas + persona), so pressure and emergency tiers evaluate on `max(view, wire)`, and only `wire` is a prompt-size reading. On a 150k window the healthy sawtooth runs wire ≈ 40k just after a fold ↔ 88–90k at the next one (≈27%–60% of the window), one fold per ~50k of raw growth, with the ceiling pinned near 90k by the pressure tier rather than by the window. If `view` climbs while no `surface-replace` row ever appears, read the skip rows (`incomplete-seqs`, `no-service`, `compaction-lock`).
139
+
140
+ **Host-compaction epochs.** Fold refs are anchored in message ids and content hashes, so a host-side compaction that replaces the re-send history ages the whole ledger out at once: no block locates, the view silently falls back to raw history (fail-open — the decision log records `view-applied applied=0`), and the plugin re-anchors its growth baseline at the post-compaction view on the next request. The host compaction is thus the backstop trim layer, and plugin folds do the fine-grained work within one host epoch. Some dispatches hand out fully frozen request arrays or option objects (the current agent loop deep-freezes assembled requests); for those `injectView` reports the outcome in the decision log: `nothing-to-apply` (no located fold blocks — raw history IS the view), `in-place`/`swapped` (the fold view shipped), or `none` (a fold existed but the frozen dispatch could not carry it — the wire ships raw history). **Surface replace is the shipping path when available** (`surfaceFold`, default on): at the serial `agent/turn-stopping` boundary plus an idle sweep, the plugin appends the host-style shadow-price metering event and ONE `user/message` replacement carrying `surfaceOp {op:'replace', startSeq, endSeq}` with `sourceEventSeqs` covering every shadowed surface node — the same mechanism the host's own compaction uses — so a committed fold reaches the wire from the source level, frozen dispatches included. While a session's recent dispatches log `none`, the view is meter-only: the watermark measures the provider-reported tally instead (so the force tier and the auto-handover keep working). Folding pauses only when the surface channel is unusable as well — a durable capability probe (live session exposing `append`/`surface.nodes`, no open compaction lock), never a recency window, so a restart no longer freezes the engine. The banner marks the line with `wire=raw` only when no fold block has ever shipped a surface replacement, so a session with a shipped block stays quiet across restarts; hosts without the surface mechanism (or with the flag off) keep exactly the legacy behavior.
137
141
 
138
- **Host-compaction epochs.** Fold refs are anchored in message ids and content hashes, so a host-side compaction that replaces the re-send history ages the whole ledger out at once: no block locates, the view silently falls back to raw history (fail-open — the decision log records `view-applied applied=0`), and the plugin re-anchors its growth baseline at the post-compaction view on the next request. The host compaction is thus the backstop trim layer, and plugin folds do the fine-grained work within one host epoch. Some dispatches hand out fully frozen request arrays or option objects; for those the plugin fails open (`injected=none` in the decision log) while the mutable dispatch that produces the model response still receives the folded view.
139
142
  **How folds preserve cache hits.** Every fold re-pays the prefix once; the goal is amortized cost, not a perfect hit rate. The engine enforces the cache contract: folds are append-only — the frontier only moves forward and the frozen zone is never edited again; the view is rebuilt deterministically from (history, fold state), so the serialized prefix stays byte-identical between folds and the provider cache keeps hitting; fold boundaries never split an assistant tool-call from its tool result; the last `trimProtectedTail` messages are exempt; and everything fails open — an internal error degrades to a pass-through, never a broken request.
140
143
 
141
144
  **Compaction arbitration.** Two automatic trimmers over one history would double-summarize and destroy each other's frontier, so `cordis.patch.yml` sets `auto: false` on the host's `dsh-compaction-basic` rows: context-trim becomes the single semantic trimmer. Manual `/compact` keeps working, and the force-tier handover (which borrows that same manual path) is untouched. Overflow recovery moves to trim: an over-window attempt fails once, then the emergency tier folds the view so the next attempt fits.
142
145
 
143
- **Fork inheritance.** A forked session (a subagent fork or the handover backup) inherits the parent's fold state copy-on-fork — but only when the parent state exists and the child's history actually resolves the parent's frontier; otherwise the child starts clean. One inheritance per child, idempotent across restarts.
146
+ **Fork inheritance.** A forked session (a subagent fork) inherits the parent's fold state copy-on-fork — but only when the parent state exists and the child's history actually resolves the parent's frontier; otherwise the child starts clean. One inheritance per child, idempotent across restarts.
144
147
 
145
148
  **The watermark reads the view.** The watermark banner reports the outbound view's token count (what the model actually sees after folding) instead of the stored tally, so a heavily folded session no longer pins the watermark at the hard tier.
146
149
 
@@ -155,7 +158,7 @@ All keys live in Settings → dsh-switchman; defaults from `host/config.js`:
155
158
 
156
159
  - After a DSH upgrade, if the factory preset plugin list changed, re-sync `cordis.patch.yml` from the new `presets/*.patch.yml` (keeping the doctrine suffix and the compaction arbitration — `auto: false` on the `compaction-basic` rows), then reinstall.
157
160
  - Protocol lines (`[SWITCHMAN:LANG|POOLS|WATERMARK|TEAMS]`) are deliberately English and byte-stable — don't localize them.
158
- - `npm pack --dry-run` should keep the audited 50-file / ~205 kB shape (`docs/` screenshots stay out of the package).
161
+ - `npm pack --dry-run` should keep the audited 60-file / ~380 kB tarball shape (~1.26 MB unpacked). `docs/` stays out of the package (it is not in `package.json files`), while the 11 `README.*` translations are always shipped by npm.
159
162
  - **Zero runtime dependencies — a hard invariant.** Host-plane packages (`@deepseek-ai/schemastery`, cordis, …) are declared as `peerDependencies` only, and the running DSH satisfies them from its own copy. An ordinary `dependencies` entry is physically installed into the profile workspace (`<profile>/node_modules/…`), where it shadows the host's copy for every other profile-resident plugin — this is exactly what crashed the dshmarket plugin market while 1.7.0 carried schemastery as a dependency (two schemastery instances in one process; the market's schemas no longer matched the host's). `scripts/validate.mjs` fails if a `dependencies` entry ever reappears, so installing, updating, or removing dsh-switchman can never touch what dshmarket or any other community bundle resolves at runtime.
160
163
 
161
164
  ## License
package/README.pt.md CHANGED
@@ -14,7 +14,7 @@ Se você trabalha com o DSH, com o tempo esbarra em duas coisas: a sessão fica
14
14
 
15
15
  dsh-switchman é um plugin para o [DeepSeek Harness](https://github.com/deepseek-ai/deepseek-harness) (DSH). Depois de instalado, o modelo principal deixa de “fazer tudo sozinho” e vira um dispatcher: mede o nível de água, escolhe a faixa, entrega as tarefas, confere o resultado. Não é um modelo novo: é um regulamento de despacho plugado ao DSH mais uma interface de configuração. Em concreto, ele faz oito coisas:
16
16
 
17
- **1. Nível de água do contexto: sessões longas não estouram.** A cada turno ele conta os tokens da sessão em tempo real, e três limiares apertam em degraus: 80k (soft, ajustável) lembra que “é hora de delegar”; 120k (hard) aperta o orçamento de leitura por chamada e empurra para encerrar; 150k (force) dispara o handover automático — fork da sessão como cópia de segurança, contexto compactado, continuação despertada: a tarefa não cai no meio. Nem os subagents em segundo plano que ainda estiverem rodando no momento da entrega se perdem: id, descrição da tarefa e caminho do relatório vão para o documento de handover, e a sessão retomada sabe onde coletar os relatórios em vez de despachar o mesmo trabalho de novo. Cada subagent enviado carrega um teto próprio e independente e, ao atingi-lo, sai depois de escrever o resumo HANDOFF. Se a intervenção automática não estiver do seu jeito, assuma o comando manualmente a qualquer momento: `/ctx-pause` interrompe todas as ações do nível (a medição continua rodando, a linha de nível de água ao vivo do final muda para paused — só deixa de agir), `/ctx-resume` retoma a qualquer momento — depois de reiniciar o DSH a intervenção também volta sozinha, você tira o pé por um tempo, não desliga de vez; `/ctx-handover` não espera o nível encher e dispara sob demanda o mesmo handover: fork de uma cópia de segurança, compactação do contexto, despertar da continuação (a sessão é conduzida primeiro até o limite de inatividade, então o resultado pode demorar alguns minutos).
17
+ **1. Nível de água do contexto: sessões longas não estouram.** A cada turno ele conta os tokens da sessão em tempo real, e três limiares apertam em degraus: 80k (soft, ajustável) lembra que “é hora de delegar”; 120k (hard) aperta o orçamento de leitura por chamada e empurra para encerrar; 150k (force) dispara o handover automático — escrita do documento de handover (o log de sessão append-only é a cópia completa), contexto compactado, sessão despertada para continuar: a tarefa não cai no meio. Nem os subagents em segundo plano que ainda estiverem rodando no momento da entrega se perdem: id, descrição da tarefa e caminho do relatório vão para o documento de handover, e a sessão retomada sabe onde coletar os relatórios em vez de despachar o mesmo trabalho de novo. Cada subagent enviado carrega um teto próprio e independente e, ao atingi-lo, sai depois de escrever o resumo HANDOFF. Se a intervenção automática não estiver do seu jeito, assuma o comando manualmente a qualquer momento: `/ctx-pause` interrompe todas as ações do nível (a medição continua rodando, a linha de nível de água ao vivo do final muda para paused — só deixa de agir), `/ctx-resume` retoma a qualquer momento — depois de reiniciar o DSH a intervenção também volta sozinha, você tira o pé por um tempo, não desliga de vez; `/ctx-handover` não espera o nível encher e dispara sob demanda o mesmo handover: escrita do documento de handover, compactação do contexto, despertar da sessão para continuar (a sessão é conduzida primeiro até o limite de inatividade, então o resultado pode demorar alguns minutos).
18
18
 
19
19
  **2. Seis pools de despacho: a cada trabalho, o seu modelo.** Pool leve (economy, trabalho pequeno em lote), pool mecânico (mechanical, reescritas de molde), pool principal (main, codificação do dia a dia), pool difícil (hard, raciocínio pesado e refatoração em grande escala), pool multimodal (vision, leitura de imagens), pool de revisão (review, verificação independente). Na página de configurações você marca os candidatos, ordena as prioridades (com níveis opcionais S/A/B/C) e fixa um reasoning effort por rota — o dropdown lista os níveis que aquele modelo realmente suporta, não três níveis genéricos. A cada turno, o prompt do modelo principal carrega uma tabela de recomendações `[SWITCHMAN:POOLS]`: o trabalho é despachado seguindo a tabela. O modo de execução tem três estados: off / advice / enforce (enforce = modelos fora do pool são recusados na hora).
20
20
 
@@ -23,7 +23,7 @@ dsh-switchman é um plugin para o [DeepSeek Harness](https://github.com/deepseek
23
23
  - **Modo Agent Teams** — ao ligar, injeta a doutrina de equipe (delegar por padrão + verificação em níveis + disciplina do quadro de tarefas compartilhado) e habilita automaticamente os Agent Teams do DSH: o modelo principal pode recrutar colegas permanentes (`spawn_teammate`), despachar trabalho para o quadro compartilhado (`team_task_*`) e trocar mensagens com eles. Há uma disciplina clara sobre quando formar a equipe: subtarefas independentes paralelizáveis, trabalho volumoso e autossuficiente, nível de água do contexto principal já alto, necessidade de separar papéis; investigações pontuais de uma vez só continuam pelo subagent. Desligando a chave de novo, as cláusulas de equipe somem sem resíduo, e as ferramentas de equipe nas sessões em andamento não são recolhidas.
24
24
  - **Sincronização da whitelist de modelos de subagent** — o DSH tem uma whitelist de autorização “Permitir que os agents escolham modelos para os subagents”: rotas escolhidas nos pools mas não autorizadas são recusadas quando o modelo principal as nomeia explicitamente (no modo equipe, são marcadas com ⚠). Com esta chave ligada, a união dos seis pools é gravada de uma vez nessa whitelist — sem configurar dos dois lados: o switchman é a única fonte da verdade. A whitelist vale como snapshot por “nova sessão”: a sincronização só alcança as sessões abertas depois.
25
25
 
26
- O cabeçalho da sessão dá um retorno imediato: badge ⚡ “Equipe autônoma”, ◇ modelo em uso na sessão atual; durante um handover automático aparece um aviso em tempo real do tipo “Handover em andamento · backup da sessão / compactação do contexto / despertar da continuação”.
26
+ O cabeçalho da sessão dá um retorno imediato: badge ⚡ “Equipe autônoma”, ◇ modelo em uso na sessão atual; durante um handover automático aparece um aviso em tempo real do tipo “Handover em andamento · escrevendo documento de handover / compactação do contexto / despertar da continuação”.
27
27
 
28
28
  **4. Preferências de idioma: pergunta uma vez, lembra para sempre.** Um dropdown para cada um dos três idiomas — respostas, comentários de código, documentos — com escopo à escolha: global ou por projeto (`.switchman/lang.json`). Pode deixar em branco: no primeiro uso perguntam uma vez, no idioma da interface do DSH, e daí em diante toda sessão segue sozinha.
29
29
 
@@ -75,7 +75,7 @@ Só um modelo? Ainda vale a pena instalar — o controle do nível de água e a
75
75
  - **Pools de despacho** — seis cards em duas fileiras de três: em cima leve / mecânico / principal; embaixo difícil / multimodal / revisão. Em cada card você marca os candidatos agrupados por provider; marque “ordem manual” e ele vira uma lista de prioridade numerada, reordenável com ↑ ↓ ×; ao lado de cada rota dá para fixar o reasoning effort (padrão “seguir a faixa”). A linha de resumo no topo se atualiza em tempo real; na captura: “4/6 pools configurados · 2 no ranking · modo advice”.
76
76
  - **Ranking de capacidade + modo de execução** — a união dos modelos escolhidos nos seis pools, ordenada por capacidade com os mais fortes na frente (na captura glm-5.3 ancorado em S e glm-5.3-flash ancorado em A); dá para reordenar e cortar; o modo de execução vai de advice / enforce (enforce = modelos fora do pool são recusados na hora).
77
77
  - **Equipe de agentes** — as duas chaves, modo equipe e sincronização da whitelist, começam desligadas; na captura estão ligadas, e abaixo de cada uma há uma linha de status de sincronização.
78
- - **Nível de água do contexto** — os três limiares (na captura 80000 / 120000 / 150000), o orçamento de leitura por chamada (3000), o comportamento do limiar hard (deixa passar com limitação / bloqueia), a chave do handover automático e o teto independente dos subagents ficam todos nesta área. Uma linha de comandos embaixo: `/ctx-pause` pausa as intervenções · `/ctx-resume` retoma · `/ctx-handover` faz backup e entrega na hora (ele conduz a sessão até o limite de inatividade antes de compactar: o resultado pode levar alguns minutos).
78
+ - **Nível de água do contexto** — os três limiares (na captura 80000 / 120000 / 150000), o orçamento de leitura por chamada (3000), o comportamento do limiar hard (deixa passar com limitação / bloqueia), a chave do handover automático e o teto independente dos subagents ficam todos nesta área. Uma linha de comandos embaixo: `/ctx-pause` pausa as intervenções · `/ctx-resume` retoma · `/ctx-handover` escreve o documento e entrega na hora (ele conduz a sessão até o limite de inatividade antes de compactar: o resultado pode levar alguns minutos).
79
79
  - **Roteamento por intenção** — a chave mestra, a rota do modelo pequeno do classificador, o tipo de classificador (auto / decision / chat), a lista de candidatos independente (cada um com sua nota de capacidade), janela de cache / limiar de confiança / timeout / orçamento de histórico e um modelo de fallback opcional. Ligado, o seletor de modelos ganha a entrada localizada “Automático (roteamento por intenção)” e acima da caixa de entrada aparece o chip com o modelo roteado e a confiança.
80
80
 
81
81
  4. **Verifique** — no cabeçalho da sessão aparece o badge ⚡ “Equipe autônoma” (ao lado, o ◇ mostra o modelo da sessão atual); ou pergunte direto ao modelo “qual é o título da última seção do seu system prompt?” — a resposta deve mencionar a doutrina dsh-switchman.
@@ -96,7 +96,7 @@ Estes são todos os valores logo depois de uma instalação nova (fonte autorita
96
96
 
97
97
  **Pools de despacho**: as seis faixas (economy/mechanical/main/hard/vision/review) começam sem candidatos (= os modelos padrão do sistema, sem intervenção); ordem manual e effort fixado desligados/vazios; `dispatchEnforce` = `advice` (só aconselha, não obriga).
98
98
 
99
- **Nível de água do contexto**: soft `80000` / hard `120000` / force `150000` tokens; orçamento de leitura por chamada `3000`; comportamento ao estourar o orçamento `cap` (corta e avisa); `wmAutoHandover` = ligado (no force, backup automático + entrega com compactação); o teto dos subagents = ligado (150k compartilhadas).
99
+ **Nível de água do contexto**: soft `80000` / hard `120000` / force `150000` tokens; orçamento de leitura por chamada `3000`; comportamento ao estourar o orçamento `cap` (corta e avisa); `wmAutoHandover` = ligado (no force, escrita do documento de handover + compactação automáticas); o teto dos subagents = ligado (150k compartilhadas).
100
100
 
101
101
  **Agent Teams**: `teamsMode` = desligado; `syncWhitelist` = desligado (as duas chaves são independentes entre si).
102
102
 
@@ -104,7 +104,7 @@ Estes são todos os valores logo depois de uma instalação nova (fonte autorita
104
104
 
105
105
  **Trim de contexto**: `trimEnabled` = ligado; `trimMode` = `auto` (totalmente automático); portão de crescimento `22500` + incremento `50000` tokens; pressão `60%` / emergência `95%`; cauda protegida `6` mensagens; teto de cadência de folds `6` por hora; modelo secundário não definido (herda o modelo da sessão) — detalhes na seção «Trim automático do contexto» abaixo.
106
106
 
107
- **Observações de fábrica**: ① o roteamento por intenção vir indisponível de fábrica é proposital — três passos para ligar (classificador, candidatos, chave); ② a janela efetiva do Auto já nasce em 200000 — o guard-rail garante 0.8×janela ≥ force (150000), então a linha de compactação do núcleo (160000) fica sempre depois da linha de entrega suave (150000); ③ o que mais se sente de fábrica é o trio de níveis: 80k lembra de delegar / 120k aperta a leitura / 150k faz backup e entrega sozinho — sem nenhuma configuração.
107
+ **Observações de fábrica**: ① o roteamento por intenção vir indisponível de fábrica é proposital — três passos para ligar (classificador, candidatos, chave); ② a janela efetiva do Auto já nasce em 200000 — o guard-rail garante 0.8×janela ≥ force (150000), então a linha de compactação do núcleo (160000) fica sempre depois da linha de entrega suave (150000); ③ o que mais se sente de fábrica é o trio de níveis: 80k lembra de delegar / 120k aperta a leitura / 150k entrega sozinho (documento + compactação) — sem nenhuma configuração.
108
108
 
109
109
  ## Trim automático do contexto
110
110
 
@@ -114,7 +114,7 @@ Níveis de automação (`trimMode`):
114
114
 
115
115
  - **`off`** — só medição: a amostragem de uso e de acertos de cache continua rodando; sem banner, sem folds.
116
116
  - **`advisory`** — o modelo da sessão dobra sozinho: as ferramentas `ctx_trim_fold` e `ctx_trim_status` mais o cabeçalho de protocolo ficam expostas.
117
- - **`auto`** (padrão) — tudo isso mais folds automáticos na fronteira de ociosidade, em três degraus: um portão de crescimento (crescimento ≥ `trimGrowthTokens` medido a partir da mínima pós-dobra do último fold — a âncora que mantém o portão armado após dobras confirmadas em pontos altos da view — E um incremento comprimível contíguo ≥ `trimIncrementTokens`), um degrau de pressão (`trimPressurePercent` da janela de contexto) e um degrau de emergência (`trimEmergencyPercent` — um fold mecânico com cooldown próprio).
117
+ - **`auto`** (padrão) — tudo isso mais folds automáticos na fronteira de ociosidade, em três degraus: um portão de crescimento (crescimento > `trimGrowthTokens` medido a partir da mínima pós-dobra do último fold — a âncora que mantém o portão armado após dobras confirmadas em pontos altos da view — E um incremento comprimível contíguo ≥ `trimIncrementTokens`), um degrau de pressão (`trimPressurePercent` da janela de contexto) e um degrau de emergência (`trimEmergencyPercent` — um fold mecânico com cooldown próprio).
118
118
 
119
119
  Todas as chaves ficam em Configurações → dsh-switchman; os padrões vêm de `host/config.js`:
120
120
 
@@ -131,16 +131,19 @@ Todas as chaves ficam em Configurações → dsh-switchman; os padrões vêm de
131
131
  | `trimMaxFoldsPerHour` | `6` | Teto de cadência de folds por hora rolante para o modelo secundário (os de emergência ficam fora). |
132
132
  | `trimSideModel` | não definida | Rota do modelo secundário que escreve os resumos. Vazia = herdar o modelo atual da sessão. |
133
133
  | `trimStateDir` | não definido | Sobrepõe o diretório do estado de folds. Vazio = `<dshHome>/.dsh-switchman/state/trim/`. |
134
+ | `surfaceFold` | `true` | Envia os folds confirmados para a superfície da sessão (par de eventos: medição shadow-price + replace com `surfaceOp`). OFF mantém a view apenas com splices. |
134
135
 
135
- **Caminhos do gatilho.** As verificações de degraus rodam na fronteira de ociosidade e, como fallback para hosts onde os eventos de estado de ociosidade são inalcançáveis, após cada conclusão do fluxo do modelo (limitadas a uma avaliação a cada 60 s por sessão). Cada decisão — folds e no-ops igualmente — é anexada como uma linha JSON a `decisions.log` no diretório do estado de folds (veja `trimStateDir`), dando aos folds uma trilha de auditoria offline.
136
+ **Caminhos do gatilho.** As verificações de degraus rodam na fronteira de ociosidade e, como fallback para hosts onde os eventos de estado de ociosidade são inalcançáveis, após cada conclusão do fluxo do modelo (limitadas a uma avaliação a cada 60 s por sessão). Cada decisão — folds e no-ops igualmente — é anexada como uma linha `key=value` com timestamp a `decisions.log` no diretório do estado de folds (veja `trimStateDir`), dando aos folds uma trilha de auditoria offline; o vocabulário de linhas (`view-applied`, linhas de decisão/resultado de folds, `surface-replace`, `surface-replace skipped reason=…`) está catalogado em [docs/context-trim.md](./docs/context-trim.md).
136
137
 
138
+ **Verdade do fio e estado estacionário.** As linhas de decisão carregam `view=<n>` e, depois que uma resposta chega, `wire=<n>` — o prompt real do provedor (entrada sem cache + leitura de cache + escrita de cache, amostrado do evento de uso do stream). A estimativa da view conta apenas o array de mensagens e sempre lê menos que o fio, pelo overhead fixo (medido ≈ 17.3k: system prompt + esquemas de ferramentas + persona), então os degraus de pressão e de emergência avaliam sobre `max(view, wire)`, e só `wire` é uma leitura do tamanho do prompt. Numa janela de 150k o dente-de-serra saudável deixa o fio em ≈ 40k logo após um fold ↔ 88–90k no seguinte (≈27%–60% da janela), um fold a cada ~50k de crescimento bruto, com o teto fixado perto de 90k pelo degrau de pressão em vez da janela. Se `view` sobe sem que nenhuma linha `surface-replace` apareça, leia as linhas de salto (`incomplete-seqs`, `no-service`, `compaction-lock`).
139
+
140
+ **Épocas de compactação do host.** As referências de fold são ancoradas em ids de mensagens e hashes de conteúdo; quando o próprio host compacta o histórico reenviado, o livro inteiro envelhece de uma vez: nenhum bloco se localiza, a view retrocede silenciosamente ao histórico bruto (fail-open — o registro de decisões anota `view-applied applied=0`) e o plugin reancora sua linha de base de crescimento na view pós-compactação na requisição seguinte. A compactação do host é, assim, a camada de aparo de último recurso; os folds do plugin fazem o trabalho fino dentro de uma época do host. Alguns despachos entregam arrays de solicitação ou objetos de opções totalmente congelados (o laço de agente atual congela em profundidade as requisições montadas); para eles, o `injectView` informa o resultado no registro de decisões: `nothing-to-apply` (nenhum bloco de fold localizado — o histórico bruto É a view), `in-place`/`swapped` (a view dobrada seguiu com a requisição) ou `none` (havia um fold, mas o despacho congelado não podia carregá-lo — o histórico bruto segue pelo fio). **A substituição de superfície é o caminho de envio quando disponível** (`surfaceFold`, ativado por padrão): na fronteira serial `agent/turn-stopping` mais uma varredura de ociosidade, o plugin anexa o evento de medição shadow-price no estilo do host e UM replacement `user/message` carregando `surfaceOp {op:'replace', startSeq, endSeq}` com `sourceEventSeqs` cobrindo cada nó de superfície sombreado — o mesmo mecanismo que a própria compactação do host usa —, de modo que um fold confirmado chega ao fio a partir do nível de origem, despachos congelados incluídos. Enquanto os despachos recentes de uma sessão registram `none`, o plugin trata a view como somente medição: o nível de água mede em vez disso a contagem relatada pelo provedor (o degrau force e a entrega automática continuam funcionando), os ciclos de fold pausam em vez de queimar chamadas ao resumidor, e o banner de aparo marca a linha com `wire=raw` (folds not shipping; watermark reads the tally); hosts sem o mecanismo de superfície (ou com a flag desligada) mantêm exatamente esse comportamento antigo.
137
141
 
138
- **Épocas de compactação do host.** As referências de fold são ancoradas em ids de mensagens e hashes de conteúdo; quando o próprio host compacta o histórico reenviado, o livro inteiro envelhece de uma vez: nenhum bloco se localiza, a view retrocede silenciosamente ao histórico bruto (fail-open — o registro de decisões anota `view-applied applied=0`) e o plugin reancora sua linha de base de crescimento na view pós-compactação na requisição seguinte. A compactação do host é, assim, a camada de aparo de último recurso; os folds do plugin fazem o trabalho fino dentro de uma época do host. Alguns despachos entregam arrays de solicitação ou objetos de opções totalmente congelados; para eles o plugin falha abertamente (`injected=none` no registro de decisões), enquanto o despacho mutável que produz a resposta do modelo ainda recebe a visão dobrada.
139
142
  **Como os folds preservam acertos de cache.** Cada fold repaga o prefixo uma vez; a meta é custo amortizado, não taxa de acerto perfeita. O motor faz valer o contrato de cache: folds são somente-acréscimo — a frontier só avança e a zona congelada nunca é editada de novo; a view é reconstruída de forma determinística a partir de (histórico, estado de folds), então o prefixo serializado fica idêntico byte a byte entre folds e o cache do provedor continua acertando; as fronteiras de fold jamais separam uma tool-call do assistant do seu resultado; as últimas `trimProtectedTail` mensagens ficam isentas; e tudo falha aberto — um erro interno degrada a pass-through, nunca a uma requisição quebrada.
140
143
 
141
144
  **Arbitragem da compactação.** Dois trimmers automáticos sobre o mesmo histórico resumiriam duas vezes e destruiriam a frontier um do outro, então o `cordis.patch.yml` põe `auto: false` nas linhas do `dsh-compaction-basic` do host: o context-trim vira o único trimmer semântico. O `/compact` manual continua funcionando, e a entrega do degrau force (que empresta justamente esse caminho manual) fica intacta. A recuperação de overflow passa para o trim: a tentativa acima da janela falha uma vez, depois o degrau de emergência dobra a view para a próxima tentativa caber.
142
145
 
143
- **Herança de fork.** Uma sessão forkada (fork de subagente ou backup de entrega) herda o estado de folds do pai por cópia-no-fork — mas só quando o estado do pai existe e o histórico do filho realmente resolve a frontier do pai; senão o filho começa limpo. Uma herança por filho, idempotente entre reinícios.
146
+ **Herança de fork.** Uma sessão forkada (fork de subagente) herda o estado de folds do pai por cópia-no-fork — mas só quando o estado do pai existe e o histórico do filho realmente resolve a frontier do pai; senão o filho começa limpo. Uma herança por filho, idempotente entre reinícios.
144
147
 
145
148
  **O banner de níveis lê a view.** O banner de níveis informa a contagem de tokens da view de saída (o que o modelo de fato vê depois da dobra) em vez da soma armazenada — uma sessão muito dobrada não crava mais o nível no degrau hard.
146
149
 
@@ -155,7 +158,7 @@ Todas as chaves ficam em Configurações → dsh-switchman; os padrões vêm de
155
158
 
156
159
  - Depois de um upgrade do DSH que mude a lista de plugins dos presets de fábrica, ressincronize `cordis.patch.yml` a partir dos novos `presets/*.patch.yml` (mantenha o doctrine suffix e a arbitragem da compactação — `auto: false` nas linhas do `compaction-basic`) e reinstale.
157
160
  - As linhas de protocolo (`[SWITCHMAN:LANG|POOLS|WATERMARK|TEAMS]`) ficam deliberadamente em inglês e estáveis a byte — não as localize.
158
- - `npm pack --dry-run` deve continuar na forma auditada de 50 arquivos / ~205 kB (os screenshots de `docs/` não vão no pacote).
161
+ - `npm pack --dry-run` deve continuar na forma auditada de 60 arquivos / ~380 kB (~1,26 MB descompactado; `docs/` fica de fora).
159
162
 
160
163
  ## License
161
164