jianf
160b5b5139
fix(memory-b): 三项验收整改 —— 去写死数字 / F8 硬报错 / blockStates 去 JSON.parse
一、skipped 断言不再写死数字
原 assert.equal(hits.skipped, 2) 属于「手抄数字」——与刚删掉的 README 计数同类:
fixture 一改就悄悄不再描述事实。
改为从构造库现算:expectedSkipped = counts.unknownSpace + counts.spaceMismatch,
并先断言 expectedSkipped > 0(防止变成「0 == 0」的假通过)。
二、F8 从「事后统计」改成「写侧硬报错」
原状:写侧维度校验只降级成「不嵌入」,坏向量仍能落库,靠 blockStates
的 dimensionMismatch 事后兜住 —— 那是 accounting,不是 validation,
与 criteria:165 的「硬报错」不符。
实现:putBlock 新增可选 expectedDimension,声明了宽度且不符 ⇒ 抛错不落库。
commit 在「调用方显式传 vector」时传 expectedDimension。
★ 两个入口必须分清,否则会与 W4 打架:
- 调用方 bug(显式传了宽度不对的向量)⇒ **必须抛**,否则它以
「块在、召回不了」的形式沉默很久
- provider 异常(embedding 返回宽度不对)⇒ 按 W4 降级为不嵌入,块仍写入
(把上游抖动抛给用户 = 让一次 provider 故障变成写入失败)
判据含三例:显式传错宽度抛;显式传对宽度通过;provider 返回错宽度降级不抛。
F8† 变异:把宽度检查改成恒不触发 ⇒ 坏向量落库 ⇒ 判据红。
三、blockStates 不再解析向量(性能账)
实测 2000 块 × 2048 维:
改前 354ms/次(其中 255ms 是纯 JSON.parse)
改后 4ms/次(约 90×)
而 renderIndex 每轮都调它 —— 这是挂在 pre-step 热路径上的固定成本。
做法:memory_blocks 新增 vector_dim 列(维度是行事实,不是负载内容),
- putBlock 写入时一并写
- 迁移时为存量行回填一次(只此一次,不在读路径)
- 加两个触发器保证 vector 与 vector_dim 永不脱节:
★ 理由:既然这一列的存在就是为了「不解析负载」,那每个写入者都背上了
保持一致的义务。漏一个写入者(修复脚本、测试 fixture、未来迁移)
就产生一行「维度是谎话」的数据 —— accounting 报它 active,
而召回静默跳过它。用触发器让这个状态**不可表示**,而不是只劝阻。
- 静态判据:blockStates 函数体内不得出现 JSON.parse(防以后「顺手简化」改回去)
四、embedFailure 记账
不进四态(它是单次调用事件,不是库状态),criteria 已补说明:
四态是库状态、从行派生;embedFailure 属于 recallBlocksHybrid 的 degraded,
由 W 组覆盖。塞进库状态会让「同一时刻读两次得到不同数字」,正是 D4 要避免的。
顺带修:F4† 的变异锚点因 blockStates 改写而失效(withMutatedCopy 显式报
「anchor not found」——这条守卫按设计响亮失败,没有静默变绿)。
验证
- npm test 148/148(143 + F8 四条 + 性能守卫一条)
- npm run check 10/10
- 性能实测见上
- 干净副本实数见后续消息
2026-10-30 16:29:05 +08:00
..
2026-10-30 15:39:03 +08:00
2026-10-30 00:39:44 +08:00
2026-10-30 16:29:05 +08:00
2026-10-30 09:52:06 +08:00
2026-10-30 09:29:37 +08:00