# Changelog


## 0.10.2 (2026-10-28)

- fab: monitor floating ball position persistence switched to viewport-fraction ({fx,fy}, 4-dec) — corner-follow promise on restart/maximize/resolution change, replacing the absolute-pixel model that only *looked* fine because resize-clamp kept it on-screen. Legacy {x,y} archives normalize on load (zero migration). Pure layout module `src/client/fab-pos.ts` is byte-identical with dsh-browser-cdp's (dual-side sync discipline); pinned by fab-pos.client.spec.ts (6) + rewritten monitor-fab position specs (fraction persist / legacy normalize / resize re-derive).


## 0.10.0 (2026-10-24)

- hosts: 0.2.1-rc.3 declaration-level enum addendum (18 rc; contract plane zero diff per host source-analysis) — shipped together with the stats feature below.


- stats: per-session 面板与持久化——节省统计三层口径（存量仪表 / 累计按 N 次 call 积分 / 缓存分权省钱估计）落 SQLite（`~/.dsh/storages/dsh-context-compression/stats.sqlite`，双驱动：better-sqlite3 optional → `node:sqlite`，缺席可见降级）；claims 以 (session_id, 绝对 seq, kind, component, basis) 复合主键幂等入库（BC #2671 双教训防御断言），原文与自由文本绝不落库；召回记账修复（offset 按存活面收敛、同 basis 翻负折叠 a−(b+R) 下限 −b、环形缓冲驱逐保护在面条目）；旧会话 jsonl 行为回填（sessionQuery 服务面优先 + 只读代次解码 fallback，分块调度、水位幂等、绝不写会话文件）；新增 `GET /savings/sessions` 分页面板端点（/savings 与 /monitor 契约冻结不动）；`/ccip` 面板实时控制命令（rows/mode/session/flush/backfill，optional commands 注入六线安全）；9 语面板键新增与"重启归零"文案替换；审计 errorMessage 首行+截断净化（自由文本不入持久面）。

## 0.9.8 (2026-10-18)

- hosts: 追加 0.2.1-rc.2 声明面枚举（34/34 @deepseek-ai/* 宿主 peer 逐包 npm 实测 rc.2 在版；本插件不触 ctx.web provider 与 conversation.input.model.label 槽，代码零改动，纯元数据发版；农场 rc.2 格挂账待命）

All notable changes use this file. The project follows semantic versioning after `0.1.0`.

## 0.9.3 - 2026-10-08

### Fixed

- **≤0.1.1 resume killer: tool-result-pruner loader entry failed to import**.
  The 0.1.0/0.1.1 host loader module table serves a `@deepseek-ai/dsh-session`
  without the `SessionSeq` / `deriveEventMessage` runtime exports; the static
  named imports in `pruner.ts` / `runtime/measurement.ts` died at ESM link
  time, the loader entry failed to mount, and the whole `standard` agent
  preset mount failed — every session resume on the two oldest cells errored
  with "failed to apply loader entry compaction … does not provide an export
  named 'SessionSeq'" (2026-10-08 five-cell reproduction). Both imports are
  now namespace soft-imports with feature-detected fallbacks: `SessionSeq`
  degrades to identity (old-line session seqs are plain numbers; the brand is
  new-line paranoia), `deriveEventMessage` degrades to null which the
  measurement adapter already maps to `unavailableTokenCount`. CJS-interop
  shapes (named exports under `default`) are covered too.

## 0.9.2 - 2026-10-08

### Reverted

- **Standalone settings.section restored (family-tab consolidation rolled back
  for this plugin)**: the 上下文压缩选择器 sidebar entry (`settings.section`,
  order 17, the exact 0.9.0 registration and component identity) is back as the
  only settings-nav seat; the `dsh-family.tab` contributor tab introduced in
  0.9.1 is removed. 2026-10-08 user verdict: perm-gate and cci were never in
  the family tab-ification scope — both plugins ship independent insections.
  The `plugins.bundle.config` bundle-detail card is unchanged and keeps the
  shared `sectionViaAdapter` closure adapter (now bundle-card-only).
- Tests: the four client specs (`settings-seat` / `code-skeleton` /
  `custom-contract` / `preset-options-write`) are restored to the 0.9.0
  contracts — settings.section seat pinned at order 17 with
  `ContextCompressionSettingsSection` as the mounted component.

## 0.9.1 - 2026-10-08

### Changed

- **Settings consolidated into the family in-section tab**: the top-level
  `settings.section` sidebar entry (上下文压缩选择器) is retired; the settings
  panel now appears only as a contributor tab inside the 起子插件设置 family
  section (`dsh-family.tab`, order 55), matching the 2026-10-08 fleet-wide
  consolidation decision (perm-gate compat.8 removes its duplicated seats in
  the same batch). The component goes through the shared closure
  `useCompression` adapter (extracted from the `plugins.bundle.config` card,
  which now reuses it) because neither the family-tab nor the bundle-detail
  render chain maps `inject.hooks` into component hooks. Eager-bound `tNav`
  label retained (search-index 0.5.3 family-tab incident). Server-side
  settings bridge, lease, estimator-catalog and savings routes unchanged.

### Fixed

- `packages/selector/dsh.plugin.json` version metadata was stale at
  `0.9.0-alpha.4` while the package shipped 0.9.0.

## 0.9.0 - 2026-10-08

### Added

- **One version for every Harness line**: 0.9.0 is a single release serving all 15 rc
  from 0.1.0-rc.2 to 0.2.0-rc.2 (six host lines). The per-line dist-tag scheme is
  retired — after publishing, `latest`, `dsh-0.1.2`, `dsh-0.1.5`, `dsh-0.1.7` and
  `dsh-0.2.0` all point at 0.9.0.
- **Three-generation settings waist**: at startup the plugin detects which settings
  face the host exposes — the legacy `settings.register` service (0.1.0-0.1.5) or
  loader-managed volatile config + `configForms` (0.1.7+/0.2.0) — and arms only the
  matching client surface (`settings.section` vs `configForms`), plus the
  `plugins.bundle.config` package-detail card on 0.1.7+.
- **Settings bridge**: on legacy lines tools read and write through a lease-writable
  settings namespace (enveloped tool results); on modern lines they read the
  configForms document directly, and bridge writes return 409 by design.
- The `plugins.bundle.config` detail card renders the full settings component via a
  closure-built `useCompression` (the package-detail chain has no hookContext, so
  entry-level hook injection is unavailable there).

### Fixed

- The generation probe no longer caches a provisional answer at wire time: absence of
  the settings service during row composition (before host services exist) is
  re-resolved when the service actually injects — the legacy lease arm was previously
  dead on 0.1.0.
- The tail-trim validator compares the replacement's source kind against the
  generation-gated writer instead of a hardcoded plugin id, so it no longer rejects
  its own legacy enveloped output.
- The configForms client arm resolves the service off the injected owner context's
  `.configForms` property; using the raw Context as the handle made `get()` return
  `undefined` and the host slot boundary abdicated the settings section into a dead
  cell on 0.1.7.

### Changed

- All `@deepseek-ai/dsh-*` peer ranges and `engines.dsh` enumerate the 15 rc
  explicitly, so no engine/peer gate blocks installation on any host line.


## 0.8.0 - 2026-10-02

> 0.2.0-beta 渠道(beta.3-beta.7)转正。本期主线功能(节省统计、意图摘要、
> 压缩监控悬浮球、会话绑定、上下文占用条、灾难性遗忘区建议压缩)已同步
> cherry-pick 到 compat/0.1.7 / compat/0.1.5 / compat/0.1.2 三条适配线。
> 各 beta 节保留于下方,内容即 0.8.0 的完整变更清单。

## 0.8.0-beta.7 - 2026-10-02

### Added

- **灾难性遗忘区建议压缩**: the monitor snapshot carries a `suggestion` block — when
  observed context occupancy reaches `MONITOR_SUGGEST_PCT` (0.7, deliberately one notch
  below the host Auto Compact default of 80%) the floating bubble lights up (breathing
  tint) and the panel shows a localized hint recommending compression or history trimming.
- Context occupancy observation is decoupled from the intent-summary gate: every turn
  records live tokens vs the auto-compact-derived window, so the occupancy bar and the
  suggestion work even with intent summaries off (previously the bar stayed empty).

## 0.8.0-beta.6 - 2026-10-02

### Added

- **Session binding for the floating monitor**: a deliberately invisible `conversation.input.left`
  seat captures the active session id (pm longtask precedent) — the panel now shows the bound
  session's data and its override buttons act on that session instead of the default one.
- **Context occupancy bar** in the panel: the turn-tail postflight observes live tokens vs the
  auto-compact-derived window per session; the panel renders the occupancy percentage
  (hot tint past 70%).

### Fixed

- Client specs that captured the settings face by `inject` presence now key off the
  `settings.section` seat explicitly (the input-bar binder's `inject` is a session callback).

## 0.8.0-beta.5 - 2026-10-02

### Added

- **Compression monitor floating panel (FAB)**: a draggable bubble beside the input area
  (visibility switch in the settings section, default off) that polls a new
  `GET /{endpoint,api}/.../monitor` snapshot — net/gross savings, cache hit rate, cost
  estimate, and the turn-tail intent-summary gate state — with session override buttons
  driving the same state machine as `/ctx-summary`. Skeleton adapted from the withdrawn
  pm longtask FAB (d29bcb1); negative net savings light the bubble.
- The savings pricing helper moved to `runtime/monitor.ts` (shared by the savings and
  monitor routes; no behavior change).

## 0.8.0-beta.4 - 2026-10-02

### Added

- **Turn-tail intent summary** (merged from the feat/intent-summary line): growth-gated turn-boundary postflight folds the consumed increment into per-candidate `intent-summary` blocks; `/ctx-summary off|on|status` gives a session-scoped override; the settings section now carries its own on/off card (nine languages) instead of relying on host forms.
- `@deepseek-ai/dsh-commands` joins the installation-provided runtime set (the command registry import), and the release gates track the post-merge chunk graph (`lib/intent-gate.js`).

## 0.8.0-beta.3 - 2026-10-01

### Added

- **Savings statistics with honest accounting** (inspired by the dsh-token-optimizer concept): every published reduction now lands in a per-process ledger (`runtime/savings.ts`) keyed by the rewrite audit's own `tokensBefore − tokensAfter` — realized savings only, never the theoretical maximum. **Negative savings are paired, not ignored**: the original text of each reduction is SHA-256 registered, and when the model later re-reads that content in full (a new tool result whose hash matches, or a `context_compression_retrieve` return), the re-read tokens are booked as an offset against the earlier claim — skeleton-then-full-read nets negative, exactly as it should. Exact-tokenizer and chars/4 bases are aggregated separately and never merged into one number.
- Surfaces: read-only `GET /{endpoint,api}/dsh-context-compression-improved/savings` snapshot route (always-on, aggregates only — no session content), and a savings card in the settings section (net/gross/offsets, per-component breakdown, recent offsets) in all nine UI languages.
- **Usage aggregation & cache-hit monitoring** (the dsh-token-optimizer monitor concept, merged with the honest ledger): every fresh request boundary records the official TokenMeter usage of the last completed request into the same per-session ledger; the snapshot aggregates real input/output/cache-read/cache-write tokens and derives the cache hit rate — the health metric that tells you whether compression is actually saving money or just destroying prefix cache. Sessions are bucketed per net savings (top 8), and a one-line per-session account (net, offsets, requests, cache hit) is logged to the Harness logger on `session/disposed` (probe-registered: hosts without the event stay silent).
- **Cost estimation on the snapshot route**: when the current host route resolves to an official DeepSeek price record, the response carries the actual aggregated cost plus an estimated saved cost (net exact tokens priced at the cache-miss input band, explicitly labeled an estimate); third-party routes fail closed to no pricing rather than inventing numbers.

## 0.8.0-beta.2 - 2026-10-01

### Added

- Japanese (`ja`) and Korean (`ko`) UI locale dictionaries for the selector settings section, bringing the client surface to nine languages (zh / en / de / es / fr / it / ja / ko / ru). Both dictionaries are type-checked against `ContextCompressionLocaleKey`, so a future selector key cannot silently miss a translation; labels are self-described (`日本語` / `한국어`) and fall back to English per key.

## 0.8.0-beta.1 - 2026-09-30

### Changed

- Harness 0.2.0 compatibility line: all 23 `@deepseek-ai/dsh-*` peer ranges moved to
  `>=0.2.0-rc.1 <0.2.1-0`, and `engines.dsh` follows in all three manifests (root,
  selector package, plugin manifest). `publishConfig.tag` becomes `dsh-0.2.0`; the 0.1.7
  line remains served from `dsh-0.1.7` (now `0.7.0-beta.1`), the 0.1.5/0.1.2 lines from
  their own dist-tags.
- 39 of the 41 pinned overrides and 46 of the 48 dev-dependencies moved to `0.2.0-rc.1`;
  `@deepseek-ai/dsh-agent-presets` (`0.1.6-alpha.2`) and `@deepseek-ai/dsh-code-runtime`
  (`0.1.5-rc.3`) keep their pins — neither package has any 0.2.0-line release.
- Release gates re-targeted: the packed-install e2e harness pin now checks out the
  official `dsh-v0.2.0-rc.1` tree (`4878cdab`), and the built-artifact contract test
  asserts the `configForms` client slot (renamed from `settingsScope` on the 0.1.7 line).

## 0.6.5 - 2026-09-29

### Fixed

- Dev-dependency alignment to the Harness 0.1.7 line: 46 of the 48 `@deepseek-ai/dsh-*`
  dev-dependencies moved from the precise `0.1.5-rc.2` pin to the precise `0.1.7-rc.2` pin,
  and `pnpm-lock.yaml` was regenerated from a clean tree. Typecheck, build, test, lint, and
  `verify:release` now run against the real 0.1.7-rc.2 baseline instead of validating the
  0.1.7 adaptations against 0.1.5 inputs (a false green). Two packages have no 0.1.7-line
  release at all and keep their install-time pinned values: `@deepseek-ai/dsh-agent-presets`
  (`0.1.6-alpha.2`) and `@deepseek-ai/dsh-code-runtime` (`0.1.5-rc.3`). `react-dom` gained an
  explicit `^18.2.0` dev-dependency so a fresh resolution cannot pair React-DOM 19 with
  React 18 under the test suites.
- The test-host settings seam was rebuilt against the real 0.1.7 host: `SettingsProvider`
  no longer exists in `@deepseek-ai/dsh-settings` (replaced by the declarative
  `SettingsForms`), while the plugin keeps the legacy `ctx.settings.get(ns)` read as a
  host-shape fallback. The specs now mount a vendored copy of the 0.1.5-rc.2 provider
  (`tests/helpers/legacy-settings/`) to exercise exactly that fallback, and the
  legacy-namespace registrar narrows the service at the seam. The live DeepSeek harness test
  registers the provider through the 0.1.7 adapter seam instead of the removed
  self-contained `llm-deepseek` plugin.
- Test adaptations surfaced by the real baseline: the compaction-engine fixtures pass
  `headroomTokens: 0` (0.1.7-rc.2 defaults a 65536-token compaction headroom, which swallows
  the fixtures' 1k-token probe windows), and the tool-result asset assertion follows the
  first-class `role: 'tool'` message shape (no wrapping `tool-result` content block).
- Release gates re-pinned to the official 0.1.7 release: `verify-release.mjs` and the packed
  E2E now assert selector peers `>=0.1.7-rc.1 <0.2.0-0`, and the packed E2E's official-harness
  clone asserts tag `dsh-v0.1.7-rc.2` (commit `477b4f42`, tree `e3e63253`).
- `packages/selector/dsh.plugin.json` now carries the release version (0.6.5; every earlier
  0.6.x shipped it frozen at 0.1.0) and declares the honest engine range
  `>=0.1.7-rc.1 <0.2.0-0`.
- Lint debt from the 0.6.3 manual adaptations cleared: unused imports/locals removed in
  `src/index.ts`, `src/client/index.ts`, `src/pruner.ts`, and three host specs; the
  standing-generation staging-leftover scan now scopes to the spec's own store so a
  concurrently publishing spec cannot fail it.

## 0.6.4 - 2026-09-26

### Fixed

- The client locale binder is eager: switching the host locale now re-renders the
  compression settings UI without a remount.
- Released from a stash and never committed to any branch (the working tree that published it
  was lost); compat/0.1.7 restored the exact content in 0.6.5 and byte-verified it against
  the registry tarball before continuing.

## 0.5.4 - 2026-09-20

### Fixed

- The install surface declares `@deepseek-ai/schemastery` as a runtime dependency. The packaged
  runtime imports it unconditionally (`import z from '@deepseek-ai/schemastery'` in
  `packages/selector/lib/index.js`, `lib/pruner.js` and `lib/advisor-state.js`), but 0.5.3
  declared it nowhere a consumer install reads: the shipped root manifest listed only
  `@huggingface/tokenizers` and `js-yaml`, and `packages/selector/package.json` listed it as a
  peer, which no package manager consults for a nested package it installs. Resolution therefore
  depended on an unrelated installed package hoisting `@deepseek-ai/schemastery` into the
  profile. In a clean install the import fell through to the Harness installation's
  shared-module fallback at `$DSH_HOME/profiles/node_modules`; where that fallback held no built
  package, every plugin entry failed to load and the host booted without the Bundle layer. Both
  manifests now pin `3.18.2`, the version this release is built and tested against, and the
  selector package no longer claims a peer obligation it does not have.

### Added

- `verify:release` derives the install-surface dependencies from the bare specifiers the
  packaged runtime files import, instead of naming `@huggingface/tokenizers` and `js-yaml` by
  hand. Which packages ship with the plugin and which the Harness installation provides is a
  reviewed list, and an import whose provider is in neither manifest fails the gate with the
  missing name. The gate was added as a negative control against the unfixed manifests, where it
  failed on `@deepseek-ai/schemastery`.

## 0.5.3 - 2026-09-20

### Fixed

- The Bundle patch no longer sets the retired review route flag. `reviewQueueRoute` was
  removed from the plugin's Config schema when the review gate was retired, but it stayed in
  `packages/selector/cordis.patch.yml`, where it advertised a route that can never register.
  Hosts tolerate the unknown key today (the plugin loads and serves — verified on a live host),
  so this is a stale-config defect rather than a break, but it would break on any host that
  validates plugin config strictly.
- Generated artifacts are pinned to LF (`packages/selector/lib/** text eol=lf`). With
  `core.autocrlf=true` every checkout rewrote the committed `lib/**` to CRLF, so any branch
  switch or merge left the whole artifact directory reported as modified with EOL-only
  differences. Nothing was ever committed from that state, but it made every tree look dirty
  and it would hide a real artifact change.

### Added

- A negative-control contract pin on the Bundle patch: it fails when a retired config key is
  set in the patch (asserted on key-setting lines, so the explanatory comment may still name
  the key), and it requires the live `estimatorCatalogRoute` flag to stay wired.

### Tests

- The client seat contract also pins the older-host degradation: a host that does not declare
  the seat rejects the registration at the slot boundary, and `apply()` must swallow it and
  warn instead of taking every settings entry down with it.

## 0.5.2 - 2026-09-20

### Changed

- The human-gated review pipeline (beta) is **retired**. Its semantics are replaced by
  advice: the benefit model still prices every pass as ONE merged mutation, but the band it
  computes (`profitable` / `high-impact` / `slow-payback` / `unpriceable` / `not-worth-it`)
  is now published as a `reduction-advice` audit record and snapshotted onto the advisor
  report route — it never withholds, delays, or rewrites a reduction. The gate contradicted
  the feature's own requirement (a reduction must never block automatic processing) and, with
  the shipped defaults (`reviewMode` on plus a 4,000-token high-impact threshold against an
  8,192-token fresh trigger), diverted 100% of a fresh batch into human review, leaving the
  automatic path effectively off for anyone who opted in. The advice thresholds are now
  module constants (α `0.1`, high-impact `4,000` tokens): nothing acts on them, so they are
  no longer settings.
- Removed with the gate: the review queue and its `storageDomain` adapter, the process-wide
  registry, the `review-queue` / `review-decide` HTTP routes and the `reviewQueueRoute`
  deployment flag, the `shell.overlay` client panel, the `reviewMode` /
  `reviewTimeoutTurns` / `cacheHitDiscountAlpha` / `reviewHighImpactTokens` settings keys,
  and the `review-outcome` audit kind. The four settings keys stay ACCEPTED and IGNORED by
  both decoders — an existing document (the live one carries `reviewMode: false`) still loads
  and still renders its settings card — and never reach the resolved policy. The read-only
  `GET .../advisor-report` route additionally serves `lastAdvice`.

### Added

- Regression pins for the retirement: a host-integration spec drives the exact settings that
  used to divert everything (`reviewMode: true`, `reviewHighImpactTokens: 1`) and asserts the
  fresh batch LANDS, described by a `high-impact` advice record; a deprecation-contract spec
  pins accept-and-ignore for the retired keys on both the runtime parser and the browser
  decoder.

### Rollback

- Reinstall the last release that still ships the gate: `npm dist-tag add
  dsh-context-compression-improved@0.5.1 dsh-0.1.5 --registry https://registry.npmjs.org/`
  then `dsh plugin --profile web add dsh-context-compression-improved@0.5.1`.

## 0.5.1 - 2026-09-20

### Fixed

- Concurrent preset-overlay composition of one identity no longer fails on Windows.
  Publication is now serialized per destination path, and when the atomic rename still
  loses the race the destination is confirmed to already carry this staging file's
  `{mtimeMs, size}` standing key before the publish reports success. Windows `MoveFileEx`
  reports that lost race as `EPERM`/`EBUSY` where POSIX `rename` simply replaces the
  destination, which made `standingKeyFor()` throw during concurrent session start. A
  destination that does not match still fails loudly, so a silently reused generation
  stays forbidden.
- Release-gate and test repairs that had been hiding this and other pre-existing red
  gates: stale identifiers and a retired audit reason in the packed smokes, a stale
  client-inject expectation, and Windows-only spawn traps (`git` and multi-line
  `node -e` scripts were routed through `cmd.exe`, which rewrote their arguments).

## 0.5.0 - 2026-09-20

### Added

- Advisory relevance advisor (statistics and suggestions only, default off): at every turn
  boundary a fire-and-forget pass summarizes the session's tail-task semantics from the
  most recent `todo/write` event (falling back to recent user text), incrementally scores
  historical tool-result candidates for content-and-comment relevance against the current
  task, and computes a prefix-decay figure (character-pressure-weighted mean relevance).
  Low-relevance old segments are marked `recertified` as suggestions for later
  history-aggressiveness decisions — nothing this round consumes them, and advisor output
  can never suppress, delay, or rewrite any reduction that would land (pinned by a
  dedicated invariant test). Configure through the `presetOptions.advisor*` settings keys
  (`advisorMode` `''|'host'|'direct'`, default `''`; the direct channel reuses the
  estimator endpoint; `SideChannel` gained an optional overrides parameter so the
  estimator's transport is shared without sharing its configuration). Observability: new
  `advisor-outcome` audit records (content-free, one per phase: summary / scoring / decay)
  and a read-only `GET .../advisor-report?sessionId=` HTTP route (opt-in deployment flag
  `advisorReportRoute`, mirroring the review routes). Client UI is intentionally absent
  this round.

## 0.4.0 - 2026-09-20

### Fixed

- The plugin no longer depends on the routed model id: every planning gate now decides on
  the character basis (Unicode code points via `characterPressure` / `pressureCost`) instead
  of exact tokenizer counts, so a route without a bundled tokenizer (the live
  `deepseek-flash`) lands rewrites again instead of silently skipping. Token thresholds keep
  their names and values (converted at the documented 4.0 chars/token convention, frozen
  profile baseline untouched); token figures become telemetry, labelled honestly by the new
  `measurementBasis` field on rewrite audit records (`exact-tokenizer` vs `characters`,
  with `tokenizerId: 'characters'` / `tokenizerRevision: 'chars-per-token-4.0'` when derived).
  Rollback: `git revert 7a1972a` restores the exact-tokenizer gates as a single unit; confirm
  no later change re-introduced a model-id split that relies on this commit first.

### Added

- Batch-level benefit pricing (R1): a review pass is priced as ONE merged mutation — the
  tail KV-cache refill penalty is paid once per batch instead of per candidate, so real
  batches (5×50k with a 64k tail) reach the auto band instead of all dropping.
- Original-event line mapping (R9a): terminal normalization returns folded lines that each
  carry their 1-based original-event line number; `retrieve` reads raw events, so printed
  ranges resolve to the right lines.
- Document skeleton and universal prose keep (R8/R8b): structured documents keep headings,
  section first/last lines, list starts and table headers; every other non-code text keeps
  head AND tail with an R9 line-range marker (prose was previously head-only truncated).
- Two-tier search folding (R10, fixes D8): a lossless per-file L1 locator plus a
  water-filled L2 content quota.
- Non-adjacent frequency folding (R11): separated exact repeats (up to 8.37% of large
  results) fold to first occurrence plus one counted marker.
- Long-string placeholders (R12): base64/hex/UUID blobs become length summaries with a
  16-char recognition prefix.
- Two-stage HTML reduction (R13, fixes D9): `html-slim` then `html-skeleton`, line-aligned
  so original line numbers survive.
- R9b anchors: contiguous masks cite original line ranges, scatter masks report
  `lines 1-N scanned, K kept`, and every retrieve hint carries a pasteable
  `{"ref":…,"start_line":N,"max_lines":80}`.
- Document census: omitted-document summaries list section headings instead of a constant
  `0 error, 0 warn, N info` histogram.

## 0.3.1 - 2026-09-18

### Changed

- The runtime package is merged into the selector package: one install brings the whole
  stack, the repository root is the install surface (`name`, `main`, `types`, `exports` with
  `./pruner` and `./invariant`, `dependencies`, `dsh`), and the toolchain, scripts and CI were
  swept to the single package. The verified estimator-catalog registration (dual prefix, guarded
  two-channel activation, per-request service resolution, visible lifecycle lines) was replayed
  onto this line with a host-side guard; the settings schema that `ab2175a` had downgraded to
  `z.any()` is restored, so the daily Custom defaults are published again.
- Adapt to the official DeepSeek Harness `v0.1.5-rc.2` on this branch. All `@deepseek-ai/dsh-*` dev dependencies and the pinned e2e host set move from `0.1.1-rc.2` to `0.1.5-rc.2` (cordis `4.0.2`, schemastery `3.18.2`), including the new split packages (`dsh-session-projection`, `dsh-session-persistence`, `dsh-atomic-write`, `dsh-home-paths`, `dsh-sandbox`, and related) and the `dsh-client-store` client stack.
- Surface replace operations now use the v3 `startSeq`/`endSeq` shape with branded `SessionSeq` values; `compaction/prune` manifests keep the durable `start`/`end` fields. Events are resolved from surface nodes by seq lookup instead of array indexing.
- The client bundle no longer imports the removed `@deepseek-ai/dsh-client-runtime`: settings types now come from `@deepseek-ai/dsh-client-ui-settings` and the session hooks merge from `@deepseek-ai/dsh-client-ui-session`. `engines.dsh >=0.1.5-alpha.1 <0.2.0-0` is declared in both package manifests and `dsh.plugin.json`.
- Harness 0.1.5 no longer exposes the session `agentPreset` to the browser, so the client can no longer detect Minimal-only sessions; the selector stays selectable and the old unavailable banner is unreachable.
- Test batteries updated for 0.1.5 semantics: cordis plugin starts require `.await()`, the Token Meter requires a mounted `SessionProjectionRegistry`, assistant events carry `stream: []`, and settings namespaces are plain strings.

### Fixed

- The estimator card no longer demands an API key on the Harness host channel. Selecting the host channel shows the live provider/model dropdowns, names the route that would actually run (explicit override, else the session default), and renders neither a key field nor a second manual model input: the base URL, the model text field, and the write-only key belong to the direct endpoint channel alone.
- `presetOptions` writes are path-addressed. Writing the whole section replaced it, so touching any second estimator field (a provider, a model, an endpoint) deleted `estimatorMode` and every sibling override — silently switching the estimator back off while the panel still reported a successful save. Each field now writes only itself, `undefined` clears exactly the field it names, and the confirmation read validates the same field set instead of the mode alone.
- New coverage: `packages/selector/tests/preset-options-write.client.spec.ts` (path-scoped writes, sibling preservation, explicit clears, no-op patches, uncommitted-write reporting) and `packages/selector/tests/estimator-channel.client.spec.tsx` (per-channel fields, catalog dropdowns, manual fallback).


### Added

- New `tokenpilot-inspired` profile: a TokenPilot-paper-inspired capability matrix layered on the Balanced thresholds, selected explicitly from the settings UI; every pre-existing profile keeps a byte-identical resolved policy (enforced by a captured-baseline golden test).
- Byte-identical repeated tool-result dedup: an oversized repeat is replaced with a pointer to the first occurrence's append-only original event (`dedupe-pointer`), with a per-session SHA-256 index (2,048-entry insertion-order eviction, hash+seq metadata only).
- No-net-savings guard: replacements whose text is not smaller than the original are rejected even when the exact tokenizer reports a token saving.
- Recovery exemption: recovery-tool output is permanently exempt from every reduction pass via a unified per-session exemption set, preventing compress-restore oscillation.
- Auto Compact summary locator: after `compaction/end`, the landed summary checkpoint gains an Exact Sources block (shadowed seq range, spill files, touched files) so summarized-away details stay recoverable; skipped when it would locate nothing concrete.
- Read-state semantics: a historical read whose file was later mutated is `superseded` and takes the small whole-result placeholder; optional error/warn/info clustering of omitted lines is appended to historical placeholders.
- Optional residual-utility estimator (three channels: off / Harness host model / direct OpenAI-compatible endpoint) with per-session exponential backoff, strict timeout, advisory-only verdicts consumed by the next pressure pass, and numeric-only `estimator-outcome` audits. The estimator card appears only while the new profile is selected; the API key is write-only in settings and never enters the frozen policy, audits, or logs.
- New audit records: `summary-locator` and `estimator-outcome`; the rewrite record covers dedup via the `dedupe-pointer` reducer. Audit field allowlists are unchanged.
- Simplified Chinese and English copy for the new profile and estimator card; unit and golden coverage under `packages/runtime/tests/tokenpilot/`.

- Orthogonal code-skeleton compression gate (`codeSkeleton.enabled`, default off): the first exposure of an oversized fresh source-code tool result can keep an imports-and-declarations skeleton with bodies elided and error lines preserved, falling back to the original head pruning. The gate is independent of every profile and gated on exact tokenizer measurement.
- Settings-UI toggle for the gate in the selector settings section, with Simplified Chinese and English copy.
- Browser/runtime decode parity for the new section, confirm-on-write contract tests for `saveCodeSkeleton`, and a full-document parity matrix extension.

### Changed

- Added an ESLint flat-config baseline (`pnpm lint`, enforced in CI) and a `pnpm test:watch` TDD loop; removed dead imports and hardened two error paths surfaced by the lint baseline.
- This repository is now maintained as an improved fork of `WilliamShi666/dsh-context-compression-selector`; documentation ships in English, Simplified Chinese, Japanese, and Korean.

## 0.1.0 - 2026-09-03

### Added

- Stable release of DeepSeek V4 Flash Vision tokenizer integration for `deepseek-v4-flash-vision-exp`, including exact text counting and bounded image-token estimates.
- User-configurable model-driven Auto Compact threshold in the selector settings section.
- Auto Compact threshold linkage for each standard profile's History / micro-compact watermarks and related compression parameters.

### Changed

- The threshold editor now uses one direct numeric input; the slider and fixed quick-value buttons were removed.
- Runtime session-event access supports both the established Harness `events` accessor and the newer `snapshotEvents()` public API.

## 0.1.0-beta.4 - 2026-09-02

### Fixed

- Support the official DeepSeek Harness `dsh-v0.1.2-alpha.5` public API while retaining compatibility with the existing `0.1.1-rc.2` peer range. The plugin now owns the two small immutable-value helpers that the newer Harness no longer exports, and uses the same public `context-compression` namespace literal accepted by both Settings implementations. No Harness core code is modified.

## 0.1.0-beta.3 - 2026-09-01

### Scope

This is a staged release. Exact **text-class** token counting for `deepseek-v4-flash-vision-exp`, best-effort bounded **vision-class image** estimates, and the Auto Compact threshold/UI/audit work are delivered. Exact image measurement remains **BLOCKED upstream**: the current measurement seam exposes neither the adapter's projected request-image dimensions nor the absolute serialized position, so estimates cannot be promoted to `exact-tokenizer`.

### Added

- DeepSeek V4 Flash Vision support for `deepseek-v4-flash-vision-exp` via a separately bundled official tokenizer pinned at `deepseek-ai/DeepSeek-V4-Flash-Vision-Exp` revision `6821d6ad3681a4b137b066b76094fa82ebd0a380`. Text, reasoning, tool-call arguments, and pure-text tool results are counted exactly; image-bearing tool-result candidates stay fail-open.
- Vision image-token arithmetic ported line-by-line from the official `inference/image_processor.py` (patch size 14, downsample 3, 384-token cap, min pixels 147456, 8:1 aspect clamp, and position-dependent alignment padding), validated against golden fixtures generated by executing the official Python implementation. Valid intrinsic dimensions now produce `tokenizer-estimate` at the midpoint of all four alignment residues with a 384-token per-image upper bound; malformed or unevaluable dimensions use a documented 256-token fallback. Mixed text/image surfaces aggregate exact text and estimated images without promoting them to exact.
- `autoCompact.thresholdPercent` setting (default 80, integer 50–90, step 1) with one shared validation contract across the settings UI, the persisted schema, and the runtime resolver. The editor lives inside the context-compression selector settings section.
- Standard-profile History linkage to the Auto Compact watermark: `A = floor(C × a)` rescales the History trigger, minimum reclaim, and recent-token tail; `D = floor(A × 0.875)` replaces the fixed 0.7 capacity-pressure ratio as the micro-compact last-chance gate; one batch must justify its cache break by pulling the complete request back below the deadline. Defaults at 80% reproduce the previous numbers exactly.
- The preset overlay writes the saved threshold into the generated `compaction-basic` composition as `thresholdRatio` (with `retainRatio` pinned at 0.16) and, from the same read, into the plugin runtime's deployment config as `autoCompactThresholdPercent`, so one standing generation never runs Auto Compact and micro compact on two different thresholds. Any generation-identity change — threshold, source, or module paths, including equal-length ones — produces a new standing composition generation. Deterministic identity-derived stamps use an 8-hex whole-second window; equal-prefix identities can collide in that first window on a coarse filesystem, so the overlay observes the staging file's real `mtimeMs+size` key and escalates to later hash windows before the atomic rename. Content, permissions, and the final unique stamp are complete before publication; already-running sessions keep their frozen policy.
- `policy-resolved` audits now record the Auto Compact coordination facts (threshold percent, `A`, `D`, parameter source — including `deployment-override`/`mixed` when deployment config replaces linked History watermarks), the routed provider/model, and the bundled tokenizer identity.
- Persisted settings reject present-but-invalid sections (`profile: null`, `custom: null`, own-property `undefined`) before any schema default can absorb them; a malformed stored document freezes the session losslessly (`profile: off`, audited as `settingsInvalidFallback: lossless-off`) instead of silently enabling the lossy Balanced default. The browser decoder applies the same rule and canonicalizes legacy Custom v1/v2 documents to the same v3 document the runtime resolver produces.
- The History planner returns a discriminated outcome, and `component-evaluation` audits distinguish the full skip taxonomy: `below-profile-trigger`, `below-micro-deadline`, `exact-tokenizer-unavailable`, `no-safe-candidates` (only recovery-tool output or already-cleared results), `protected-working-set` (everything inside the protected tail), `insufficient-reclaim` and `cannot-reach-deadline-target` (with the reached/required token numbers), `adaptive-cost-rejected`, and `recovery-tool-unavailable`.

### Known limitations

- Images never claim exact counts. The official expansion depends on the absolute prompt position (system prompt, chat-template framing, adapter image handles) and on the adapter's final request-image projection (including per-route `imagePixelBudget`/`imageDetail` overrides and byte-cap reprojection), none of which is exposed through the current measurement seam. Intrinsic/default estimates may therefore differ materially from provider accounting. Upstream capability requests remain projected request-image dimensions and the absolute serialized position exposed to token-meter extensions.
- History skips the whole batch whenever any tool-result candidate lacks an exact count, including image-bearing candidates, even though sibling text candidates are individually exact.
- Custom remains manual token mode; its History parameters do not follow the Auto Compact watermark.
- A vision token breakdown UI is not shipped; image estimates and the intrinsic alignment diagnostic are available on the measured token view, while lossy rewrite proofs still require exact counts.

### Deferred

- Audit `modality` field and the tokenizer artifact SHA-256 inside audit records (the audits already carry the routed provider/model and tokenizer identity).
- Publishing the (now complete) runtime skip-reason taxonomy as a user-facing documentation table.
- Custom-profile display of the A/D watermarks and an above-D warning; Custom remains fully manual.
- Vision token breakdown UI and promotion of image estimates to exact measurement.

## 0.1.0-beta.2 - 2026-08-28

### Fixed

- Resolve the official DeepSeek V4 Flash tokenizer route so Fresh and Aggregate can evaluate tool results for the supported V4 models.
- Run Cache Strict History at the real request boundary once its configured capacity-pressure condition is met; trigger the capacity condition at 70% routed-context utilization.
- Disable Harness-native head/middle/tail tool-result pruning whenever a selector profile is active, leaving the selector as the sole tool-result compactor.

### Changed

- Protect the newest 10 agent tool calls and a 64,000-token tool-result tail window before History/microcompact rewrites older results.

## 0.1.0-beta.1 - 2026-08-27

### Added

- One-install DeepSeek Harness Product Bundle backed by a separate exact-version runtime package.
- Web profile selector with preset-stable settings and an explicit built-in Minimal exception.
- Fresh, Aggregate, routine/capacity-aware History, Native tool-result pruning, and default-off Custom TailTrim.
- Standard-event TailTrim protocol using `compaction/prune` plus recoverable `user/message` replacement.
- Plugin-owned `context_compression_retrieve` recovery tool.
- Structured, content-free policy, evaluation, rewrite, failure, and Native auto-compact audit records.
- Pinned official DeepSeek V4 tokenizer assets with runtime SHA-256 validation and upstream license.
- Public-API component E2E, preset/Minimal, and parent/fork/spawn cache-prefix regression tests.

### Compatibility

- Verified against DeepSeek Harness `dsh-v0.1.1-rc.2` public packages.
- Exact tokenizer mapping is currently limited to `deepseek-v4-flash` and `deepseek-v4-pro`.

### Known limitations

- Adaptive ordinary History fails closed when public request-level route/cache evidence is incomplete; capacity pressure remains a separate safety override.
- Cache-prefix tests prove native fork inheritance and identical serialized prefixes, not a provider-specific cache allocation or a guaranteed DeepSeek cache hit.
- Settings snapshots and first-exposure decisions are process-local to the mounted runtime.
