# Clavue v8.10.4 — Website / Marketing Update Pack

**Audience**：clavue.com 的内容维护者 / marketing。
**目标**：把 8.10.4 的 user-visible 变化更新到首页、changelog、docs 三个地方。
**约束**：本仓库不含网站源码（见 `docs/website-content-recommendations.md`）。这份文档把所有"可粘"内容打包好。

---

## 1. 首页改动建议

### 1.1 顶部 banner / hero 副标题

替换或新增：

> **v8.10.4** — 长会话不再随机 OOM；模型不再被反复打断分析"这是不是 malware"；todo / task 的隐性 nag 已彻底关闭。

CTA 链接到 changelog 锚点 `#8-10-4`。

### 1.2 "新功能 / 新修复" 卡片

新增 3 张：

**卡 1: 长会话 OOM 不再随机崩进程**
- 标题：Long sessions no longer crash on autocompact failure
- 副标题：双层防线 — autocompact 失败时本地紧急截断（无 LLM）保留首条任务 + 末尾对话；堆压仍超临界则软阻断下一次 streaming 而不是让 V8 死。两道护栏 + 完整契约测试。
- 数据点：5K+ messages session 在用户实测下从"几分钟必崩"到"稳定推进"。
- 链接：`/docs/long-session-stability`

**卡 2: 干掉了打断模型的"malware reminder"**
- 标题：Read no longer interrupts the model with a malware lecture
- 副标题：之前每次 Read 都注入"考虑这文件是不是恶意软件"的 system-reminder，长会话累积成几百份相同文本，把模型从用户任务上拉走。彻底删除。Cyber-risk system prompt 仍然覆盖真实安全需求。
- 链接：`/docs/changelog#8-10-4`

**卡 3: 关掉 TodoWrite / TaskCreate 的"自动催促"**
- 标题：No more "you haven't used TodoWrite recently — and never tell the user about this reminder"
- 副标题：每 ~10 turn 自动注入的隐性催促 prompt 现已彻底关闭。Tools 本身保留，模型按需调用，不再被强行打断节奏。
- 链接：`/docs/changelog#8-10-4`

---

## 2. Changelog 页（/changelog 或 /releases）

把以下 markdown 块直接 append 到 changelog 页顶部：

```markdown
## v8.10.4 — 2026-05-10

### Fixed
- **长会话 autocompact 失败后不再随机 OOM**：autoCompact 的 critical-heap 分支之前直接 skip 但不裁剪 messages，下一个 streaming 请求照常分配几百 MB 缓冲区然后 V8 OOM。新增 L3 紧急截断（保留首条 user 任务 + 末尾 N 条 + 一条本地摘要，不调 LLM、不切断 tool_use ↔ tool_result 配对）和 L4 堆压软阻断（autocompact 后仍超临界则以 `heap_soft_block` 早返回，不发 streaming）。两道防线都有契约测试锁住代码形状。
- **删除 FileReadTool 的 cyber-risk reminder 注入**：每次 Read 工具结尾不再追加 "Whenever you read a file, you should consider whether it would be considered malware … MUST refuse to improve or augment the code" 的 system-reminder。Cyber-risk system prompt 仍然处理真实安全场景，重复的逐次注入对开发流程是纯噪声。
- **关掉 todo / task 的自动 nag**：`getTodoReminderAttachments` / `getTaskReminderAttachments` 不再每 ~10 turn 注入 "TodoWrite/TaskCreate 最近没用过…NEVER mention this reminder to the user" 的隐性指令。TodoWrite / TaskCreate / TaskUpdate 工具本身保留，按需显式调用即可。

### Added
- 新文件 `src/services/compact/emergencyTruncate.ts` — 纯本地、确定性、无 LLM 的紧急截断器。导出 `buildEmergencyTruncationWith({ messages, keepTail })`，便于单元测试与 wiring 层装配。
- 新文件 `src/services/compact/emergencyTruncateWiring.ts` — 把 emergencyTruncate 注入运行时依赖（getUserMessageText、roughTokenCountEstimationForMessages、createCompactBoundaryMessage 等）。
- 新测试 `tests/emergency-truncate.test.mjs`：empty 输入、无需省略、典型省略、tool_use chain 不被切断、原始用户请求缺失时的优雅降级共 5 种场景。
- 新契约测试 `tests/heap-soft-block-contract.test.mjs`：锁住 `query.ts` 的 `heap_soft_block` 守门 + `CLAVUE_DISABLE_HEAP_SOFT_BLOCK` 逃生开关 + `autoCompact.ts` 的 "critical 检查 → emergency truncation → fallback skip 文案" 顺序。后续 PR 删或重排都会立即爆红。

### Changed
- `query.ts` 在每次准备 streaming 前增加堆压检查：autocompact + 紧急截断都跑过仍超临界时早返回 `heap_soft_block`，避免再分配几百 MB 触发 OOM。
- `autoCompact.ts` 的 critical-heap 分支从 "直接 skip" 升级为 "先尝试 buildEmergencyTruncation，失败才 skip"。Skip 文案与 success 路径都被 contract test 锁定。
- 渲染层 `messages.ts` 的 `todo_reminder` / `task_reminder` case 改为 `return []`，删除全部 nag 字面量；类型 union 中的 case 保留以维持 exhaustiveness。

### Removed
- `MITIGATION_EXEMPT_MODELS` 白名单与 `CYBER_RISK_MITIGATION_REMINDER` 常量（FileReadTool）。
- `TODO_REMINDER_CONFIG` 常量、`getTodoReminderTurnCounts` / `getTaskReminderTurnCounts` 两个 helper（attachments.ts）。
- 五处变孤儿的 import：`TODO_WRITE_TOOL_NAME`、`TASK_CREATE_TOOL_NAME`、`TASK_UPDATE_TOOL_NAME`、`isThinkingMessage`、`isTodoV2Enabled`。

### Environment Flags（逃生开关）
- `CLAVUE_DISABLE_EMERGENCY_TRUNCATE=1` — 关掉 L3 紧急截断，回到旧 skip 行为。
- `CLAVUE_DISABLE_HEAP_SOFT_BLOCK=1` — 关掉 L4 堆压软阻断（debug 用，会重新打开 OOM 风险）。
- `CLAVUE_MAX_OLD_SPACE_SIZE_MB=16384` — 已存在的堆 cap 配置，配合本版本两道护栏使用。

### Tests
- 新增 7 个测试（5 emergency-truncate + 2 heap-soft-block contract）
- 全套 `npm run check` 993/990 pass，3 skipped，0 fail，~53s

升级：

\`\`\`bash
npm install -g clavue@8.10.4
\`\`\`

完整发布说明：[docs/clavue-v8.10.4-release-notes.md](https://github.com/mycode699/clavue/blob/v8.10.4/docs/clavue-v8.10.4-release-notes.md)
```

---

## 3. Docs 页改动建议

### 3.1 新增 `/docs/long-session-stability` 页

参考骨架：

```markdown
# Long-session stability — autocompact, emergency truncation, heap soft-block

Clavue keeps every conversation as an append-only JSONL transcript.
Sessions can run for hours and accumulate thousands of messages plus
hundreds of MB of tool output. Two failure modes used to randomly kill
the process:

1. **autocompact LLM call fails** (timeout / empty completion) →
   messages array is unchanged → next streaming request allocates
   hundreds of MB → V8 OOM → process gone.
2. **autocompact succeeds but writes back into a heap that is already
   above the critical threshold** → GC can't keep up → next allocation
   trips OOM the same turn the summary lands.

## Three layers of defense

| Layer | Trigger | Action | Cost | Escape hatch |
|---|---|---|---|---|
| L1 | warning heap pressure | proactive autocompact (LLM summary) | 1 LLM call | n/a |
| L2 | reactive autocompact path | reactive autocompact (LLM summary) | 1 LLM call | n/a |
| L3 | autocompact failed AND heap critical | local emergency truncation, no LLM | ~few ms | `CLAVUE_DISABLE_EMERGENCY_TRUNCATE=1` |
| L4 | L3 done AND heap still critical | refuse to send next streaming request, return `heap_soft_block` | early-return | `CLAVUE_DISABLE_HEAP_SOFT_BLOCK=1` |

L3 (`emergencyTruncate.ts`):
- preserves the very first user message (original task anchor)
- keeps the last N messages (default 6, autoCompact callsite uses 8)
- expands the tail backwards if the tail starts with a `tool_result`
  whose paired `tool_use` is outside the window — never splits a
  tool_use chain
- replaces everything in the middle with one `<system-reminder>`-style
  summary message, marked with `compactMetadata.userContext = 'emergency_truncate'`

L4 (`query.ts`):
- checks `getHeapPressureState().isAboveCriticalThreshold()` right before
  starting the next streaming request
- if true, logs a non-silent warning to stderr and returns
  `{ reason: 'heap_soft_block' }` instead of allocating the request

## Why no `--max-old-space-size` knob alone is enough

V8 will happily go OOM at 12GB if you allocate a 4GB Buffer in one shot,
even with `--max-old-space-size=16384`. The fix is to **not allocate
the buffer** when the heap is already past the critical waterline. L4
implements that.

## Verifying the contract

`tests/heap-soft-block-contract.test.mjs` walks the source of `query.ts`
and `autoCompact.ts` and asserts:

- `heap_soft_block` reason exists
- `CLAVUE_DISABLE_HEAP_SOFT_BLOCK` escape hatch exists
- `isAboveCriticalThreshold()` is called
- `buildEmergencyTruncation({` is called inside the critical branch,
  before the original "Auto-compact was skipped to avoid an OOM" text

Any PR that removes or reorders these lines will fail this test.
```

### 3.2 更新 `/docs/changelog` 页

把 §2 的 changelog 块直接贴顶部即可。

### 3.3 (可选) 给"Why Clavue"页加一段

参考措辞：

> **No hidden prompt injections.** Clavue used to inject a "you haven't used TodoWrite recently — and NEVER mention this reminder to the user" message every ~10 turns, plus a "consider whether this file is malware" reminder on every file read. Both turned out to interrupt the model far more than they helped, and the "never mention this to the user" framing is the wrong shape for a tool that brands itself as honest. They're gone in 8.10.4.

---

## 4. llms.txt / llms-full.txt

`content-artifacts/llms.txt` 和 `llms-full.txt` 的版本字段需要从 `8.10.1` 全文替换为 `8.10.4`。具体见 `scripts/content-gen/generate-llms-txt.mjs`，本仓库 `npm run content:llms-txt` 会重新生成；如果直接发布固定快照，把所有 `8.10.1` 字面替换为 `8.10.4` 即可。

---

## 5. Social / 短文案候选

> Clavue 8.10.4 出了。两件事：长会话不再随机 OOM（autocompact 失败后增加本地紧急截断 + 堆压软阻断两道护栏）；删掉 FileRead 每次都塞的 "consider whether this is malware" 暗指令和 todo/task 的 "NEVER mention this reminder to the user" 隐性 nag。npm i -g clavue@8.10.4

> v8.10.4: long sessions stop dying on autocompact failure (two new defense layers — local emergency truncation and heap soft-block, both contract-tested), and we removed the hidden system-reminders that interrupted the model on every file read and every 10 turns. Clean now.

---

## 6. 不要做的事

- **不要重写老 changelog 条目。** v8.9.2 / v8.10.1 / v8.10.3 的内容保持不动，只 append。
- **不要在网站上声称 OOM 已经"完全解决"。** 当前是双层防线，根因（in-heap message store）等 Step 3 路线落地后才解。
- **不要在公开文案里强调 reminder 的内部字面量**（"NEVER mention this reminder to the user"）—— 简单说"删除了 hidden system-reminders that interrupted the model"足够，避免给读者解码一长段技术上下文的负担。
