Skip to content

fix(distill): 滤空窗口与「没写 JSON」分开报错,summary 枚举与 VALID 对齐(#502) - #504

Open
modusensus wants to merge 1 commit into
mainfrom
fix/summary-type-enum
Open

modusensus wants to merge 1 commit into
mainfrom
fix/summary-type-enum

Conversation

@modusensus

Copy link
Copy Markdown
Member

Closes #502 · 报告见 #493(2026-10-21 19:12 那条)

一句话

summarize_compress 有两种完全不同的失败,以前共用一句 invalid summary JSON:一种模型在说话,另一种 JSON 合法、条目全被 type 枚举滤掉。后者因此被当成前者反复重放——游标不推进,同一个窗口一遍遍跑。

现场(报告者给的数据,我按代码逐条核过)

18:32:07  summarize_compress  success  in=10745 out=3822   ← 27 小时来首次成功(#493 的围栏生效)
18:35:03  summarize_compress  error    in= 2711 out=2047   invalid summary JSON

失败行的 metadata.raw_has_bracket = true、raw_len 2574/3299,而 raw_head 是:

[ { "id": 1, "type": "环境/版本", "content": "…", "source": "工具结果:版本确认" }, … ]

根因是两套菜单不一致(对照 main 已核):

位置 值
summarize.js 的 VALID 7 个类型
lang.js 的 summary prompt(zh + en) 只列 4 个
lang.js 的 codingSummary 列全 7 个
两个 prompt 里的「只能用这些值 / 不要额外键」 0 命中

喂给模型的菜单和卡内容的闸门对不上,模型按最像中文标签的方式发挥是合理结果。

改了什么(按报告者排的 1 → 3,两条都零行为变更)

  1. 失败形态分开 + 可诊断字段:describeParseFailure 分 no-array / syntax / filtered-empty。第三种的错误消息写成 no valid summary entries (arr=N, valid=0),metadata 补 failure_kind / arr_count / invalid_entries / sample_types(模型实际用的分类词原样带出来——不看这一眼就得去猜它是自造了「环境/版本」还是压根没写格式)。另补 raw_tail(正文 > 500 字时给末 200 字):有些模型先写几条合法条目、再在后面跑偏,前 300 字看不出来。早退那一支(连方括号都没有,[0.9.3] 解析失败后确定性无限重试同一窗口:转录裸放 user 消息会被模型当成「该我回话了」 #493 的 B 臂)以前返回 {ok:false, entries:[]} 什么上下都不带,现在也带 failure——否则下游只能靠「输出里有没有 [」再猜一次,而猜出来的东西不该写进错误消息。
  2. prompt 与闸门对齐:summary 中英两版枚举列全 7 个,并各加一句「只能取上面枚举里的值,不要自造分类;每项只输出上面列出的键,不要附加 id、source 等额外字段」。两种语言一起改——只改一种,另一种语言的窗口照样被滤空,而孪生守卫看不见「两边一起过期」。

没做的一条:type 归一化(中文近义词 → 枚举)。它能把内容救回入库,但会改变入库分类分布;等上面第 1 条产出统计(哪些分类词被反复自造、频率多高)再判断值不值。这也是报告者自己的排序 1 → 3 → 2。

summarizeParseFailureMaxRetries 继续默认关:这两种形态是该被修的,设成 2 会把它们连着窗口一起丢掉——护栏应该在 #502 落地之后再开。

验证

  • 全量 npm test → 2308 tests / 2307 pass / 0 fail / 1 skipped;check-sync ✓ 76 文件
  • 新增 test/summarize-parse-diagnostics.test.js 5 条:filtered-empty 报出 arr/valid 与 sample_types、no-array 仍用原消息且不许编出 arr_count、有合法条目时不产出 failure、raw_tail 只在长正文时给、prompt 中英枚举与约束齐备
  • 升级 1 条既有断言:「全无效摘要仍窗口可重试」那组(3 个子用例)从 error_message === "invalid summary JSON" 改成等于新的精确消息,并加锁 metadata 含 filtered-empty;行为断言一条没放松(状态仍是 error、窗口仍可重试、重试收到逐字节相同的转录)

与 #503 的关系

#503(dream 侧围栏)与本条互不相干:那条改 dream.js / dream/sleep.js,本条改 summarize.js / lang.js 的 summary 段。两条会在 CHANGELOG 的 [Unreleased] 各加一个条目,后合的那条大概率要解一次行级冲突——那是文档拼接,不是代码耦合。

…align the prompt's type list (#502)

The reporter's second shape after #493 unfroze: an audit row with
raw_has_bracket = true and a 2.5-3.3K character body, yet `invalid summary JSON`.
The JSON was fine - every entry had been dropped by the type filter, because the
model invented localised categories ("env/version", "user need") and added id /
source keys. ok:false means the cursor does not advance, so a window that is only
wrong about a label gets replayed forever.

The root cause is two menus that never matched, verified against main: the
filter accepts 7 types, while the plain summary prompt lists 4 in both languages
(only codingSummary had all 7), and neither says "use only these values" or
"no extra keys" - grep for such a constraint across lang.js returns nothing.

Both fixes are behaviour-free, in the reporter's own order (1, then 3):
describeParseFailure classifies no-array / syntax / filtered-empty, the last one
reporting `no valid summary entries (arr=N, valid=0)` with failure_kind,
arr_count, invalid_entries and sample_types in the metadata so the invented
labels are visible without re-reading the raw blob; and the summary prompt gains
the full 7-value list plus an explicit no-invented-categories / no-extra-keys
line in BOTH languages - fixing one leaves the other replaying the same way, and
a twin guard cannot see both halves going stale together. raw_tail is added for
outputs that start valid and drift later.

Type normalisation (synonyms -> enum) is deliberately not done here: it would
rescue content but shifts the stored category distribution, so it waits for the
statistics fix 1 produces. The early return (no bracket at all, #493's arm B) now
carries the same failure descriptor; without it the caller re-guesses the kind
from whether a "[" appeared anywhere, and guesses do not belong in error messages.
Copilot AI lite review requested due to automatic review settings October 21, 2026 21:21

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Copilot was unable to review this pull request because the user who requested the review has reached their quota limit.

An organization owner can choose the repository organization as the billing source for reviews requested by members with a paid Copilot license. Learn about Copilot code review billing.

@coderabbitai

coderabbitai Bot commented Oct 21, 2026

Copy link
Copy Markdown

Warning

Review limit reached

You've used all free OSS reviews for now. Wait for the free limit to reset to keep reviewing this public repository.

Next included review available in 10 minutes.

Check out review usage here.

View limit details

Limit details: You’ve used all 2 included reviews currently available.

Learn how review limits work.

Review configuration:

⚙️ Run configuration
  • Configuration used: Repository: slow-stack/mneme/.coderabbit.yaml
  • Review profile: CHILL
  • Plan: Advanced
  • Run ID: 2de4b8b1-ddab-49c4-b83f-5ddce813ec2b
📥 Commits

Reviewing files that changed from the base of the PR and between cecd2b5 and 9594a31.

📒 Files selected for processing: 7
  • dsh-mneme/CHANGELOG.md
  • dsh-mneme/lib/lang.js
  • dsh-mneme/lib/summarize.js
  • dsh-mneme/src/lang.js
  • dsh-mneme/src/summarize.js
  • dsh-mneme/test/summarize-parse-diagnostics.test.js
  • dsh-mneme/test/summarize.test.js
  • Autofix · Keep fixing CodeRabbit findings and required CI, and resolving merge conflicts

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@codecov

codecov Bot commented Oct 21, 2026

Copy link
Copy Markdown

Codecov Report

✅ All modified and coverable lines are covered by tests.

📢 Thoughts on this report? Let us know!

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.

[蒸馏] type 枚举不对称:prompt 给 4 值、VALID 吃 7 值,滤空窗口被报成「没按格式写」并反复重放(#493 第二形态)

2 participants