dsh-switchman 1.11.6 → 1.11.7

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/cordis.patch.yml CHANGED
@@ -650,9 +650,9 @@
650
650
  langScope: project
651
651
  dispatchEnforce: advice
652
652
  wmSoftTokens: 80000
653
- wmHardTokens: 95000
654
- wmForceTokens: 150000
655
- wmReadBudgetTokens: 3000
653
+ wmHardTokens: 100000
654
+ wmForceTokens: 200000
655
+ wmReadBudgetTokens: 3500
656
656
  wmDenyMode: cap
657
657
  wmAutoHandover: true
658
658
  wmSubagentCap: true
@@ -661,15 +661,15 @@
661
661
  teamsMode: true
662
662
  syncWhitelist: true
663
663
  trimEnabled: true
664
- trimMode: auto
664
+ trimMode: advisory
665
665
  trimGrowthTokens: 22500
666
- trimIncrementTokens: 25000
667
- trimPressurePercent: 65
668
- trimEmergencyPercent: 95
669
- trimAdvisoryPercent: 65
670
- trimAdvisoryCriticalPercent: 95
666
+ trimIncrementTokens: 45000
667
+ trimPressurePercent: 45
668
+ trimEmergencyPercent: 90
669
+ trimAdvisoryPercent: 50
670
+ trimAdvisoryCriticalPercent: 80
671
671
  trimWindowTokens: 0
672
- trimProtectedTail: 10
672
+ trimProtectedTail: 6
673
673
  trimMaxFoldsPerHour: 30
674
674
  trimLadderEnabled: true
675
675
  trimProtectTaskIntent: true
package/host/config.js CHANGED
@@ -84,15 +84,16 @@ export const Config = z.object({
84
84
  * the plugin UI into that locale (extra locales resolve
85
85
  * client-side from the inline EXTRA_UI_DICTS table, falling back
86
86
  * to English). */
87
- uiLocale: z.union(["auto", "en", "zh", "zh-TW", "ja", "ko", "de", "es", "fr", "it", "pt", "ru"]).default("auto").volatile(),
87
+ uiLocale: z.union(["auto", "en", "zh", "zh-TW", "ja", "ko", "de", "es", "fr", "it", "pt", "ru"]).default("zh").volatile(),
88
88
 
89
89
  // --- Phase 1: project language preference -----------------------------
90
90
  /** Where the three language slots live: "global" = these profile-level
91
91
  * fields below; "project" = each project's .switchman/lang.json (per
92
92
  * session cwd; missing file = ask once per session and save there). */
93
- langScope: z.union(["global", "project"]).default("global").volatile(),
94
- /** Language for conversational replies. Empty = ask once, then remember. */
95
- langConversation: z.string().default("").volatile(),
93
+ langScope: z.union(["global", "project"]).default("project").volatile(),
94
+ /** Language for conversational replies (shipped default zh-CN). Empty =
95
+ * ask once, then remember. */
96
+ langConversation: z.string().default("zh-CN").volatile(),
96
97
  /** Language for code comments. Empty = follow langConversation. */
97
98
  langComments: z.string().default("").volatile(),
98
99
  /** Language for documents the agent authors. Empty = follow langConversation. */
@@ -131,23 +132,22 @@ export const Config = z.object({
131
132
 
132
133
  // --- Phase 3: context watermark control --------------------------------
133
134
  /** Soft watermark: advisory banner + delegation nudge (tokens). */
134
- wmSoftTokens: z.number().min(1000).default(80000).volatile(),
135
- /** Hard watermark: read budget tightens, wrap-up advised (tokens). 95k
136
- * sits just under the trim pressure line (65% of the 150k window ≈
137
- * 97.5k): past
138
- * this point the fold engine is already folding, so per-call read
139
- * budgets must tighten at the SAME boundary — agent sessions grow in
140
- * PULSES (one large file read = tens of thousands of tokens injected
141
- * at once, faster than any fold can commit), and the read budget is
142
- * the only preventive valve on the pulse source. */
143
- wmHardTokens: z.number().min(2000).default(95000).volatile(),
135
+ wmSoftTokens: z.number().min(1000).max(10000000).default(80000).volatile(),
136
+ /** Hard watermark: read budget tightens, wrap-up advised (tokens). 100k
137
+ * sits just above the trim pressure line (45% of the 200k effective
138
+ * cap = 90k): by the time the hard tier tightens, the fold engine is
139
+ * already folding — the read budget stays the preventive valve on the
140
+ * pulse source: agent sessions grow in PULSES (one large file read =
141
+ * tens of thousands of tokens injected at once, faster than any fold
142
+ * can commit). */
143
+ wmHardTokens: z.number().min(2000).max(10000000).default(100000).volatile(),
144
144
  /** Force watermark: handover document + compaction (tokens). */
145
- wmForceTokens: z.number().min(3000).default(150000).volatile(),
145
+ wmForceTokens: z.number().min(3000).max(10000000).default(200000).volatile(),
146
146
  /** Per-TURN read budget (inspection C16 — the name predates the turn
147
147
  * accounting): read/glob/grep/bash results accumulate against it within
148
148
  * one turn; the account resets after 15 idle minutes and the pre/post
149
149
  * gates act at 2.4× this value (CEILING_MULTIPLE in context-watch.js). */
150
- wmReadBudgetTokens: z.number().min(200).default(3000).volatile(),
150
+ wmReadBudgetTokens: z.number().min(200).max(10000000).default(3500).volatile(),
151
151
  /** Hard-tier behavior: cap reads and advise, or deny outright. */
152
152
  wmDenyMode: z.union(["cap", "deny"]).default("cap").volatile(),
153
153
  /** Force tier triggers the handover (document + compaction) automatically. */
@@ -155,7 +155,7 @@ export const Config = z.object({
155
155
  /** Cap subagent contexts at wmSubagentForceTokens. */
156
156
  wmSubagentCap: z.boolean().default(true).volatile(),
157
157
  /** Subagent hard cap; 0 = share wmForceTokens. */
158
- wmSubagentForceTokens: z.number().min(0).default(0).volatile(),
158
+ wmSubagentForceTokens: z.number().min(0).max(10000000).default(0).volatile(),
159
159
  /** Scale subagent watermark tiers to the subagent's own model window:
160
160
  * force = min(static force [or wmSubagentForceTokens], window × ratio);
161
161
  * soft/hard shrink by the same factor to preserve tier spacing. The ratio
@@ -173,15 +173,19 @@ export const Config = z.object({
173
173
  * doctrine, no whitelist detection (the DSH factory conservative team
174
174
  * policy takes over); the bundle is never disabled and the whitelist is
175
175
  * never cleared. */
176
- teamsMode: z.boolean().default(false).volatile(),
177
- /** Replace-sync the six-pool union into DSH's subagent model-selection
178
- * whitelist (`subagent-model-selection-settings`) whenever the teams
176
+ teamsMode: z.boolean().default(true).volatile(),
177
+ /** Replace-sync the dispatch model union (the six pools plus modelRank)
178
+ * into DSH's subagent model-selection whitelist
179
+ * (`subagent-model-selection-settings`) whenever the teams
179
180
  * orchestration runs — an INDEPENDENT switch: it does not require
180
181
  * teamsMode, and teamsMode alone does not sync. switchman is the single
181
182
  * source of truth: the deduplicated union overwrites allowedModels
182
- * wholesale. The whitelist only applies to top-level sessions composed
183
+ * wholesale. modelRank belongs in the union because its head is the
184
+ * dispatch fallback route and enforce mode denies anything outside
185
+ * "pools or modelRank" — leaving it out would strand that route.
186
+ * The whitelist only applies to top-level sessions composed
183
187
  * afterwards. */
184
- syncWhitelist: z.boolean().default(false).volatile(),
188
+ syncWhitelist: z.boolean().default(true).volatile(),
185
189
 
186
190
  // --- Intent recognition: classifier-routed "auto" model ----------------
187
191
  /** Master switch for intent routing (design: .dsh-switchman/plans/
@@ -238,7 +242,7 @@ export const Config = z.object({
238
242
  * ceil(wmForceTokens / 0.8) so the smooth handover always fires before
239
243
  * the 0.8×-window auto-compaction (see effectiveContextWindow in
240
244
  * host/intent.js). */
241
- intentContextWindow: z.number().min(1024).default(200000).volatile(),
245
+ intentContextWindow: z.number().min(1024).default(250000).volatile(),
242
246
  /** Optional fallback route after classification fails when no prior route
243
247
  * is available; empty = the first candidate. An optional effort pin
244
248
  * overrides the fallback model's default. */
@@ -254,27 +258,48 @@ export const Config = z.object({
254
258
  * "advisory" = expose ctx_trim_fold/ctx_trim_status + the protocol head
255
259
  * so the session model can fold itself, "auto" = everything plus
256
260
  * idle-boundary automatic folds (growth gate / pressure / emergency). */
257
- trimMode: z.union(["off", "advisory", "auto"]).default("auto").volatile(),
261
+ trimMode: z.union(["off", "advisory", "auto"]).default("advisory").volatile(),
258
262
  /** Growth gate (tier a): fold when the outbound-view estimate grew this
259
263
  * much since the last fold. */
260
264
  trimGrowthTokens: z.number().min(1000).default(22500).volatile(),
261
265
  /** Growth gate companion: the contiguous compressible increment must
262
266
  * also reach this many estimated tokens (chars/4 heuristic). */
263
- trimIncrementTokens: z.number().min(1000).default(25000).volatile(),
267
+ trimIncrementTokens: z.number().min(1000).default(45000).volatile(),
264
268
  /** Pressure tier (tier b): fold when view usage reaches this percent of
265
269
  * the context window (requires a resolvable window; otherwise skipped). */
266
- trimPressurePercent: z.number().min(1).max(100).default(65).volatile(),
270
+ trimPressurePercent: z.number().min(5).max(100).default(45).volatile(),
267
271
  /** Emergency tier (tier c): forced MECHANICAL fold (no side-model call)
268
272
  * at this percent of the window; cooldown-gated. */
269
- trimEmergencyPercent: z.number().min(1).max(100).default(95).volatile(),
273
+ trimEmergencyPercent: z.number().min(5).max(100).default(90).volatile(),
270
274
  /** Advisory mode speak line: the model is nudged to fold when pressure
271
275
  * reaches this percent of the window (default sits below the protocol's
272
276
  * own 80% fold line, nudging while folding headroom is still comfortable). */
273
- trimAdvisoryPercent: z.number().min(1).max(100).default(65).volatile(),
277
+ trimAdvisoryPercent: z.number().min(5).max(100).default(50).volatile(),
274
278
  /** Advisory mode escalation line: at this percent the nudge escalates to a
275
279
  * fold-down-this-turn order; must stay above trimAdvisoryPercent (an
276
- * inverted or out-of-range pair falls back to 65/95). */
277
- trimAdvisoryCriticalPercent: z.number().min(1).max(100).default(95).volatile(),
280
+ * inverted or out-of-range pair falls back to 50/80). */
281
+ trimAdvisoryCriticalPercent: z.number().min(5).max(100).default(80).volatile(),
282
+ /** [2026-11-15]-[advisory critical relief fold]-[at the critical advisory
283
+ * line the engine itself performs ONE mechanical (emergency-style) fold,
284
+ * 90 s cooldown (EMERGENCY_COOLDOWN_MS), instead of only nudging — the
285
+ * 2026-11-14 turn-25 incident (nudges ignored, 74%→99% in 28 minutes)
286
+ * burned the window down to host compaction. Off restores nudge-only
287
+ * advisory mode.] */
288
+ trimCriticalRelief: z.boolean().default(true).volatile(),
289
+ /** [2026-11-15]-[per-band nudge repeat]-[a spoken advisory nudge slides
290
+ * under the growing turn tail and becomes background noise; the repeat
291
+ * now re-pins the nudge at the new tail this many ms after the last
292
+ * speak (critical band halves it, floor 45 s). Old behavior: one
293
+ * repeat per 10 minutes. 5000..3600000 sane; out-of-range falls back
294
+ * to 120000.] */
295
+ trimAdvisoryRepeatMs: z.number().min(5000).max(3600000).default(120000).volatile(),
296
+ /** [2026-11-15]-[verbose debug log]-[the turn-25 + window-unknown
297
+ * incidents both hid inside silent gates that outcomes-only logging
298
+ * cannot see. On, every engine step, gate evaluation and decision path
299
+ * writes a debug row to decisions.log; off keeps the key decision rows
300
+ * only. Exceptions log full detail (message + stack frames) regardless
301
+ * of this switch.] */
302
+ trimVerboseLog: z.boolean().default(false).volatile(),
278
303
  /** [2026-11-07]-[growth/increment constants are absolute tokens
279
304
  * calibrated for the default 150k effective window]-[scaling
280
305
  * trimWindowTokens down without scaling trimGrowthTokens /
@@ -285,13 +310,16 @@ export const Config = z.object({
285
310
  * 2026-11-09 steady-growth recalibration — one fold per ~22.5k of new
286
311
  * work instead of one every ~2 minutes; pressure pins the 50-100k band
287
312
  * ceiling).]
313
+ * [2026-11-14]-[shipped defaults recalibrated to the 200k force
314
+ * window]-[increment 45000 ≈ window/4.4, growth 22500 ≈ window × 0.11;
315
+ * pressure/emergency 45%/90%, advisory 50%/90%, hard watermark 100k.]
288
316
  * Effective-window cap for the tier math: tier points are computed
289
317
  * against min(model-resolved window, cap). 0 = auto (cap follows
290
318
  * wmForceTokens, so folds always fire ahead of the handover tier). */
291
319
  trimWindowTokens: z.number().min(0).default(0).volatile(),
292
320
  /** Last N messages of a history are never folded (the live tail the
293
321
  * next model call reasons over). */
294
- trimProtectedTail: z.number().min(0).max(100).default(10).volatile(),
322
+ trimProtectedTail: z.number().min(0).max(100).default(6).volatile(),
295
323
  /** Side-model fold cadence cap per rolling hour (emergency mechanical
296
324
  * folds are exempt; they have their own cooldown). 30 sits just above
297
325
  * the pure T1 demand of continuous full-rate generation (~27 folds/hour
@@ -333,8 +361,11 @@ export const Config = z.object({
333
361
  /** Ladder T3 companion floor: a T3 condensation merges at least this
334
362
  * many active T2 blocks. */
335
363
  trimLadderT3MinBlocks: z.number().min(2).max(200).default(2).volatile(),
336
- /** Explicit ledger state directory. Empty = <dshHome>/.dsh-switchman/
337
- * state/trim/. */
364
+ /** Explicit ledger state directory (absolute, or relative inside the
365
+ * plugin root). Must stay under <dshHome>/.dsh-switchman/state/trim/
366
+ * (or the OS temp root, for throwaway test state); anything else is
367
+ * refused and the default root is used. Empty =
368
+ * <dshHome>/.dsh-switchman/state/trim/. */
338
369
  trimStateDir: z.string().default("").volatile(),
339
370
  /** Ship committed folds onto the session surface: append the host-style
340
371
  * shadow-price + surfaceOp replace event pair so folds reach the wire