dsh-context-compression-improved 0.5.0 → 0.5.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.
Files changed (50) hide show
  1. package/CHANGELOG.ja.md +51 -0
  2. package/CHANGELOG.ko.md +51 -0
  3. package/CHANGELOG.md +55 -0
  4. package/CHANGELOG.zh.md +45 -0
  5. package/package.json +1 -1
  6. package/packages/selector/lib/advisor-state.js +4 -231
  7. package/packages/selector/lib/client.d.ts +0 -24
  8. package/packages/selector/lib/client.js +6 -501
  9. package/packages/selector/lib/index.d.ts +4 -10
  10. package/packages/selector/lib/index.js +65 -235
  11. package/packages/selector/lib/pruner.d.ts +13 -248
  12. package/packages/selector/lib/pruner.js +148 -552
  13. package/packages/selector/src/client/EstimatorControls.tsx +277 -378
  14. package/packages/selector/src/client/index.ts +0 -17
  15. package/packages/selector/src/client/locales.ts +196 -234
  16. package/packages/selector/src/client/preset-options.ts +3 -2
  17. package/packages/selector/src/client/settings-section.tsx +8 -17
  18. package/packages/selector/src/index.ts +463 -710
  19. package/packages/selector/src/preset-overlay.ts +60 -1
  20. package/packages/selector/src/profiles.ts +4 -27
  21. package/packages/selector/src/pruner/state.ts +50 -73
  22. package/packages/selector/src/pruner.ts +2402 -2730
  23. package/packages/selector/src/runtime/audit.ts +27 -21
  24. package/packages/selector/src/runtime/config.ts +6 -32
  25. package/packages/selector/src/runtime/tokenpilot/advisor-state.ts +16 -0
  26. package/packages/selector/src/runtime/tokenpilot/benefit.ts +200 -0
  27. package/packages/selector/src/runtime/types.ts +0 -17
  28. package/packages/selector/tests/built/client-artifact.spec.ts +9 -5
  29. package/packages/selector/tests/preset-options-write.client.spec.ts +7 -23
  30. package/packages/selector/tests/runtime/advice-never-withholds.host.spec.ts +232 -0
  31. package/packages/selector/tests/runtime/audit.spec.ts +35 -21
  32. package/packages/selector/tests/runtime/deprecated-preset-options.spec.ts +96 -0
  33. package/packages/selector/tests/runtime/tokenpilot/benefit.spec.ts +217 -0
  34. package/packages/selector/tests/runtime/tokenpilot/profile-baseline.spec.ts +4 -5
  35. package/packages/selector/tests/settings-seat.client.spec.ts +16 -10
  36. package/packages/selector/tests/standing-generation.host.spec.ts +54 -5
  37. package/scripts/packed-components-smoke.mjs +30 -8
  38. package/scripts/packed-install-e2e.mjs +69 -15
  39. package/packages/selector/src/client/ReviewOverlay.tsx +0 -320
  40. package/packages/selector/src/client/review-scope.ts +0 -16
  41. package/packages/selector/src/runtime/tokenpilot/proposal.ts +0 -267
  42. package/packages/selector/src/runtime/tokenpilot/review-queue.ts +0 -231
  43. package/packages/selector/src/runtime/tokenpilot/review-registry.ts +0 -117
  44. package/packages/selector/src/runtime/tokenpilot/review-storage.ts +0 -122
  45. package/packages/selector/tests/review-overlay.client.spec.tsx +0 -118
  46. package/packages/selector/tests/review-routes-registry.host.spec.ts +0 -142
  47. package/packages/selector/tests/review-routes.host.spec.ts +0 -290
  48. package/packages/selector/tests/runtime/tokenpilot/proposal.spec.ts +0 -393
  49. package/packages/selector/tests/runtime/tokenpilot/pruner-review.spec.ts +0 -382
  50. package/packages/selector/tests/runtime/tokenpilot/review-queue.spec.ts +0 -168
package/CHANGELOG.ja.md CHANGED
@@ -2,6 +2,57 @@
2
2
 
3
3
  > 完全な履歴(アップストリーム 0.1.0 以前を含む)は [CHANGELOG.md](CHANGELOG.md) を参照。このファイルはフォークの追加エントリーのみを翻訳したものです。 · [English](CHANGELOG.md) · [中文](CHANGELOG.zh.md) · [한국어](CHANGELOG.ko.md)
4
4
 
5
+ ## 0.5.2 - 2026-09-20
6
+
7
+ ### Changed(変更)
8
+
9
+ - 人手ゲート付きレビューパイプライン(review gate、beta)を**廃止**しました。その意味論は
10
+ 「助言」に置き換わります。便益モデルは従来どおり 1 パスを 1 回の統合 mutation として
11
+ 価格付けしますが、算出したバンド(`profitable` / `high-impact` / `slow-payback` /
12
+ `unpriceable` / `not-worth-it`)は `reduction-advice` 監査レコードとして公開され、
13
+ advisor レポートルートにスナップショットされるだけになりました——reduction を保留・遅延・
14
+ 書き換えることはありません。この gate は機能自身の要件(削減は自動処理を妨げない)と矛盾し、
15
+ 出荷既定(`reviewMode` 有効 + 4,000 トークンの高影響しきい値に対し 8,192 トークンの
16
+ fresh トリガー)では fresh バッチを 100% 人手レビューへ迂回させ、有効化した利用者から
17
+ 自動経路を事実上奪っていました。助言のしきい値はモジュール定数(α `0.1`、高影響
18
+ `4,000` トークン)になりました。何もこれに従って動作しないため、設定項目ではなくなります。
19
+ - gate とともに削除:レビューキューとその `storageDomain` アダプタ、プロセス全体の
20
+ レジストリ、`review-queue` / `review-decide` の HTTP ルートと `reviewQueueRoute` 配置
21
+ フラグ、`shell.overlay` クライアントパネル、`reviewMode` / `reviewTimeoutTurns` /
22
+ `cacheHitDiscountAlpha` / `reviewHighImpactTokens` の設定キー、`review-outcome` 監査種別。
23
+ 4 つの設定キーは**両方のデコーダで引き続き受理され無視されます**——既存の文書(稼働中は
24
+ `reviewMode: false` を含む)はそのまま読み込まれ、設定カードも表示されます——そして解決済み
25
+ policy には決して到達しません。読み取り専用の `GET .../advisor-report` は `lastAdvice` も
26
+ 返します。
27
+
28
+ ### Added(追加)
29
+
30
+ - 廃止に対する回帰ピン:かつて全量を迂回させていた設定(`reviewMode: true`、
31
+ `reviewHighImpactTokens: 1`)で fresh バッチが**そのまま着地**し、`high-impact` の助言
32
+ レコードがそれを記述することをホスト統合テストで固定。ランタイムパーサとブラウザデコーダの
33
+ 両側で「受理して無視」を固定する非推奨契約テストも追加。
34
+
35
+ ### Rollback(ロールバック)
36
+
37
+ - gate を含む最後のリリースへ戻す:`npm dist-tag add
38
+ dsh-context-compression-improved@0.5.1 dsh-0.1.5 --registry https://registry.npmjs.org/`
39
+ の後、`dsh plugin --profile web add dsh-context-compression-improved@0.5.1`。
40
+
41
+ ## 0.5.1 - 2026-09-20
42
+
43
+ ### Fixed(修正)
44
+
45
+ - 同一 identity を並行して compose する preset-overlay が Windows で失敗しなくなりました。
46
+ 公開は宛先パスごとに直列化し、それでも原子的 rename が競合に敗れた場合は、宛先が
47
+ このステージングファイルと同じ `{mtimeMs, size}` standing key を既に持っていることを
48
+ 確認してから成功と見なします。Windows の `MoveFileEx` はこの競合を `EPERM`/`EBUSY` と
49
+ して報告しますが、POSIX の `rename` は単に置き換えます——これが並行セッション開始時に
50
+ `standingKeyFor()` を投げさせていました。一致しない宛先はこれまで通り明確に失敗し、
51
+ 静かな世代の再利用は禁止されたままです。
52
+ - この問題と他の既存レッドゲートを覆い隠していたリリースゲート/テストの修正
53
+ (packed smoke の陳旧な識別子と廃止済み audit reason、古い client inject 期待値、
54
+ Windows 限定の spawn トラップ)。
55
+
5
56
  ## 0.5.0 - 2026-09-20
6
57
 
7
58
  ### Added(追加)
package/CHANGELOG.ko.md CHANGED
@@ -2,6 +2,57 @@
2
2
 
3
3
  > 전체 히스토리(업스트림 0.1.0 이전 포함)는 [CHANGELOG.md](CHANGELOG.md)를 참고하세요. 이 파일은 포크의 추가 항목만 번역한 것입니다. · [English](CHANGELOG.md) · [中文](CHANGELOG.zh.md) · [日本語](CHANGELOG.ja.md)
4
4
 
5
+ ## 0.5.2 - 2026-09-20
6
+
7
+ ### Changed(변경)
8
+
9
+ - 사람이 승인하는 리뷰 파이프라인(review gate, beta)을 **폐기**했습니다. 그 의미론은
10
+ "조언"으로 대체됩니다. 이익 모델은 여전히 한 패스를 하나의 병합 mutation으로 가격
11
+ 책정하지만, 계산한 밴드(`profitable` / `high-impact` / `slow-payback` /
12
+ `unpriceable` / `not-worth-it`)는 이제 `reduction-advice` 감사 레코드로 게시되고 advisor
13
+ 리포트 라우트에 스냅샷될 뿐입니다——reduction을 보류·지연·재작성하지 않습니다. 이 gate는
14
+ 기능 자체의 요구(축소는 자동 처리를 막지 않는다)와 모순되었고, 출하 기본값(`reviewMode`
15
+ 켬 + 4,000 토큰 고영향 임계값 대 8,192 토큰 fresh 트리거)에서는 fresh 배치를 100% 사람
16
+ 리뷰로 우회시켜, 이를 켠 사용자에게서 자동 경로를 사실상 빼앗았습니다. 조언 임계값은 이제
17
+ 모듈 상수(α `0.1`, 고영향 `4,000` 토큰)입니다. 아무 경로도 이에 따라 동작하지 않으므로
18
+ 더 이상 설정 항목이 아닙니다.
19
+ - gate와 함께 제거: 리뷰 큐와 그 `storageDomain` 어댑터, 프로세스 전역 레지스트리,
20
+ `review-queue` / `review-decide` HTTP 라우트와 `reviewQueueRoute` 배포 플래그,
21
+ `shell.overlay` 클라이언트 패널, `reviewMode` / `reviewTimeoutTurns` /
22
+ `cacheHitDiscountAlpha` / `reviewHighImpactTokens` 설정 키, `review-outcome` 감사 종류.
23
+ 네 개의 설정 키는 **두 디코더 모두에서 계속 허용되고 무시됩니다**——기존 문서(운영 중인
24
+ 문서에는 `reviewMode: false`가 있음)는 그대로 로드되고 설정 카드도 렌더링됩니다——그리고
25
+ 해석된 policy에는 결코 도달하지 않습니다. 읽기 전용 `GET .../advisor-report`는
26
+ `lastAdvice`도 함께 제공합니다.
27
+
28
+ ### Added(추가)
29
+
30
+ - 폐기에 대한 회귀 고정: 예전에 전량을 우회시키던 설정(`reviewMode: true`,
31
+ `reviewHighImpactTokens: 1`)으로 fresh 배치가 **그대로 착지**하고 `high-impact` 조언
32
+ 레코드가 이를 설명함을 호스트 통합 테스트로 고정했습니다. 런타임 파서와 브라우저 디코더
33
+ 양쪽에서 "허용 후 무시"를 고정하는 폐기 계약 테스트도 추가했습니다.
34
+
35
+ ### Rollback(롤백)
36
+
37
+ - gate를 포함한 마지막 릴리스로 되돌리기: `npm dist-tag add
38
+ dsh-context-compression-improved@0.5.1 dsh-0.1.5 --registry https://registry.npmjs.org/`
39
+ 후 `dsh plugin --profile web add dsh-context-compression-improved@0.5.1`.
40
+
41
+ ## 0.5.1 - 2026-09-20
42
+
43
+ ### Fixed(수정)
44
+
45
+ - 동일 identity를 동시에 compose하는 preset-overlay가 Windows에서 더 이상 실패하지
46
+ 않습니다. 게시는 대상 경로별로 직렬화되며, 그래도 원자적 rename이 경쟁에서 지면 대상이
47
+ 이미 이 스테이징 파일과 같은 `{mtimeMs, size}` standing key를 가지고 있는지 확인한 뒤에만
48
+ 성공으로 간주합니다. Windows의 `MoveFileEx`는 이 경쟁을 `EPERM`/`EBUSY`로 보고하지만
49
+ POSIX `rename`은 대상을 그대로 교체합니다——이 때문에 동시 세션 시작 시
50
+ `standingKeyFor()`가 예외를 던졌습니다. 일치하지 않는 대상은 여전히 명확히 실패하며,
51
+ 조용한 세대 재사용은 계속 금지됩니다.
52
+ - 이 문제와 다른 기존 레드 게이트를 가리던 릴리스 게이트/테스트 수정
53
+ (packed smoke의 오래된 식별자와 폐기된 audit reason, 낡은 client inject 기대값,
54
+ Windows 전용 spawn 함정).
55
+
5
56
  ## 0.5.0 - 2026-09-20
6
57
 
7
58
  ### Added(추가)
package/CHANGELOG.md CHANGED
@@ -2,6 +2,61 @@
2
2
 
3
3
  All notable changes use this file. The project follows semantic versioning after `0.1.0`.
4
4
 
5
+ ## 0.5.2 - 2026-09-20
6
+
7
+ ### Changed
8
+
9
+ - The human-gated review pipeline (beta) is **retired**. Its semantics are replaced by
10
+ advice: the benefit model still prices every pass as ONE merged mutation, but the band it
11
+ computes (`profitable` / `high-impact` / `slow-payback` / `unpriceable` / `not-worth-it`)
12
+ is now published as a `reduction-advice` audit record and snapshotted onto the advisor
13
+ report route — it never withholds, delays, or rewrites a reduction. The gate contradicted
14
+ the feature's own requirement (a reduction must never block automatic processing) and, with
15
+ the shipped defaults (`reviewMode` on plus a 4,000-token high-impact threshold against an
16
+ 8,192-token fresh trigger), diverted 100% of a fresh batch into human review, leaving the
17
+ automatic path effectively off for anyone who opted in. The advice thresholds are now
18
+ module constants (α `0.1`, high-impact `4,000` tokens): nothing acts on them, so they are
19
+ no longer settings.
20
+ - Removed with the gate: the review queue and its `storageDomain` adapter, the process-wide
21
+ registry, the `review-queue` / `review-decide` HTTP routes and the `reviewQueueRoute`
22
+ deployment flag, the `shell.overlay` client panel, the `reviewMode` /
23
+ `reviewTimeoutTurns` / `cacheHitDiscountAlpha` / `reviewHighImpactTokens` settings keys,
24
+ and the `review-outcome` audit kind. The four settings keys stay ACCEPTED and IGNORED by
25
+ both decoders — an existing document (the live one carries `reviewMode: false`) still loads
26
+ and still renders its settings card — and never reach the resolved policy. The read-only
27
+ `GET .../advisor-report` route additionally serves `lastAdvice`.
28
+
29
+ ### Added
30
+
31
+ - Regression pins for the retirement: a host-integration spec drives the exact settings that
32
+ used to divert everything (`reviewMode: true`, `reviewHighImpactTokens: 1`) and asserts the
33
+ fresh batch LANDS, described by a `high-impact` advice record; a deprecation-contract spec
34
+ pins accept-and-ignore for the retired keys on both the runtime parser and the browser
35
+ decoder.
36
+
37
+ ### Rollback
38
+
39
+ - Reinstall the last release that still ships the gate: `npm dist-tag add
40
+ dsh-context-compression-improved@0.5.1 dsh-0.1.5 --registry https://registry.npmjs.org/`
41
+ then `dsh plugin --profile web add dsh-context-compression-improved@0.5.1`.
42
+
43
+ ## 0.5.1 - 2026-09-20
44
+
45
+ ### Fixed
46
+
47
+ - Concurrent preset-overlay composition of one identity no longer fails on Windows.
48
+ Publication is now serialized per destination path, and when the atomic rename still
49
+ loses the race the destination is confirmed to already carry this staging file's
50
+ `{mtimeMs, size}` standing key before the publish reports success. Windows `MoveFileEx`
51
+ reports that lost race as `EPERM`/`EBUSY` where POSIX `rename` simply replaces the
52
+ destination, which made `standingKeyFor()` throw during concurrent session start. A
53
+ destination that does not match still fails loudly, so a silently reused generation
54
+ stays forbidden.
55
+ - Release-gate and test repairs that had been hiding this and other pre-existing red
56
+ gates: stale identifiers and a retired audit reason in the packed smokes, a stale
57
+ client-inject expectation, and Windows-only spawn traps (`git` and multi-line
58
+ `node -e` scripts were routed through `cmd.exe`, which rewrote their arguments).
59
+
5
60
  ## 0.5.0 - 2026-09-20
6
61
 
7
62
  ### Added
package/CHANGELOG.zh.md CHANGED
@@ -2,6 +2,51 @@
2
2
 
3
3
  > 完整历史(含上游 0.1.0 及更早版本)见 [CHANGELOG.md](CHANGELOG.md)。本文件只翻译本 fork 的新增条目。 · [English](CHANGELOG.md) · [日本語](CHANGELOG.ja.md) · [한국어](CHANGELOG.ko.md)
4
4
 
5
+ ## 0.5.2 - 2026-09-20
6
+
7
+ ### Changed
8
+
9
+ - **退役**人工审查管线(review gate,beta)。其语义由"建议"取代:收益模型仍按"整批一次
10
+ mutation"定价,但它算出的分带(`profitable` / `high-impact` / `slow-payback` /
11
+ `unpriceable` / `not-worth-it`)现在只作为 `reduction-advice` 审计记录发布,并在 advisor
12
+ 报告路由上留一份快照——绝不扣留、延迟或改写任何 reduction。该 gate 与本功能自身的要求
13
+ (缩减不阻断自动处理)相矛盾,且在出厂默认下(`reviewMode` 开 + 4000 token 高影响阈值
14
+ 对 8192 token 的 fresh 门槛)会把整批 fresh 100% 改道进人审,等于让选择开启它的用户失去
15
+ 自动路径。建议阈值改为模块常量(α `0.1`、高影响 `4000` token):没有任何路径依据它们
16
+ 行动,因此不再作为配置项。
17
+ - 随 gate 一并移除:审查队列及其 `storageDomain` 适配器、进程级注册表、
18
+ `review-queue` / `review-decide` 两条 HTTP 路由与 `reviewQueueRoute` 部署开关、
19
+ `shell.overlay` 客户端浮窗、`reviewMode` / `reviewTimeoutTurns` /
20
+ `cacheHitDiscountAlpha` / `reviewHighImpactTokens` 四个 settings 键,以及
21
+ `review-outcome` 审计类型。这四个键在**两个解码器**中仍被接受但被忽略——既有配置文档
22
+ (线上即带 `reviewMode: false`)照常加载、设置卡照常渲染——且永不进入已解析的 policy。
23
+ 只读路由 `GET .../advisor-report` 额外提供 `lastAdvice`。
24
+
25
+ ### Added
26
+
27
+ - 退役的回归钉桩:一条宿主集成测试用**当年会全量改道的那套配置**(`reviewMode: true`、
28
+ `reviewHighImpactTokens: 1`)断言 fresh 批次**照常落地**并附带 `high-impact` 建议记录;
29
+ 另一条弃用契约测试在运行时解析器与浏览器解码器两侧钉死"接受但忽略"。
30
+
31
+ ### Rollback
32
+
33
+ - 回退到仍带 gate 的最后一个版本:`npm dist-tag add
34
+ dsh-context-compression-improved@0.5.1 dsh-0.1.5 --registry https://registry.npmjs.org/`,
35
+ 然后 `dsh plugin --profile web add dsh-context-compression-improved@0.5.1`。
36
+
37
+ ## 0.5.1 - 2026-09-20
38
+
39
+ ### Fixed
40
+
41
+ - 同一 identity 的并发 preset-overlay 组装在 Windows 上不再失败:发布改为按目标路径串行,
42
+ 且当原子 rename 仍然竞争失败时,会先确认目标文件已带有本 staging 文件的
43
+ `{mtimeMs, size}` standing key 才判定发布成功。Windows 的 `MoveFileEx` 会把这种竞争
44
+ 失败报成 `EPERM`/`EBUSY`,而 POSIX `rename` 只是覆盖目标——这曾导致并发启动会话时
45
+ `standingKeyFor()` 抛错。目标不匹配时仍会明确失败,静默复用世代依旧被禁止。
46
+ - 一并修复了长期掩盖该问题及其它预存红灯的发布门禁与测试:packed smoke 中陈旧的标识符与
47
+ 已退役的审计 reason、过期的客户端 inject 断言,以及仅 Windows 触发的 spawn 陷阱
48
+ (`git` 与多行 `node -e` 脚本经 `cmd.exe` 转发会被改写参数)。
49
+
5
50
  ## 0.5.0 - 2026-09-20
6
51
 
7
52
  ### Added
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "dsh-context-compression-improved",
3
- "version": "0.5.0",
3
+ "version": "0.5.2",
4
4
  "publishConfig": {
5
5
  "registry": "https://registry.npmjs.org",
6
6
  "access": "public",
@@ -408,8 +408,7 @@ function parsePresetOptionsSettings(value) {
408
408
  "dedupeToolResults",
409
409
  "summaryLocator",
410
410
  "prefixStabilizer",
411
- "readState",
412
- "reviewMode"
411
+ "readState"
413
412
  ]) {
414
413
  const entry = value[key];
415
414
  if (entry !== void 0 && typeof entry !== "boolean") throw new TypeError(`Context-compression presetOptions.${key} must be a boolean`);
@@ -430,12 +429,6 @@ function parsePresetOptionsSettings(value) {
430
429
  if (advisorMinTokens !== void 0 && (typeof advisorMinTokens !== "number" || !Number.isSafeInteger(advisorMinTokens) || advisorMinTokens < 1)) throw new TypeError("Context-compression presetOptions.advisorMinTokens must be a positive integer");
431
430
  const estimatorTimeoutMs = value.estimatorTimeoutMs;
432
431
  if (estimatorTimeoutMs !== void 0 && (typeof estimatorTimeoutMs !== "number" || !Number.isSafeInteger(estimatorTimeoutMs) || estimatorTimeoutMs < 100 || estimatorTimeoutMs > 6e4)) throw new TypeError("Context-compression presetOptions.estimatorTimeoutMs must be an integer between 100 and 60000");
433
- const reviewTimeoutTurns = value.reviewTimeoutTurns;
434
- if (reviewTimeoutTurns !== void 0 && (typeof reviewTimeoutTurns !== "number" || !Number.isSafeInteger(reviewTimeoutTurns) || reviewTimeoutTurns < 1)) throw new TypeError("Context-compression presetOptions.reviewTimeoutTurns must be an integer of at least 1");
435
- const cacheHitDiscountAlpha = value.cacheHitDiscountAlpha;
436
- if (cacheHitDiscountAlpha !== void 0 && (typeof cacheHitDiscountAlpha !== "number" || !Number.isFinite(cacheHitDiscountAlpha) || cacheHitDiscountAlpha <= 0 || cacheHitDiscountAlpha >= 1)) throw new TypeError("Context-compression presetOptions.cacheHitDiscountAlpha must be a number strictly between 0 and 1");
437
- const reviewHighImpactTokens = value.reviewHighImpactTokens;
438
- if (reviewHighImpactTokens !== void 0 && (typeof reviewHighImpactTokens !== "number" || !Number.isSafeInteger(reviewHighImpactTokens) || reviewHighImpactTokens < 0)) throw new TypeError("Context-compression presetOptions.reviewHighImpactTokens must be a non-negative integer");
439
432
  for (const key of [
440
433
  "estimatorProvider",
441
434
  "estimatorModel",
@@ -456,10 +449,6 @@ function parsePresetOptionsSettings(value) {
456
449
  if (value.estimatorBaseUrl !== void 0) result.estimatorBaseUrl = value.estimatorBaseUrl;
457
450
  if (value.estimatorApiKey !== void 0) result.estimatorApiKey = value.estimatorApiKey;
458
451
  if (estimatorTimeoutMs !== void 0) result.estimatorTimeoutMs = estimatorTimeoutMs;
459
- if (value.reviewMode !== void 0) result.reviewMode = value.reviewMode;
460
- if (reviewTimeoutTurns !== void 0) result.reviewTimeoutTurns = reviewTimeoutTurns;
461
- if (cacheHitDiscountAlpha !== void 0) result.cacheHitDiscountAlpha = cacheHitDiscountAlpha;
462
- if (reviewHighImpactTokens !== void 0) result.reviewHighImpactTokens = reviewHighImpactTokens;
463
452
  if (advisorMode !== void 0) result.advisorMode = advisorMode;
464
453
  if (advisorTimeoutMs !== void 0) result.advisorTimeoutMs = advisorTimeoutMs;
465
454
  if (advisorRefreshTurns !== void 0) result.advisorRefreshTurns = advisorRefreshTurns;
@@ -681,10 +670,6 @@ const PRESET_OPTION_DEFAULTS = deepFreeze({
681
670
  prefixStabilizer: true,
682
671
  readState: true,
683
672
  estimator: { mode: "" },
684
- reviewMode: false,
685
- reviewTimeoutTurns: 6,
686
- cacheHitDiscountAlpha: .1,
687
- reviewHighImpactTokens: 4e3,
688
673
  advisor: {
689
674
  mode: "",
690
675
  timeoutMs: 8e3,
@@ -709,10 +694,6 @@ function mergePresetOptions(overrides) {
709
694
  prefixStabilizer: overrides.prefixStabilizer ?? PRESET_OPTION_DEFAULTS.prefixStabilizer,
710
695
  readState: overrides.readState ?? PRESET_OPTION_DEFAULTS.readState,
711
696
  estimator: { mode: overrides.estimatorMode ?? PRESET_OPTION_DEFAULTS.estimator.mode },
712
- reviewMode: overrides.reviewMode ?? PRESET_OPTION_DEFAULTS.reviewMode,
713
- reviewTimeoutTurns: overrides.reviewTimeoutTurns ?? PRESET_OPTION_DEFAULTS.reviewTimeoutTurns,
714
- cacheHitDiscountAlpha: overrides.cacheHitDiscountAlpha ?? PRESET_OPTION_DEFAULTS.cacheHitDiscountAlpha,
715
- reviewHighImpactTokens: overrides.reviewHighImpactTokens ?? PRESET_OPTION_DEFAULTS.reviewHighImpactTokens,
716
697
  advisor: {
717
698
  mode: overrides.advisorMode ?? PRESET_OPTION_DEFAULTS.advisor.mode,
718
699
  timeoutMs: overrides.advisorTimeoutMs ?? PRESET_OPTION_DEFAULTS.advisor.timeoutMs,
@@ -915,215 +896,6 @@ function assertPositiveInteger(name, value) {
915
896
  function assertNonNegativeInteger(name, value) {
916
897
  if (!Number.isSafeInteger(value) || value < 0) throw new Error(`ToolResultPruneConfig: ${name} (${String(value)}) must be a non-negative safe integer`);
917
898
  }
918
- //#endregion
919
- //#region src/runtime/tokenpilot/review-queue.ts
920
- /** In-memory store: the fail-open fallback when no durable seam is available. */
921
- var MemoryReviewStore = class {
922
- sessions = /* @__PURE__ */ new Map();
923
- load(sessionId) {
924
- return this.sessions.get(sessionId);
925
- }
926
- save(sessionId, record) {
927
- this.sessions.set(sessionId, record);
928
- }
929
- ids() {
930
- return [...this.sessions.keys()];
931
- }
932
- };
933
- var ReviewQueue = class {
934
- store;
935
- options;
936
- constructor(store, options) {
937
- this.store = store;
938
- this.options = options;
939
- }
940
- /**
941
- * Fail-open store access: a throwing seam must never break the compression
942
- * pipeline. Reads degrade to "no stored record"; writes degrade to losing
943
- * durability for that call (the store itself is expected to warn).
944
- */
945
- safeLoad(sessionId) {
946
- try {
947
- return this.store.load(sessionId);
948
- } catch {
949
- return;
950
- }
951
- }
952
- safeSave(sessionId, record) {
953
- try {
954
- this.store.save(sessionId, record);
955
- } catch {}
956
- }
957
- sessionRecord(sessionId) {
958
- return this.safeLoad(sessionId) ?? {
959
- version: 1,
960
- proposals: []
961
- };
962
- }
963
- /**
964
- * Queue one classified proposal. A repeated classification of the same
965
- * content re-does nothing but refresh the patience clock, so re-enqueue
966
- * cannot duplicate a live proposal.
967
- * @returns `false` when an identical live proposal already exists.
968
- */
969
- enqueue(sessionId, skeleton, turnIndex) {
970
- const record = this.sessionRecord(sessionId);
971
- const existing = record.proposals.find((entry) => entry.id === skeleton.id);
972
- if (existing !== void 0 && existing.status !== "expired") {
973
- existing.lastTurnIndex = turnIndex;
974
- this.safeSave(sessionId, record);
975
- return false;
976
- }
977
- const proposal = {
978
- id: skeleton.id,
979
- sessionId,
980
- kind: skeleton.kind,
981
- items: skeleton.items.map((item) => ({ ...item })),
982
- benefit: { ...skeleton.benefit },
983
- status: "pending",
984
- enqueuedTurn: turnIndex,
985
- lastTurnIndex: turnIndex
986
- };
987
- this.safeSave(sessionId, {
988
- version: 1,
989
- proposals: [...record.proposals.filter((entry) => entry.id !== skeleton.id), proposal]
990
- });
991
- return true;
992
- }
993
- /** Live pending proposals of one session, oldest enqueue first. */
994
- listPending(sessionId) {
995
- return this.sessionRecord(sessionId).proposals.filter((entry) => entry.status === "pending").sort((left, right) => left.enqueuedTurn - right.enqueuedTurn);
996
- }
997
- /** Approved proposals waiting for the next turn-boundary batch. */
998
- listApproved(sessionId) {
999
- return this.sessionRecord(sessionId).proposals.filter((entry) => entry.status === "approved").sort((left, right) => left.enqueuedTurn - right.enqueuedTurn);
1000
- }
1001
- /**
1002
- * Transition one pending proposal. Idempotent: deciding an unknown id or a
1003
- * non-pending proposal changes nothing and reports the miss.
1004
- */
1005
- decide(sessionId, id, decision) {
1006
- const record = this.sessionRecord(sessionId);
1007
- const proposal = record.proposals.find((entry) => entry.id === id);
1008
- if (proposal === void 0) return {
1009
- ok: false,
1010
- reason: "unknown-proposal"
1011
- };
1012
- if (proposal.status !== "pending") return {
1013
- ok: false,
1014
- reason: "not-pending"
1015
- };
1016
- proposal.status = decision;
1017
- this.safeSave(sessionId, record);
1018
- return { ok: true };
1019
- }
1020
- /**
1021
- * Expire every pending proposal whose patience has run out at this turn
1022
- * boundary. Expired proposals are removed from the store (the summary view
1023
- * aggregates them from the audit log instead).
1024
- * @returns the expired proposals, for the caller's audit emission.
1025
- */
1026
- expireTurn(sessionId, turnIndex) {
1027
- const record = this.sessionRecord(sessionId);
1028
- const keep = [];
1029
- const expired = [];
1030
- for (const proposal of record.proposals) {
1031
- if (proposal.status === "pending" && turnIndex - proposal.lastTurnIndex > this.options.timeoutTurns) {
1032
- expired.push({
1033
- ...proposal,
1034
- status: "expired"
1035
- });
1036
- continue;
1037
- }
1038
- keep.push(proposal);
1039
- }
1040
- if (expired.length > 0) this.safeSave(sessionId, {
1041
- version: 1,
1042
- proposals: keep
1043
- });
1044
- return expired;
1045
- }
1046
- /**
1047
- * Settle an approved proposal with its execution receipt and retire it from
1048
- * the live store. The caller is responsible for auditing the receipt; the
1049
- * queue only records which proposal left and why.
1050
- */
1051
- recordReceipt(sessionId, id, receipt) {
1052
- const record = this.sessionRecord(sessionId);
1053
- const proposal = record.proposals.find((entry) => entry.id === id);
1054
- if (proposal === void 0 || proposal.status !== "approved") return void 0;
1055
- this.safeSave(sessionId, {
1056
- version: 1,
1057
- proposals: record.proposals.filter((entry) => entry.id !== id)
1058
- });
1059
- return {
1060
- ...proposal,
1061
- receipt
1062
- };
1063
- }
1064
- };
1065
- //#endregion
1066
- //#region src/runtime/tokenpilot/review-registry.ts
1067
- /**
1068
- * Scope-independent handle on the live review pipeline.
1069
- *
1070
- * The R4 HTTP routes are registered on the plugin's TOP-LEVEL fiber
1071
- * (`cordis.patch.yml` → `context-compression-improved-estimator-catalog`),
1072
- * but every `ToolResultPruner` is mounted inside an agent preset's isolated
1073
- * group — `canonicalCompressionRows()` declares
1074
- * `isolate: { compaction: true, toolResultPruner: true }` — so
1075
- * `ctx.get('toolResultPruner')` at the top level is always `undefined` and the
1076
- * queue route could only ever answer 503 "review pipeline unavailable".
1077
- *
1078
- * Ownership, not transport, was in the wrong place: the queue records are
1079
- * already keyed by session id, so the store belongs to the plugin rather than
1080
- * to one pruner instance. Every instance shares one store and publishes itself
1081
- * here, which lets a top-level reader reach whichever instance currently holds
1082
- * a session's proposals.
1083
- *
1084
- * The durable seam already behaves this way — `REVIEW_STORAGE_DOMAIN` /
1085
- * `REVIEW_STORAGE_TABLE` are constants, so every instance opens the same table.
1086
- * Only the in-memory fallback was per-instance, and that is what this module
1087
- * makes shared.
1088
- *
1089
- * @module dsh-context-compression-improved/review-registry
1090
- */
1091
- /**
1092
- * The one in-memory fallback every pruner instance starts from. Session ids are
1093
- * globally unique and `ReviewSessionRecord` is keyed by them, so a single store
1094
- * is semantically identical to one store per instance — except that a reader
1095
- * reaching any instance now observes every session.
1096
- */
1097
- const sharedStore = new MemoryReviewStore();
1098
- const live = /* @__PURE__ */ new Set();
1099
- /** The process-wide review queue store shared by every pruner instance. */
1100
- function sharedReviewStore() {
1101
- return sharedStore;
1102
- }
1103
- /**
1104
- * Publish one pruner instance for scope-independent readers.
1105
- * @param pruner - the instance to publish.
1106
- * @returns the disposer removing it, for `ctx.effect`.
1107
- */
1108
- function registerReviewPruner(pruner) {
1109
- live.add(pruner);
1110
- return () => {
1111
- live.delete(pruner);
1112
- };
1113
- }
1114
- /**
1115
- * Resolve a live pruner instance for the top-level routes.
1116
- *
1117
- * Any instance can serve an aggregate read because the store is shared, and a
1118
- * session-scoped read is answered from that same store. Instances that have
1119
- * upgraded to the durable seam read the same table, so the answer does not
1120
- * depend on which instance this happens to return.
1121
- *
1122
- * @returns a live instance, or `undefined` when no preset has been composed yet.
1123
- */
1124
- function resolveReviewPruner() {
1125
- return live.values().next().value;
1126
- }
1127
899
  const advisorStates = /* @__PURE__ */ new WeakMap();
1128
900
  /**
1129
901
  * The per-session advisor state, created on first touch.
@@ -1141,7 +913,8 @@ function getAdvisorState(session) {
1141
913
  recertified: /* @__PURE__ */ new Map(),
1142
914
  failures: void 0,
1143
915
  inFlight: false,
1144
- lastDecay: void 0
916
+ lastDecay: void 0,
917
+ lastAdvice: void 0
1145
918
  };
1146
919
  advisorStates.set(session, state);
1147
920
  }
@@ -1186,4 +959,4 @@ function invalidateOnTaskChange(state, todoVersion) {
1186
959
  return true;
1187
960
  }
1188
961
  //#endregion
1189
- export { DEFAULT_CUSTOM_COMPRESSION_POLICY as C, COMPRESSION_PROFILES as D, deepFreeze as E, CustomCompressionPolicySchema as S, assertNever as T, isCompressionProfile as _, registerReviewPruner as a, resolveConfig as b, ReviewQueue as c, ContextCompressionSettingsSchema as d, DEFAULTS as f, codePointLength as g, charsToTokens as h, recordScore as i, AUTO_COMPACT_THRESHOLD_LIMITS as l, charsForTokens as m, invalidateOnTaskChange as n, resolveReviewPruner as o, PRUNE_MARKER as p, recordRecertified as r, sharedReviewStore as s, getAdvisorState as t, CONTEXT_COMPRESSION_SETTINGS_NAMESPACE as u, isValidAutoCompactThresholdPercent as v, resolveCustomPolicy as w, resolvePolicy as x, parseContextCompressionSettings as y };
962
+ export { COMPRESSION_PROFILES as C, deepFreeze as S, resolvePolicy as _, AUTO_COMPACT_THRESHOLD_LIMITS as a, resolveCustomPolicy as b, DEFAULTS as c, charsToTokens as d, codePointLength as f, resolveConfig as g, parseContextCompressionSettings as h, recordScore as i, PRUNE_MARKER as l, isValidAutoCompactThresholdPercent as m, invalidateOnTaskChange as n, CONTEXT_COMPRESSION_SETTINGS_NAMESPACE as o, isCompressionProfile as p, recordRecertified as r, ContextCompressionSettingsSchema as s, getAdvisorState as t, charsForTokens as u, CustomCompressionPolicySchema as v, assertNever as x, DEFAULT_CUSTOM_COMPRESSION_POLICY as y };
@@ -84,11 +84,6 @@ interface PresetOptionsSettings {
84
84
  readonly estimatorBaseUrl?: string;
85
85
  readonly estimatorApiKey?: string;
86
86
  readonly estimatorTimeoutMs?: number;
87
- /** Review-mode overrides (beta); mirrors the runtime PresetOptions.reviewMode. */
88
- readonly reviewMode?: boolean;
89
- readonly reviewTimeoutTurns?: number;
90
- readonly cacheHitDiscountAlpha?: number;
91
- readonly reviewHighImpactTokens?: number;
92
87
  /** Advisory advisor channel; `''` (the default) keeps the advisor off. */
93
88
  readonly advisorMode?: '' | 'host' | 'direct';
94
89
  readonly advisorTimeoutMs?: number;
@@ -153,25 +148,6 @@ declare const zh: {
153
148
  'estimator.apiKey.set': string;
154
149
  'estimator.apiKey.clear': string;
155
150
  'estimator.apiKey.overwrite': string;
156
- 'review.title': string;
157
- 'review.description': string;
158
- 'review.enabled': string;
159
- 'review.enabled.on': string;
160
- 'review.enabled.off': string;
161
- 'review.timeoutTurns': string;
162
- 'review.alpha': string;
163
- 'review.highImpact': string;
164
- 'review.badge': string;
165
- 'review.summary.autoApplied': string;
166
- 'review.summary.reviewApplied': string;
167
- 'review.summary.expired': string;
168
- 'review.summary.voided': string;
169
- 'review.row.payback': string;
170
- 'review.row.expectedSaving': string;
171
- 'review.row.estimated': string;
172
- 'review.action.approve': string;
173
- 'review.action.reject': string;
174
- 'review.action.ignore': string;
175
151
  'detail.tokenpilot-inspired': string;
176
152
  'profile.custom': string;
177
153
  'profile.native': string;