Skip to content

feat(item6): transcript 磁盘裁剪 79x + 崩溃安全 checkpoint (CC 2.1.208) - #114

Merged
dahai80 merged 1 commit into
mainfrom
feat/item6-transcript-disk-trim
Aug 21, 2026
Merged

feat(item6): transcript 磁盘裁剪 79x + 崩溃安全 checkpoint (CC 2.1.208)#114
dahai80 merged 1 commit into
mainfrom
feat/item6-transcript-disk-trim

Conversation

@dahai80

@dahai80 dahai80 commented Aug 21, 2026

Copy link
Copy Markdown
Owner

item 6 — transcript 磁盘裁剪 + 崩溃安全 checkpoint (CC 2.1.208, §188/§628)

closes #113

问题 (实读确认)

compact 发生时, 内存里 QueryEngine.splice(0, boundaryIdx) 丢掉 pre-compact 消息 (已正确)。但磁盘从不裁剪:

  • compact_boundary 系统消息带内写盘 (纯追加 appendEntryToFile)
  • 加载时 readTranscriptForLoad 流内截断内存累积, 但磁盘字节永留
  • 注释 "可增到多 GB (inc-3930)"。编辑密集会话同文件反复 Read/Edit → tool_result 巨大 → 79x 放大

方案

compact 收尾阈值触发磁盘 JSONL 裁剪, 保留 [metadata + boundary + post-compact] 段。崩溃安全 — checkpoint 文件记录裁剪点, resume 恢复协议。

三重数据安全:

  1. default offFUSION_TRANSCRIPT_TRIM_THRESHOLD 未设则永不裁 (byte-identical 旧行为)
  2. atomicWriteFile tmp+rename — 崩溃不留半写
  3. preservedSegment boundary 不裁 — 防丢 preserved 消息

文件

文件 改动
src/utils/sessionTranscript.ts (新 ~350 行) 纯函数裁剪逻辑: shouldTrimTranscript (env gate), computeTrimBoundary (单遍扫找最后非-preserved boundary + 收 pre-metadata), performTrim (checkpoint→atomicWriteFile→删 checkpoint), recoverTrimIfNeeded (no-op/幂等删/fail-visible 保留)
src/utils/sessionStorage.ts Project 类方法 trimTranscriptOnDisk/recoverTrimIfNeeded (走 trackWrite 串行, 同 removeMessageByUuid) + standalone 包装 + loadTranscriptFile 恢复钩子
src/services/compact/postCompactCleanup.ts 主线程 compact 收尾 fire-and-forget 触发 (+10/-1 surgical)
src/__tests__/utils/sessionTranscript.test.ts (新) 9 case 真实磁盘 I/O

验证

  • bun run typecheck0 errors
  • bun test src/__tests__/utils/sessionTranscript.test.ts9/9 pass (33 expect)
  • bun test src/__tests__/244 pass, 0 fail (235 现有 + 9 新, 无回归)
  • bun run build:dev + bun run build:dev:fullpass
  • biome: 新文件 0 error; 现有文件 baseline 不变 (0 回归)
  • diff surgical: postCompactCleanup +10/-1 (原 2-space/no-semi 风格保留), sessionStorage +89/-0 (纯插入 tab)
  • live MLX smoke: 二进制启动 + 模块导入安全

关键设计决策

  • logEvent string 类型冲突: LogEventMetadata = { [key: string]: boolean | number | undefined } 不允许 string。错误细节走 logForDebugging (接受 string, 进本地 debug 日志), 遥测只记 boolean { failed: 1 } (避免错误字符串含敏感数据进遥测)。
  • 裁剪点 = 最后非-preserved compact_boundary: 多 compact 累积只保最后段 (中间段已被后续 compact supersede); preservedSegment boundary 保守不裁。
  • 恢复协议 fail-visible (Rule 12): checkpoint + 主文件坏 → 保留 checkpoint 作证, 不自动删主文件 (让用户决定)。
  • trackWrite 串行: 避免与并发 append 竞态 (同 removeMessageByUuid 模式)。

Co-Authored-By: Claude Fable 5 noreply@anthropic.com

问题: compact 内存裁前缀 (QueryEngine.splice) 正确, 但磁盘 .jsonl 纯追加
(appendEntryToFile), pre-compact 段永留盘。编辑密集会话同文件反复 Read/Edit
→ tool_result 巨大 → 79x 放大, 多 GB (inc-3930)。

方案: compact 收尾阈值触发磁盘 JSONL 裁剪, 保留 [metadata + boundary + post-compact]
段。崩溃安全 — checkpoint 文件记录裁剪点, resume 恢复协议。

三重数据安全:
1. default off — FUSION_TRANSCRIPT_TRIM_THRESHOLD 未设则永不裁 (byte-identical)
2. atomicWriteFile tmp+rename — 崩溃不留半写
3. preservedSegment boundary 不裁 — 防丢 preserved 消息

文件:
- src/utils/sessionTranscript.ts (新 ~350 行): 纯函数裁剪逻辑
  shouldTrimTranscript (env gate, default Infinity=off)
  computeTrimBoundary (单遍正向扫找最后非-preserved compact_boundary + 收 pre-metadata)
  performTrim (checkpoint 先写 → atomicWriteFile 换主文件 → 删 checkpoint)
  recoverTrimIfNeeded (checkpoint 不存在=no-op; 主文件OK=幂等删; 主文件坏=fail-visible 保留)
- src/utils/sessionStorage.ts: Project 类方法 trimTranscriptOnDisk/recoverTrimIfNeeded
  (走 trackWrite 串行, 同 removeMessageByUuid 模式) + standalone 包装 + loadTranscriptFile
  恢复钩子。错误细节走 logForDebugging (logEvent LogEventMetadata 不允许 string, 用 boolean)
- src/services/compact/postCompactCleanup.ts: 主线程 compact 收尾 fire-and-forget 触发
- src/__tests__/utils/sessionTranscript.test.ts (新): 9 case 真实磁盘 I/O
  default-off / threshold / 裁剪 / metadata 保留 / preservedSegment / 无 boundary /
  崩溃恢复 (幂等 + fail-visible) / default-off recover

验证: typecheck 0 / 9 新单测 pass / 244 全测 pass 无回归 / build + build:dev:full pass /
lint baseline 不变 (新文件 0 error) / surgical diff (+10/-1 postCompact, +89/-0 sessionStorage)。
live MLX smoke: 二进制启动 + 模块导入安全 (trim 路径 post-compact 触发, 启动不调)。
gateway auth 401 为 pre-existing 传输问题, 非 item 6。

closes #113

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
@dahai80
dahai80 merged commit 1967ed0 into main Aug 21, 2026
1 check passed
@dahai80
dahai80 deleted the feat/item6-transcript-disk-trim branch August 21, 2026 15:06
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

feat(item6): transcript 磁盘裁剪 + 崩溃安全 checkpoint (CC 2.1.208)

1 participant