## 是什么 #493 的**第二种形态**,与围栏无关、也不是解析器太严:社区报告(#493 19:12 追加)给出 0.9.4 生效后 28 分钟的审计——`summarize_compress` 失败行的 `raw_has_bracket = true`、`raw_len` 2574/3299,**JSON 是合法的**,条目却被 `type` 枚举全部滤掉。模型自造了中文分类(`"type": "环境/版本"`、`"用户需求"`)并多给 `id`/`source` 这类键。 于是 `entries.length === 0` 而 `arr.length > 0` → `ok:false` → 记 `invalid summary JSON` → **游标不推进,整窗反复重放**。一个只错在分类词上的窗口,被当成「模型没按格式写」。 ## 根因是两套不一致(对照 `main` 已核) - `src/summarize.js` 的 `VALID` 接受 **7** 个类型; - `src/lang.js` 里普通 `summary` 的中英两版 prompt 只列 **4** 个(`preference|project|decision|history`),`codingSummary` 才列全 7 个; - 两个 prompt 都**没有**一句「只能用这些值 / 不要输出额外键」(grep `只能用这些值|枚举外的值|额外键` = 0 命中),枚举写成裸竖线串。 「喂给模型的菜单」和「卡内容的闸门」不一致,模型按最像中文标签的方式发挥是合理结果。 ## 拟修(按侵入性从小到大,前两条零行为变更) 1. **诊断先行的错误分叉**:`entries.length === 0 && arr.length > 0` 时 `error_message` 写成 `no valid summary entries (arr=N, valid=0)`,`metadata` 补 `invalid_entries`(被滤掉的条数)与 `sample_types`(前 5 个 `type` 原文),另补 `raw_tail`——有些模型先写几条合法条目再跑偏,头 300 字看不出来。 2. **prompt 侧对齐**:`summary` 两版列全 7 个枚举,并写明「不要输出枚举外的值、不要输出 `id`/`source` 等额外键」,与 `codingSummary` 严格程度一致。 3. **`type` 归一化(暂缓)**:中文/近义词 → 枚举,未知落 `project`/`history`。它会把内容救回入库,但**改变入库分类分布**,等 1 的统计出来再判断值不值。 `summarizeParseFailureMaxRetries` 保持默认关是对的:这两种形态是「该被修的」,设成 2 会把它们连着窗口一起丢掉。护栏应在 1/2 落地之后再开。
Activity
Merge pull request #504 from slow-stack/fix/summary-type-enum
fix(distill): tell a filtered-empty window apart from "no JSON", and …
docs(changelog): 补上 #507 / #508 / #513 三条外部 PR 的条目与贡献者小节
strange2000 commentedon Oct 30, 2026
0.9.5 上线 4 小时后的
filtered-empty实测(第 2 步要的统计)环境:
@modusensus/dsh-mneme0.9.5,本机 Windows,2026-10-30 05:57Z 装好;模型workbuddy2api:cn:deepseek-v4.1-flash;数据源llm_audit_logs只读查询。summarize_compress调用failure_kindfiltered-empty×37;另 1 条是传输错误(metadatanull)arr_count累计 394,invalid_entries累计 394,valid = 0raw_has_bracket=falsestreak峰值诊断分叉、
failure_kind、arr_count、invalid_entries、sample_types、raw_head、streak全部按设计工作。这次不用再猜了。sample_types长什么样37 个失败窗口里 18 个带了
type字段,取值去重后 78 种,没有收敛迹象:taskverificationfindingfactactionresultlessonadviceincidentanalysischangeriskissueclosurediagnosticroot_causestate_changeaction_item…根因问题版本状态环境事实事实验收结果配置现状已完成任务经验教训约束规则用户诉求问题现象证据处置故障定位修复路径操作发现验证…这些值看着是「这条内容在说什么」,不是「这条记忆属于哪一类记忆」——模型把语义分类和记忆分类混在一起了。
一个会改变第 2 步结论的点
19/37(51%)的失败窗口根本不带
type键。 它们把整个 schema 换掉了:{ "类别": "变更-插件升级", "要点": "…", "证据": "…" } { "category": "依赖更新", "summary": "…", "details": ["…"] } { "type": "task", "id": "upgrade-plugins", "topic": "…", "status": "done", "changes": ["…"] }第三种有
type,但同样没有title/content。也就是说失败有两类成因:type不在枚举,和键名整体替换(topic/summary/要点/摘要顶掉title+content)。type归一化只覆盖前者,也就是一半。对 78 种类型值做映射表我判断性价比不高:表要么很长,要么大面积落默认值,而默认值会把 decision / pitfall / constraint 这些高价值类型冲淡。
如果要做,我推荐这两个方向
title←title|topic|标题|要点|摘要,content←content|summary|details|正文|内容|证据;type缺失时按关键词猜,猜不到落project。上面三种形态都能收下,信息不丢,代价是字段判定变宽。[{type,title,content,importance}],只输出 JSON 数组」。多一次几百 token 的小调用,把「理解」和「格式化」拆开,服从率通常高得多。两条都不动 prompt 语义,也不影响已合入的 #503。
顺带一句:dream 侧修得很干净,装后 12 次巩固 11 成功(此前 35 连败)。
不用回,数据放这儿备查。
fix(dream): 失败轮不再什么都不留下:原文进 raw_output、skipped 补三布尔、校验判决补回审计行(slow-st…