# Changelog

## 0.3.0 — 2026-08-16

### Added
- **Image token budget** (`imageBudget`, default 3): on vision routes each
  attached screenshot keeps billing on every subsequent request, so the
  attach path is budgeted per session; identical screens are content-hashed
  and never re-attached (free); both skips disclose themselves as deliberate
  economy, not failure. The PNG + geometry table always ship.

### Fixed
- **Image state is per-SESSION, not per-project** (pre-release review P1):
  one plugin instance serves many sessions in the dsh host, and cwd-keyed
  budget/dedupe state leaked across conversations — a brand-new session
  taking its first screenshot could be told the image was "still in your
  context" when its context held nothing. State now lives in a `WeakMap`
  keyed by the session object and dies with it. `mp_session restart`
  deliberately does not reset it: a daemon restart changes nothing about
  what a conversation's context was already billed.
- **G1 cache window removed**: the quick doctor costs 0.10–0.18s measured
  (`docs/evidence/quick-doctor-timing.txt`), and the 30s verdict cache was
  exactly the hole where "touch a .ts, act within the TTL" ran green against
  a stale build. Every act now gets a fresh verdict; the stored one only
  feeds the read-tools' warning line.
- **`imageBudget` is clamped** to a non-negative integer: `0` (or negative)
  disables attaching with a deliberate-economy message. Through the dsh host
  a non-numeric value is rejected by schema validation before the plugin
  loads; the in-plugin clamp (`NaN`/junk → default 3, never unbounded) is
  defense-in-depth for schema-less embedding.
- Dedupe disclosure reworded compaction-safe: "an identical image **was
  attached earlier** this session" stays true even after the host prunes
  old turns; "is still in your context" did not.

### Removed
- **`freshnessTtlSeconds`**: dead since the G1 cache removal — dropped from
  the config schema rather than shipping a knob that silently does nothing.
  If you had raised it to cut doctor spawns, note the measured cost above;
  `freshnessMode: warn` (or `off`) is the supported lever now.

### Packaging
- The npm tarball now ships `test/` and `scripts/`, so `npm test` works
  inside the installed package (it previously referenced unshipped files);
  the harness still self-skips visibly on machines without the dsh host.

- `STEP_TIMEOUT` now maps to a real remedy (session restart; if screenshots
  alone keep timing out, restart WeChat DevTools — a wedged render process
  does exactly that, observed live).

### Verified
- Complex-case live battery: state loops (eval→data), navigation loops,
  camera-less scan, console generate-and-read, and the full image
  budget/dedupe/exhaustion arc on a real vision route (exactly 3 image
  blocks in requests, vision proof quoted from pixels) —
  `docs/evidence/live-matrix.md`. Live scroll assertion was an honest N/A
  (the test app scrolls inside a `scroll-view`; scroll math is pinned by the
  in-repo harness instead).
- Doctrine addition from live evidence: native overlays (`wx.showLoading`)
  never appear in DevTools screencaps — byte-identical PNGs, so the dedupe
  correctly refuses to re-attach; the skill now says so.

## 0.2.0 — 2026-08-16

Every change traces to a ledgered residual from the 0.1.0 audit rounds
(`docs/ATTACK-LEDGER.md`).

### Added
- **In-repo harness for `lib/index.js`** (`test/index.test.js` + `scripts/link-host.mjs`):
  fake-ctx + injected executor against the REAL host packages; self-skips
  visibly (a registered skip, narrowed to the absent-host case only) on
  machines without dsh. 46 tests total.
- **Scroll-aware visibility**: element flags are now computed against the
  current scroll window (`step scrollTop`), disclosed as `scrollTop=` in fact
  tables; an unreadable scroll position is disclosed, never silent.
- `CHANGELOG.md`, `engines: node >= 20`.

### Fixed
- `mp_console` walks every buffer page (bounded ×20) instead of assuming the
  ≤2000 merged cap; every early-exit path sets the unread-tail disclosure.
- All tools declare `isConcurrencySafe: () => false` explicitly.
- Async `mkdir`/`readFile` on the screenshot path; capability probe cached
  per `binPath|cwd`; `_exec` accepts functions only.

### Verified
- Four-route live battery (DeepSeek V4-Pro / V4-Flash / Kimi k2.7-code
  declared-text / declared-image), each with in-band route proof —
  `docs/evidence/live-matrix.md`.

## 0.1.0 — 2026-08-16

First release: 8 `mp_*` tools, 5 gates, dual screenshot path. Built through
a 5-lens + cross-vendor attack battery, an execution-level fix-audit, and a
stern release review — all ledgered.
