Repository navigation
Releases: DreamRift/dsh-memory-context-lab
Release list
v0.13.1 单引擎收敛:移除 v1、P4 模块拆分、17 处缺陷修复
0.13.1(2026-10-19)
单引擎重构:彻底移除 v1,修复实测缺陷,收敛指令面。
不兼容(升级前必读)
/memory-lab2已删除。 唯一命令是/memory-lab,全部子命令都是顶层的
(card/cost/verify/forget/compress…)。- v1 引擎已移除。 旧会话目录
sessions/<key>/state.json不再被读取,也不会被删除或迁移。
已归档的原文仍留在磁盘上,但插件不再提供恢复入口;确认不需要后可手动删除
$DSH_HOME/.memory-context-lab/sessions/。 - 0.13.0 及更早的批次回执仍可恢复(format 3 渲染路径冻结),但新写入的回执使用 format 8,
其文案与 format 3 不同。降级到 0.13.0 会读不懂 format 8 的行——本版不承诺向后兼容。
新增
help重排为分组帮助:生命周期 / 回读与检索 / 证据与失效 / 主动遗忘 / 层级压缩 /
会话迁移 / 设置与诊断。此前是一张 40 行平铺清单,且混着已删除的import-v1。- 回注的两个补充触发点(F5):同一回合内「重读同一文件」时触发一次;每 15 步兜底一次。
此前自动回注只认新的人类提示——实测会话 1 回合 120 步,回注 0 次。 - 单步内合并多批(F6):同一次自动降温内继续提交,直到没有候选或达单步上限(4 批)。
此前一步只提交一批,实测出现相隔 5 秒的两批,等于刚失效完又失效一次。 status显示单批释放上限:过去是隐藏常量,用户只看到「没按 10 个归档」。
变更
- 单批释放上限改为窗口比例(默认 6.25%)。1M 窗口下等于原值 65,536,行为不变;
小窗口下不再让一批吃掉三分之一上下文。 - 批次回执口径拆开写(F2/F3):
本批 N/阈值 M 个操作(阈值与本批成员)与
本条回执覆盖其中相邻的 K 个(段长)分开;被上限截断时明写
「单批释放上限截断,其余留待下批」。此前只有一个「N 个相邻操作」,
事后审计读不出阈值是否生效。 - 回执回读指路修正(F4):
可回读:memory_lab_recall(record_ids=[…])在前,
命令面:/memory-lab read在后。此前指路已删除的/memory-lab2。 - 删除
engines.json台账:所有权只由engine.json表达。两份真源必然漂移——
实测会话 c1787f24 里 v1 归档借道 v2 存储时写入 engine.json,把从未启用 v2 的会话
判成「v2 持有」,重启后/memory-lab on被 EV2ACTIVE 拒绝。 - 删除预设(presets):全历史模式下「保留最近操作」失效,预设行没有可切换的内容。
index.mjs1897 → 594 行,storage.mjs378 → 171 行;纯渲染器迁至v2/runtime-render.mjs。
修复
- F1 引擎归属误判:见上「删除 engines.json 台账」。
- F2/F3 批次口径混用与短批无解释:见上「批次回执口径拆开写」。
- F4 回执指路失效:见上「回执回读指路修正」。
- F5 单回合长任务永不回注:见上「回注的两个补充触发点」。
- F6 同一步内多批替换放大前缀失效:见上「单步内合并多批」。
- format 8 的恢复路径:分组条件原先只认 format 3,新格式的行会被当成单条回执,
永远对不上摘要正文(实现过程中发现并修复)。
验证
- 97 套件全绿(2026-10-19,Node v24.19.0),0 跳过。
install.test.mjs11 项全部真正执行
(profile 已升级到 0.13.1;此前那 3 项 SKIP 是路径编码缺陷造成的假绿,见「安装面断言长期 SKIP」)。 - 新增 12 个守卫:
v1-residue(基线式残留扫描)·engine-ownership(F1)·
batch-accounting(F2/F3)·receipt-affordance(F4)·v2-recall-trigger(F5)·
runtime-module-budget(单文件 ≤800 行 + 已知债务必须写明理由)·
runtime-domain-wiring(域内「用了没声明」与域间「声明了没传」)·
panel-command-coverage(面板/帮助/输入提示不得指向不存在的子命令或设置键)·
client-dead-entry(删功能后不留死入口:Config 数据面 / i18n 死键 / 重复键 / zh-en 键集相等)·
settings-key-coverage(折叠认得的键必须可写、每个键必须有分支、数字区间与 core 一致)·
doc-command-surface(帮助/README 键位表与SETTING_KEYS集合相等、README 子命令都有 case)·
v2-store-hardening/v2-workingset-hardening/v2-compress-hardening(见「缺陷总排查」)。 - 改回去必红:
batch-accounting、runtime-module-budget、runtime-domain-wiring、
panel-command-coverage、client-dead-entry、settings-key-coverage、doc-command-surface
与三个 hardening 套件各做过一次「临时改坏 → 用例红 → 复原 → 绿」。 - 测试面如实记账:
session.test.mjs37 → 5、reliability.test.mjs29 → 24、
v2-import.test.mjs删除(功能已移除)。这些是「不兼容老版本」的直接代价。
P4 模块拆分
runtime.mjs3588 → 617 行,十个域模块各 ≤700 行:render 110 / fork 110 /
compress 173 / settings 197 / cooling 293 / card 413 / forget 440 / read 521 /
lifecycle 558 / recall 682。- 函数体逐字搬移、语义零改动。拆分本身暴露并修掉 5 个真实 bug:
setSetting的
未定义BT、auditInheritedArchive缺factoryFor/receiptTextOf、retrievalStatusLines
缺semanticBackendStatus/semanticBackendFailure、indexCommand缺三个 semanticBackend*、
recallTriggerOf缺latestReadPathOf。其中 4 个在 89 套件全绿时也不会暴露。 - 装配顺序 forget → lifecycle → card → read → recall → compress → cooling;两处后置绑定
(compressDepsOf/invalidateLedgerForRestore)用惰性取值避免 TDZ。
修复(面板与命令面对齐)
/memory-lab clean confirm delete-session之前不存在:面板「清理」按钮发的是
/memory-lab clean,而命令面没有clean分支——点下去只得到帮助文本,冷库原封不动。
更糟的是off与set fullhistory off在窗口守卫拒绝恢复时,失败提示里写的就是这条
命令,等于把用户指向一条死路。现已实现:须两道确认词、引擎仍启用时拒绝、只删本会话
隔离根(不碰会话日志与命令审计)。set autorestore键缺失:面板「停用时恢复原文」开关一直发这个键,而setSetting的
键位闭集里没有它,点了只回「未知设置键」。已补上(引擎侧disable路径确实读该字段)。- 预设残留两处死入口:预设功能已删(命令面无
preset,Config schema 无presets),但
① 会话面板仍渲染预设下拉框(选一次只得帮助文本);② 设置页仍有「新增预设」编辑器,
点保存会把path: ['presets']写进 Config——schema 里没有该字段,保存必然失败。两处均已
移除;旧日志里的 preset 命令仍会被投影折叠,视图字段保留。 - i18n 清理:删掉 13 个随功能删除而失去引用的键,修掉 2 组重复键
(field.compressModel/field.compressModelHint各重复一次,后者静默覆盖前者),
并把client.js里 12 处裸 CR 换行统一为 CRLF。 - 日志前缀统一:
apply-engine.mjs与runtime-settings.mjs各有一处memory-lab2:前缀,
与其余 40 处memory-context-lab:不一致,已统一。
修复(缺陷总排查:15 处,2026-10-19)
P4 拆分完成后按要求做了一轮完整缺陷排查:三个只读复审并行通读高债模块
(working-state 2183 行 / store 1092 行 / hierarchy-coordinator +
disposition + evidence-atoms 2291 行),各自用临时目录探针实测,再逐条写必红用例
→ 修 → 复原验证。
存储层(store.mjs)
- 带正文却不声明载荷 → TypeError 且烧号:
stageRecord在payload为 undefined 时
解引用.hash,抛的是 TypeError(不是EngineV2Error,调用方按 code 分支全部落空),
事务号与 WAL 意图文件一起残留。改为结构化ESCHEMA拒绝,事务仍可继续用。 - 只校验 hash、不校验 size → 记录永久不可读:把 size 按字符数算(中文 8 字符 /
24 字节)能提交成功,此后每次readRecord都判size-mismatch、正文恒 null,
记录仍在 catalog 里;fork 还会因integrity !== 'ok'直接EFORKINTEGRITY。
现在写入前就比对字节数。 - 并发阶段化拿到同一个稳定 ID:ID 取自
handle.records.length,而载荷落盘是 await 点,
一步里多个并行工具结果同时落库就会双双读到同一长度;后写覆盖先写,catalog 少一条而提交
报告按两条算。改为同一句柄上的串行队列。 - 对账窗口里
peekOpen能拿到半成品句柄:open()先登记再对账,于是 fork 的
acquireShared可能拿到#manifest未赋值的对象(warnings抛 TypeError、
recordCount恒 0)。落在「manifest 已写、catalog 未建完」的窗口时,fork 把父闭包
当空集合迁移 → 子库 0 条而命令报成功(静默丢历史)。改为对账完成后才登记。 offsetBytes在「全文不大于 maxBytes」时被静默忽略:分块读拿到的是从头开始的内容。
分块判据改为fullBytes > start + maxBytes,起点越界返回空段。- WAL 写失败时事务号残留:该号永久留在
#openTransactions(hasOpenTransactions
恒 true、同号重试永远EINVAL),本进程内无法自愈。失败时撤销登记。
工作状态卡(working-state.mjs)
- 否定/撤回被 positive 挤掉:claim 配额按列表顺序截断,而生产路径按 seq 升序(最旧在前),
于是最新的更正永远落选——与「否定/更正可见」的注释承诺相反,模型会按已撤回的结论行动。
改为否定/撤回优先再补 positive。 required: true从不生效:softSectionsOf没把required传到段上,预算装包
又只按分值丢弃。现在随段传递,且预算不足时必选、退让链也只退非必选段。tokens: null印成「取回 ≈0 token」:Number(null) === 0,把未知代价印成免费。- 增量卡截断后变化行永不出现:确认注入会把基线推进到本步全量卡,被省略的行此后不会
出现在任何增量卡里(要等 ≤20 次注入后的周期性全量卡)。现在截断即改发全量卡,
并把「完整内容以最近一张全量卡为准」这句不成立的文案改成「未在本卡列出」。 - 非有限上限把进度夹成 0:
newestTake与take()对同一输入的行为相反
(0 vs 全量),limits.maxProgressItems: undefined时进度整段消失、连「另有 N 条」也不印。
统一为「没设上限 = 不截断」。 - 未曝光结果保留最旧 6 条:与进度列表(P2-5(d))同一类「丢反了」,最新的未曝光结果
只报数量并掉出最小依赖集。改用newestTake。
层级压缩(hierarchy-coordinator.mjs / runtime-compress.mjs)
- 冷节点 id 被当成记录 ID:回执正文只印
mcl2-…,而store.readRecord只认
tXXXXXXXX-rYYYY,传进去直接EINVAL——层级压缩在真实库上从未跑通过
(「读不到就退化用回执文本」那条兜底也走不到,body ?? receiptText兜不住 throw)。
现在用与 read/forget 同一套只读身份索引做别名展开。 - run 审计汇总行
phaseKey: null:账本写入校验要求非空字符串,整批审计条目被
EINVAL拒绝,compressRun又.catch(() => {})吞掉——一批里既有已应用又有被拒/
失败时,被拒与失败行一起消失。 compress status读不存在的ledger.repairNotes:loadHierarchy只给
damageDetail,账本一旦带损坏修复记录,status 直接 TypeError。
设置面
set protect缺失:core.mjs的折叠认这个键、apply-engine每轮读
settings.protectBudgetTokens,但 v2 命令面没有分支——面板/日志显示「预算已改」,
命令只回「未知设置项」,运行时保护预算永远是配置默认值。已补上(0..2,000,000)。- 「未知设置项」提示是手写字符串:删 v1 命令面时漏了
autorestore,用户按提示逐个试
都试不出来。现在由SETTING_KEYS派生。 set batch/retain只挡下界:set batch 100000回「已设置(重启后仍生效)」,
而normalizeSettings对越界值是回落默认(不是夹取)——账本里存的是 10。
现在按NUMERIC_SETTINGS的上界显式拒绝。
文档面
plugin/README.md命令块漏了recall与clean(面板「清理」与off的失败提示
都指向/memory-lab clean confirm delete-session,唯一能救回死路的命令没写进安装文档),
set键位表停在 8 个键(实际 13 个)。- 项目入口与
docs/README.md仍写「合并版 0.12.0、双引擎、/memory-lab2」,已改为单引擎口径;
docs/降温模式.md加版本口径横幅(历史小节保留当时的命令名)。 - 删掉
src/v2/_wiring.txt(P4 拆分时的临时切片产物,会随包发出去)。
新增 5 个守卫(各做过「改回去必红」):v2-store-hardening(6 条)·
v2-workingset-hardening(6 条)· v2-compress-hardening(3 条)·
settings-key-coverage(折叠认得的键必须可写、每个键必须有分支、数字区间与 core 一致)·
doc-command-surface(帮助/README 键位表与 SETTING_KEYS 集合相等、README 子命令都有
case、现行文档不得再教 /memory-lab2)。
安装面断言长期 SKIP(第 17 处,收尾时发现)
test/install.test.mjs 的三条安装面断言自 0.13.0 起一直 SKIP,理由写着「profile 安装的
版本与本仓源码不同(升级前)」。真实原因与版本无关:判断同版的探针用
new URL(import.meta.url).pathname 拼路径——那是百分号编码的,本仓路径含空格
(deepseek Harness)与中文(Harness插件 / 记忆上下文),readFile 必然
ENOENT → 探针恒判「不同版本」→ 三条断言永远不执行。
把路径换成 fileURLToPath 之后它们立刻真正执行,并立刻暴露出两条过期断言:
0.13.0 删 v1 后 agent/pre-step 监听器从 6 个变 4 个、prepend 回注从 2 条变 1 条,
而断言里写的是旧数字。也就是说:这两条断言在 0.13.0 之后一直是假绿。
修法:探针改用 fileURLToPath + 换行归一(profile 副本是 git checkout 的 CRLF,源码是 LF,
直接比字节同样会误判);断言更新为单引擎口径(4 个监听器 / 1 条 prepend);并新增两条守卫——
「探针必须真的读到两个文件」与「test/ 与 src/ 不得用 URL.pathname 拼文件路径」。
改回去验证:把 fileURLToPath 换回 pathname → 立刻回到 3 SKIP(假绿);复原 → 11 项全过、0 跳过。
未完成
- 真实 A/B(同任务开/关插件)与收益量化不在本批。
- 未推送 GitHub、未安装到 profile、未重启 DSH。
安装
plugin_manager add_bundle dsh-memory-context-lab
或使用本 Release 附件 dsh-memory-context-lab-0.13.1.tgz。
不兼容:/memory-lab2 已删除,旧会话目录不再被读取(不删不迁移)。
v0.13.0 — 恢复闭环、压力闸门与补丁重打
0.13.0 — 2026-10-18
这一版先修数据不可恢复,再修降温净亏:前者是「原文一定回得来」这条产品承诺的直接违背,
后者是「低占用时降温省下的是最便宜的缓存读、付出的是最贵的未命中输入」。同一版里做面板瘦身。
恢复闭环(P0,修复前 230 条归档里 221 条不可恢复)
- 归档回执退出折叠:
isCardNode()曾把以[已归档操作·v2]开头的归档回执也判成工作卡。折叠把整组回执换成一条只留seq:的折叠回执,而restoreReceipts()按replacementSeq找节点——找不到就逐条skipped: 回执节点已不在活动面。回执是 restore 的唯一句柄,折掉它等于删掉「原文可恢复」的承诺。现在折叠只治理工作状态卡;归档回执与回注包同为断组边界。 - 第二通道(冷库重建):回执节点已不在活动面时不再直接判不可恢复——按
nodeId读冷库、核对archiveMac(body) === row.hash,通过则在活动面重建原文(rebuilt: true)。hash 不符仍然失败关闭,绝不把来历不明的正文塞回上下文。 - 恢复对账不变量:
restored + skipped + forgotten必须等于输入行数,不等即告警。这是 221/230 事件静默发生的直接原因——没有对账,少恢复的那些既没回来、也没被报出来。
压力闸门(P0,替代「无压力也降温」)
- 新判据
src/v2/pressure.mjs:占用率(assembledTokens / contextWindow)达到阈值才自动降温;0 = 无压力也降温(旧行为,保留为显式选择)。实测会话占用 8.3%–13.5%,默认 20% 下它一次都不会归档——这正是修复。 - 滞回 + 动态死区(智能论 3.4 §2.7.2):进入
enter,退出enter − max(5%, 3σ),σ 取最近 30 次占用率的标准差、上限 20。防的是一次降温后在阈值附近反复抖动。 - 失败关闭:占用率或窗口不可判定时不归档,
status写明pressure-unknown。 - 观测面:
status新增「压力闸门:占用低于进入阈值 / 已回落到退出阈值以下 / 占用率不可判定 / 闸门已关闭」四种如实理由;成本账本新增belowGateCount。修复前这些只能从state.lastMeasurement里翻出来。 - 离线回放:以真实会话 246 步占用序列为夹具,断言闸门 20% 下归档 0 次。
面板瘦身
- 删除四个开关:「保留最近操作」(全历史模式下恒为 0,已是死开关)、「全历史记忆上下文」(唯一模式,不再需要开关)、「自动降温」(由压力闸门取代)、「自动回注」(恒开——它是取回闭环的一部分,不是应被关掉的选项)。
- 新增「压力闸门」一行:开关 + 阈值(1–95)。开关关闭 = 写 0 = 无压力也降温。
- 状态行改写:
降温状态 · 压力闸门(≥N% / 关)· 已归档 · 计划中。
取回通道(P0)
memory_lab_recall在 PTC 形态下可读:run_code里拿到的是原始 value,而ids/query模式此前不填顶层text(只有working-set填),于是模型r.text?.slice(...)得到undefined,判定回读失败并放弃——实测 246 步里唯一一次回读就是这样失败的(冷库其实返回了 779 token)。现在顶层text在所有模式下都是可判定的摘要 + 指针(不复制正文,一次回读只付一遍 token),工具描述同步写明这条读法。
插件消息不再冒充人类(P1)
source.kind改为dsh-memory-context-lab:此前一律写'user',宿主侧所有按kind === 'user'取人类输入的功能都被污染。已取证的消费点:dsh-session-title(实测标题请求的messageSeqs是[31, 155, 157, 159],后三条全是归档回执)、dsh-session-turn-outline(用回执填「本轮提问」)、dsh-session-reference、dsh-web-deepseek-api;聊天 UI 对非'user'的 kind 走role:'inject'分支,比冒充用户气泡诚实。dsh-session的user/message不变量对source.kind无约束(已核对lib/types/invariant.js),日志不会因此打不开。旧日志仍是kind:'user'+form,读取端按form识别,不依赖 kind。
折叠回执(P1)
- 标签如实:归档回执曾被一律标成「回注包」——两者是完全不同的东西(回执是 restore 句柄,回注包是当轮检索证据)。现在按形态显式列出,未知形态写「未知形态」而不是猜。
- 区间有序:成员按活动面顺序排列,
seq可能比左侧更早的节点小,于是出现过seq 243–189/802–770这种倒置区间(实测 4 处)。现在端点取 min/max。 - 最新全量卡永不被折:增量卡的语义是「相对最近一张全量卡的变化」,全量卡是它的基准。实测最新全量卡(seq 2565)被折掉后,后续 5 张增量卡仍在引用一张模型看不见的卡。
验证
- 83 套件全绿(2026-10-18,Node v24.19.0);新增 6 套:恢复完整性、孤儿重建、压力闸门纯函数、压力闸门接线、PTC 回读、source.kind 契约、全量卡保护。
- 改回去必红:恢复闭环与压力闸门各做一次「临时回退修复 → 用例失败 → 恢复修复 → 用例通过」。
- 离线回放夹具:
test/fixtures/replay-c5af11b4.jsonl(1,249 行 / 246 步,只留结构、工具名、字符数,不含工作区正文)。 - 未完成:回执文案里的「相关提问会自动回注要点」未删——
buildBatchReceipt同时用于渲染与 restore 的逐字节比对,改文案必须配合回执格式号升级,纳入下一批;架构分层(kernel/store/host)与 v1 拆除、ReFold 去重/折叠算子、情节日志尚未开工。
0.13.0 补丁重打(2026-10-19)
首发的 0.13.0 在真机上暴露四处界面缺陷(排查报告 v1)。四处都是读路径问题:命令能写进去,界面读不回来。
- 面板「压力闸门」点不动(A2,核心):
viewOf()从未输出pressureGate,而面板用view.pressureGate推pressureOn——视图读到undefined→ 开关永远画成「关」、阈值框永远 disabled、状态行永远「未启用」,而命令其实已经写进会话设置,用户感知就是「点了没反应」。现在视图按0..95收敛后如实输出,越界或非整数回落DEFAULT_SETTINGS.pressureGate(0是合法值,不得回落)。 - 设置页常驻「配置加载中…」(B,核心):宿主用同一个组件渲染两个座位——描述行传
{ view: 'summary' }且刻意不传form,设置区传{ view: 'page', form }。原实现在!snapshot早退分支里把「没有 form」当成「命名空间未服务」,于是详情页常驻一句把视图差异说成宿主故障的文案,而下方设置卡其实工作正常。现在 summary 分支提到快照判断之前,兜底文案改为「设置尚未就绪:宿主未提供本插件的设置表单」。 - 设置页配不到闸门阈值(C):
buildConfigSchema()的defaults块补pressureGate(范围0..95,与NUMERIC_SETTINGS.pressure同域,不进 settingFields——它是阈值不是档位);设置卡的「全局默认设置」补一个数字输入行。连带必改:settingsValueOf()是白名单构造,漏字段会让用户保存其他设置时把闸门整块抹掉,已同步。 - v1 会话点闸门必然失败(D):该行硬编码
/memory-lab2,但闸门是 v1/v2 共用的引擎判据(apply-engine的runAutoCooling),v1 也接受/memory-lab set pressure N。现在命令前缀按会话引擎分流。 - 权威状态记录补
pressureGate(P2):该机制的意义是「命令被拒绝时面板不得显示已生效」,闸门同样受此约束——否则被拒绝的set pressure仍会停在面板上。越界值丢弃(失败关闭),不写进记录。
为什么 83 套没挡住:client.test.mjs 手造了含 pressureGate: 20 的 view,只测「开关 → 命令」映射,从未测「投影 → 视图」这段契约;summary 用例只断言「文本非空」,而误报文案恰好非空。本批新增 test/v2-pressure-view.test.mjs(投影 → 视图契约 4 条),并把 summary 断言改成「必须命中摘要行 + 不得出现任何未就绪兜底」——第一次只写了后半句,把分支关掉后用例仍然绿,是假绿。
验证:84 套全绿(2026-10-19,Node v24.19.0);四处修复各做一次「改回去必红 → 复原必绿」(投影缺字段 4 红、summary 分支关闭 1 红、schema 默认值漂移 1 红、前缀硬编码 1 红)。
v0.12.0 — 投影经济学与归档-重读循环修复(含面板开关同步补丁)
0.12.0 — 2026-10-18
把「归档—重读」自激循环修掉,并把投影经济学补齐:按灵枢统一架构 v1.2 P5-3(率与失真必须同时声明),
让每条回执/工作卡都说清「释放了多少、失真等级、怎么取回、取回多少钱」,并让最便宜的取回动作成为默认动作。
事实前提:memory_lab_recall 在真实会话 303 步里被调用 0 次(read 182 / pwsh 109 / grep 80),而同键重读 55 次。
已发布到 GitHub:tag v0.12.0(提交 d0329d5)与 Release 附件 dsh-memory-context-lab-0.12.0.tgz(139 文件 / 784.2 kB / sha256 b74a1b23…1b23,远端 digest 一致)已按补丁后的包重打覆盖(见下「面板开关同步」)。安装状态以 DSH 为准,本包不代为安装或重启。
折叠语义(P0-6,硬前置)
- 回注包不再被卡片折叠吞掉:
card-fold.mjs曾把recall算作卡形态,同一步的回注包(prepend)与工作卡(append)两条相邻user/message正好满足minRun=2,下一次归档就被折成一条回执——刚读回的证据从投影消失,模型只能再读一次。现在recall移出CARD_FOLD_FORMS并登记为CARD_FOLD_EXCLUDED_FORMS,是断组边界;人类/assistant/tool-result 仍是硬边界。 - 折叠计划改用活动面顺序(不再按 seq 排序):replace 事件拿到的 seq 比它左边仍在面上的节点大,按 seq 排序会把折叠回执挪到被保留的卡后面,于是下一轮把断组边界读成卡、把卡读成边界(每轮注 2 张卡时卡数不收敛)。
投影头与回读可用性(P0-5 / P0-1)
- 投影头:每条回执/卡片加一行
投影:A 类(可完整重建)|释放 ≈N token / M 字|取回 ≈K token。失真只有 A 类(原文在冷库、可逐字节重建);构造 B 类直接抛错。投影头 ≤1 行 / ≤120 字符,超限先丢取回段再丢字数列。取回代价取冷库载荷既有 token 估算,不新增计算。 - 新格式占新号:操作回执
format 6、片段回执format 7;旧格式 1/2/4/5 的渲染逐字节不变(恢复依赖逐字节相等,这是 format 4 引入时的教训)。 - 可回读动作行:
记录 ID:按 … 别名回读→可回读:memory_lab_recall(record_ids=["mcl2-…"])|A 类可完整重建,命令面降到第二行命令面:/memory-lab2 read …。新格式不再重复那句「相关提问会自动回注要点」(真实会话里一次都没兑现)。 - 工作卡「本步可回读」:最多 3 条,每条 = 记录 ID + 工具/范围/对象 + 取回代价;只描述结构、不复述正文(复述正文等于撤销归档);单行 ≤80 字符,超出的只报计数。
- 成本账本拆三路:
toolRecallReads/commandRecallReads/fileReReads(+fileReReadChars),互不覆盖;修复前只有一个evidenceReReads,把「按 ID 回读」与「重读文件」混在一起,于是插件以为自己「回读 0 次」。
读取账本与读取租约(P0-2 / P0-3)
read-ledger.json:会话隔离根新增账本,键<path>|<offset>,记seq/coldRecordId/hash/chars/firstSeenAt/reads/unchangedReads/lastReadStep。归档含读取类结果的操作时登记;不拦截、不改写工具行为;restore后失效、重启不清零、单会话上限 4,000 条按lastReadStep淘汰。- 失败关闭:账本不可读、不是合法 JSON、schema 不符,或部分条目不可解析,一律
ok:false且不写盘——不静默重建为空。 status重复读取两行:口径 A(重读字符/全部内容字符)与口径 B(内容完全未变的重读)分开报,标「本账本口径」,不把看不见的历史算成 0。retainReads(默认 3,TTL=2N):全历史模式下retainOperations仍为 0(设计不变),最近 N 个含读取结果的操作强制保留,M 步后租约到期并标readLeaseExpired(转「需复核」)。这是降权轴,不是保护集扩张——v1.2 §8.3 的受保护集无界增长是未解问题。retainReads: 0完全退回旧行为;写类操作不受影响。
卡片净占用上界与降噪(P0-4 / P1-6)
CARD_NET_CHAR_CAP = 4000(字符,不是条数):MIN_OPERATION_CHARS = 1200对 span 同样生效,短卡永远进不了候选,所以按字符算。超上限时折叠同一段连续卡组(哪怕只有 2 张),不放宽minRun(放宽会跨非卡节点吞掉助手消息)。- 最新一张工作卡永远保护:它是模型当前能看到的状态面;折叠回执保留全部成员
seq:(替换不是删除);上界到了却折不动时如实告警并计cardCapUnreached。 - 降噪:丢弃页脚只报「类别 × 段/行数」,删掉逐条重要度打分算式;软段头不再重复整条类目次序;增量卡硬上限 24 行 / 1600 字符,超出只留「变化摘要 + 记录 ID」。
其它修复
onEnabled失败语义(P1-1):index.mjs注入的是同步对象,旧写法onEnabled?.(agent)?.catch(...)在同步返回值上访问.catch是undefined→ TypeError,且发生在enable()尾部、状态已落盘之后且不在 try 内:命令显示失败,引擎其实已启用。现在同步/异步都接,抛错(含异步 rejection)一律降级为提示「计划先行未生效」。- 任务锚(P1-2):
isReceiptMessage改由单一常量表SURFACE_INJECTION_MARKERS判定(v1/v2 回执、折叠回执、聚合凭证);无source.form的旧折叠回执不再被当成人类请求。 - 回注信息量门槛(P1-3):命中项必须有结构事实(范围/工具/片段种类)才注入;纯壳不注入,也不产生空块。
- 卡片角色一致性(P1-4):硬保护项带
role/kind;同一 seq 出现在两类硬保护时降级「角色未确认」并告警。不引入req:/evt:双命名空间(同号在本会话未复现)。 - 回执 status(P1-5):工具结果回执加
status=ok|fail|partial,失败附首错行(≤200 字符,不改写原文);非工具结果标kind=message。 - 检索口径文案(P1-7):工具描述与告警不再说「不含正文词」,如实写「覆盖记录 ID/kind/工具名/callId/范围,以及每条记录 ≤8 KiB 的正文词元(含中文二元组)」;描述与
INDEX_TEXT_MAX_BYTES引用同一常量。
面板开关同步(0.12.0 补丁,2026-10-18 重打)
首发 0.12.0 漏了两处未提交的修复,真实新会话里表现为「开关闪一下又关掉、之后点不动」:
- 权威状态记录读错账本:
recordAuthoritativeState只读 v1 的records,v2 会话永远读到空账本,于是每条状态类命令后写出的plugin:dsh-memory-context-lab/state都是空账本默认值。现在按引擎归属取对应账本(v2 读v2.records)。 - 缺席的开关位被按默认 false 补齐:v2 账本没有
planFirst、v1 账本没有fullHistory,旧实现一律补false,于是每写一条权威记录就把刚折叠出来的开关压回关。现在账本没有的位不表态(投影保留日志折叠值),而v2 专属位在 v2 不持有时写 false——否则面板会停在「降温已停用、全历史仍显示开」,再点只得到「v2 引擎未启用」,看起来就是关不掉。 shareL2Content补进权威字段表(原实现折叠时被静默丢弃)。/memory-lab set planfirst支持 v2 会话:旧实现只看 v1 账本,v2 会话里既不落账、还误报「本会话尚未启用降温」。- 回归:新增
test/v2-authoritative-ledger.test.mjs(4 项,走插件真实入口 apply → 命令 → 投影重放),覆盖「开 → 关 → 再点启用降温不回退」完整往返。
测试与验证
- 76 套 / 790 项断言全绿(Node v24.19.0),新增 14 套;
entry-coverage保证入口 == 磁盘。 - 6 个 P0 各做一次变异必红(改回去 → 对应新套件红 → 复原 → 绿):P0-6a / P0-5a / P0-1a / P0-2a / P0-3b / P0-4c。
- 蜂巢:确定性全量(job
…_0006、回修后…_0007)与只读独立复审(job…_0003,verdict REJECT → 2 条 finding 已回修并加回归)。 - 探针:
probe:revert28/28、probe:lingshuexit 0、probe:hostSKIP(未提供--asar)。 - 面板开关补丁(同日重打):
v2-authoritative-ledger4 项全绿;源码线test:all与release/镜像各自 76 套 / 790 项全绿。
兼容性
- 不新增/不删除模型可见工具(工具集逐字节不变,前缀缓存纪律)。
- 旧格式回执与旧日志:format 1/2/4/5 渲染不变,旧折叠回执按标记识别;
read-ledger.json缺失时按空账本处理。 - 不阻止重读、不自动回注正文、不恢复 v1 保留数、不扩保护集、不做 B 类有损投影、不放宽折叠阈值、不改
MIN_OPERATION_CHARS。
安装:下载 dsh-memory-context-lab-0.12.0.tgz,执行 dsh plugin add <tgz 绝对路径>,随后重启 DSH Desktop。
0.11.0(会话日志完整性、卡片默认脱敏与成员级排除)
会话日志完整性与披露边界版:修掉两个「写坏会话日志」的 P0 与一个「命令被拒绝但面板照样翻开关」的投影不一致,完成卡片默认脱敏、压缩成员级排除、弱候选置信度统一。
修复(P0)
- 替换节点缺
data.source(持久性损坏):session.append(type, data, opts)的opts只认surfaceOp/sourceEventSeqs,其余键静默丢弃。插件把source写进opts,落盘的user/message就没有source,宿主投影无保护地读event.data.source.kind抛TypeError,整条历史从此打不开(SESSION_QUERY_CORRUPT_SESSION),重启无效。已复发两次。现在折叠回执与凭证的source一律写在data里并补id/role;测试替身FakeSession.append同步收紧成与真实宿主同语义。 compaction/prune.shadowedSeqs与活动面不符:提交点用run.flatMap(unit => unit.shadowedSeqs)拼名单,区间里若夹着插件自己的回执(seq 数值比区间末尾大、位置却落在区间内),它不会进名单 → prune 落盘即非法 → 下次冷加载报SessionFormatError,紧随的 replace 也被宿主拒(sourceEventSeqs must include every shadowed surface node; missing <seq>),该区间永远归档不掉。现在提交点按活动面位置切片取名单(两端必须在面上、顺序正确、逐项相等,否则失败关闭不写 prune);shadowedTokenCount与名单同源,对账差额归零,容差未放宽。- 命令被拒绝,面板却显示已生效:宿主把每次斜杠命令都记成
command/run,投影只能按命令行折叠,看不出这次调用成没成——「关闭降温」被维护窗口拒绝(返回红字、持久状态一个字节没动)时面板照样翻成已关闭。现在每条状态类命令结束后(成功或失败都写)追加一条权威状态记录plugin:dsh-memory-context-lab/state,值取自当时的真实记录/引擎状态;投影折叠到它时直接覆盖开关位,重放(resume/fork)同样生效。宿主拿不到appendPluginRecord时如实降级并在回执里说明,绝不假装写过。
隐私与披露
- L1/L2 卡片默认不复制正文:摘录、跨度摘录、结论行这类自由文本原子的值默认渲染成固定标记
(正文摘录未共享),只保留 entity、属性标签、极性/关系标签、来源 ID 与expand入口;结构化属性(exit 1、465 项全绿、版本号、错误签名、时间)照常保留——脱敏删的是正文副本,不是证据。 - 新开关
shareL2Content(默认false,失败关闭):/memory-lab2 set sharel2content on|off,设置页「全局默认」增复选项,面板在engine === 'v2' && compressOn时显示开关。显式开启才在卡里放正文摘录。 - 开关覆盖全链路:程序卡渲染、L1/L2 卡、模型相位的输入行(建块时就脱敏,保证模型消息、预算计量、
blocksHash与最终卡同源)、崩溃重放的 L1 占位都受同一开关约束;两种模式各自逐字节稳定,卡里带一行恒定模式说明。
层级压缩
- 成员级排除:此前任一成员被遗忘即整组
member-forgottenblocked,同组其余成员永远压不掉。现在只把被遗忘成员排除出参与集:不读其正文、不进 L1/L2/sourceRecordIds/leafIds,其余成员照常蒸馏;全部成员被排除时仍整组失败关闭(没有安全子集)。 - 计划 schema 2:
recordIds语义收紧为「参与蒸馏的子集」,新增excludedRecordIds/excludedMembers({recordId, seq, reason})/memberDigest(sha256 前 12 位);memberSeqs/memberTexts仍是表面全集,区间身份与voucherId因此不变。v1 计划(无planSchema)保持整条作废语义。 - 披露有边界:凭证文本与 L2 卡头只在真的排除了成员时追加一行;无排除时输出与 0.10.x 逐字节一致。
检索
- 统一 exact 后验:抽成纯函数
exactPostfilterHit+ 共用驱动applyExactPostfilter,检索通道与弱候选诊断走同一份判定(此前各写一份,口径会漂移)。 - 弱指针带可机读置信度:
weakPointer: true、isHit: false、confidence: { kind: 'weak', score, coverage, exactVerified };不通过 exact 后验的弱候选如实丢弃(「弱」不是免责条款)。回注文案改为「弱指针(不是命中),只给 ID,不计入回读计数」。
测试
- 全量 62 套 / 717 项断言 0 失败、0 跳过(Node v24.19.0,2026-10-18)。新增 3 套:
v2-surface-source(8)、v2-share-l2-content(8)、v2-weak-pointer(5);v2-forget-hierarchy改写为成员级排除契约(6 项)。 npm run probe:revert:28 个场景全部OK(还原后测试失败),未覆盖 0 个(0.11.0 新增 6 个)。- 真实灵枢集成 3/3 真实通过(不再 skip);
npm run probe:lingshuexit 0。
安装
dsh plugin add dsh-memory-context-lab-0.11.0.tgz从下方 Assets 下载 dsh-memory-context-lab-0.11.0.tgz。本版未改动 v1 命令面;plugin-v1(0.6.2)是冻结线,不随本版升号。
0.10.1(回读闭环、卡治理与 16 项复核修复)
回读闭环与卡片治理版:别名回读、检索契约修复、工作卡有界治理、助手结论盘点;并完成外部取证复核发现的 16 项缺陷修复。
新增
- 别名回读(v2):
read/memory_lab_recall接受三种 ID 形态——精确记录 ID 直通;冷节点基名展开为整单元(分块按序拼接);callId 解析配对记录与依赖 span。别名展开有上限,未解析 ID 返回显式 error 行(不再伪装空成功)。回执格式升 format 4:新增「记录 ID」行;旧格式回执 restore-only 兼容(显式 dispatch,升版不吞旧行)。 - 弱候选导航:查询零命中但与冷记录有词元重合时,回注给 ≤3 条 pointerOnly 弱指针(只给 ID 与重合说明,不注入正文,不计入有效回读次数);T1 检索面同步披露 queryDetailed 诊断(admitted/weak/oovTerms)。
- 工作卡有界治理(v2):注入生命周期改 prepare→确认→commit 三态,成本账本新增 prepared/committed/sent 三计数器(未确认注入如实留残差);活动面上连续的插件工作卡组(≥2 张)自动折叠为一条恒定回执(附成员范围与数量;绝不触碰用户/助手/工具消息);锚点被宿主压缩移除时下一张状态卡自动回落全量(不虚构增量连续性)。
- 助手结论盘点(v2 工作状态卡):新增「助手结论」段,确定性提取最近的助手结论行(保留原句与来源),恒标注 unverified——这是「此前助手判断」,不是事实;否定/撤回结论优先保留(可见性不靠关键词升级);有界配额(8 条,超出只报数量)。
修复
- 检索契约(v2):引号短语按连续顺序验证(换序/散落不再命中);字面检索多精确词按 AND;语料外词元(OOV)不再稀释相关度分母;回注命中保持最相关在前;弱候选不计入 readCount/retrievalHits。
- 0.10.0 遗留:层级压缩模型相位 over-budget 短路失效、P4 接线字段失配(模型摘要模式从未生效)、modelNote 作用域错误——三处修复后模型相位测试 3 项转绿。
修复(复核批次:BUG-001…016)
- 普通历史段归档可恢复(BUG-001):非工具跨度归档行改用专用回执格式 5 并记录
spanLabel;恢复侧按行内版本用buildSpanReceipt逐字节重建。旧 format 4 span 行没有可重建标签时如实 skip 并指路/memory-lab2 read <nodeId>,不猜测覆写。 - 人类消息硬保护(BUG-002):
forget宽条件同时拦截 verbatimturn.user记录与projection.span(turn.user);显式点名仍允许但带警告。修复前kind=turn.user可软遗忘全部人类消息。 - 停用路径(BUG-003):measure 抛错时
off与set fullhistory off不再因未定义ctx抛 ReferenceError;恢复照常尝试、停用状态照常落盘并留告警。 - 自动层级压缩收尾(BUG-004):补上
maybeStageCompress导入,钩子可注入观测,失败日志保留错误类型。 - 未启用会话 forget(BUG-005):
preview/apply返回ENOTENABLED结构化错误;undo可完成账本级撤销,无活动面时如实说明。 - expand 分页(BUG-006):第 2 页起按全量成员数组偏移取原文,遗忘占位不再错位。
- L1 证据卡(BUG-007):按成员事实原子渲染,不再用不带来源的渲染块反查导致空卡。
- compressModelDefault(BUG-008):经
defaults解包读取,设置页开关能真正播种新账本。 - 投影折叠 context(BUG-009):每次折叠解包
getPresets()/getDefaults(),resume/fork 与命令执行一致。 - 批摘要残余成员(BUG-010):不再用
buildReceipt(formatVersion=3)抛错中止 restore;表面仍是该组摘要或已被 forget 换成该组墓碑时,只恢复可见成员原文,已遗忘成员绝不复活,其余 fail-closed。 - 测试摘要(BUG-011):同行 passed+failed 聚合;
failed>0必报失败,未说明项不再判全绿。 - 未验载荷(BUG-012):
readRecord增加verified维度;工作集扫描路径标ok(unverified)且verified:false。 - 损坏账本(BUG-013):hierarchy/disposition 首行损坏优先
damaged,空文件/ENOENT 仍absent。 - 旁证损坏(BUG-014):重建时写
frozenBefore冻结重采,归档后改动的文件不得洗成valid。 - recall 别名(BUG-015):预算判定不双扣;别名中断时游标指向未处理前缀,续读不漏不重。
- T2 幂等重写(BUG-016):
committed:false回读核对content,内容一致走重试成功,不再误报冲突。
测试
- 全量 57 套 / 664 项断言 0 失败(Node v24.19.0,2026-10-17);新增 3 套 fix-brief 回归 18 项,回退对应修复即变红。
npm run probe:revert:20 个回退场景全部“还原后测试失败”;修复探针在 Windows CRLF 下多行还原点失配与缺--test-force-exit的挂起问题。- 8 个变异验证(必红→复原)全部通过;独立复审(蜂巢验证单元,与作者不同会话)两批均 accept。
完整对比:v0.9.1...v0.10.1
0.9.1(修复 0.9.0 加载失败缺陷)
紧急修复版:0.9.0 正式版有一处读取错误会让整个插件加载失败(插件页显示「异常」),本版修正并补上回归防线。行为与 0.9.0 宣称的能力完全一致,无新增特性。
修复
- 插件加载失败(0.9.0 正式版引入):装配期读取检索后端配置时写成了
ctx.config?.defaults。config是apply(ctx, config)的第二参数,不是 context 属性;宿主 cordis 的 context 代理对未注入属性是抛错而非返回undefined(cannot get property "config" without inject),?.拦不住抛错。该行一执行即抛出并冒泡出apply,插件加载被回滚——两个命令、投影与只读召回工具全部消失。- 影响面:0.9.0 正式版(
82e751b引入)。0.9.0-rc.6 及更早版本不含该行,不受影响。 - 触发条件:必然触发,与配置内容、是否装
dsh-memory无关。 - 修复:改读
config?.defaults,与同文件既有读取口径一致。
- 影响面:0.9.0 正式版(
测试
test/install.test.mjs新增回归防线:替身把config建模为「读取即抛」(与既有tools替身同形),并新增静态+动态断言。该防线对 0.9.0 坏副本会如实报错(实测指向src/index.mjs:418),修复后通过。- 全量
npm test:32 个测试文件全绿、0 失败 / 0 跳过(Node v24.19.0,exit=0);0.9.1 tgz 装入 desktop profile 后 9 项安装测试全通过。
完整对比:v0.9.0...v0.9.1
0.9.0(首个正式版)
新增(PR #4 整合)
- 验证跟踪:归档后对记录引用的文件采集 sha256 指纹(旁证
verification.json,原子写、差集增量,不改不可变记录)。/memory-lab2 verify <ID…>三态裁决(valid / stale / unverified),mark-stale <ID> <原因>人工标记;read/recall与memory_lab_recall回读时附失效注记。旁证损坏失败关闭,绝不伪造 valid。错误码EVERIFICATIONSTALE。 - 检索后端显式指定(
retrievalBackend配置):auto(默认,行为不变)/local-lexical-v1/lingshu-mdcg-receipt。显式 lingshu 不可用时拒绝启用(EBACKENDUNAVAILABLE)、握手失败报EBACKENDPINGFAIL,不静默降级。 - lingshu-backend 动态加载:主装配路径与 T2 实现解耦,加载失败走既有失败关闭路径。
- 设计文档:
docs/architecture-design.md与docs/interface-design.md(PR #4 原文 + 0.9.0 状态注记)。
未实施(0.10.0 候选)
归并固化(层级压缩)与主动遗忘(精确遗忘)登记为 0.10.0 候选,前置设计(摘要主体、墓碑机制)待定。
验证
31 套测试 417 项全部通过、0 失败 0 跳过(plugin / release / 安装副本三处一致)。包内含 docs/ 与 CHANGELOG。
0.9.0-rc.6
本版合入社区 PR #3(独立运行——本地冷库客户端与本地词法检索后端),并补上合并复核发现的两处缺口(D1/D2)。
新增
- 独立模式:不再要求安装
dsh-memory。冷库、冷写、字面检索由本地实现承担,新增本地词法检索后端(纯 Node:CJK 二元组 + ASCII 词元倒排,无外部进程;词条上限 20 万、超限如实标注覆盖边界)。装了dsh-memory时灵枢后端(T2)照常优先,且要求 mcp_server 完成握手才启用。 - 启用注记对齐实际能力:未装
dsh-memory时启用文案改为「以独立模式运行」,不再宣称「归档与回注会失败关闭」(本地冷库可用后那是假话)。
修复(合并复核)
- 状态面虚报生效检索后端(D1):复合检索后端的
describe此前按「灵枢 root 在场」即报灵枢为生效后端,但灵枢未为任何会话启动时实际生效的是本地词法后端。现在顶层 name/capabilities 按「灵枢已启动会话 > 0」取值,未启动期如实报本地后端(defaultBackend字段恒报本地后端名)。 - 旧 v1 冷库升级后静默读不回(D2):升级前经灵枢子进程归档的 v1 冷库(
sessions/<键>/mdcg/,灵枢 contextual 节点格式)无法由本地冷库客户端读取;若该会话仍有待恢复或已跳过的回执,on/status/restore现在会附注「旧回执原文已读不回、数据仍在磁盘不会被删除、回收磁盘走clean confirm delete-session」,不再让用户在不知情下以为旧回执仍可恢复。
变更
@furongjun1999/dsh-memory从必需 peer 降为可选 peer,并加显式版本上界。off文案自洽:冷节点缺失导致未能恢复的回执,随冷库回收时改述为「已随冷库一并清除」,不再与「仍依赖冷库」同段出现。⚠️ 升级注意(v1 会话):升级前若已有经灵枢子进程归档的 v1 冷库,其原文载荷在灵枢格式内。升级后建议先/memory-lab off恢复原文,或保持dsh-memory安装(T2 路径照常可读)。
文档
- 据实测会话取证补两条说明:README 解释回执「批次归档:N 个相邻操作」的 N 为何可小于批量阈值(受保护/不够格/冷写失败的单元把连续段切断,非漏归档);用户观察到的「长时间不动」经日志取证为供应商 API 空响应/流空闲超时(300 s)重试所致,非插件卡死,未作代码变更。
测试
- 新增
test/v2-local-lexical.test.mjs(本地词法后端:词条化、AND 语义、持久化、增量幂等、词条上限如实报、崩溃重建)与test/v2-local-client.test.mjs(本地冷库客户端)。 - D1/D2 各补守卫断言:未启动灵枢时复合
describe报本地后端(test/v2-retrieval-provider.test.mjs,含 backendFor 兜底与 close 语义);旧 mdcg 冷库在场时status/on/restore附注升级出路(test/session.test.mjs)。 - 0.9.0-rc.6 全量:29 套、407 项断言(402 通过 / 5 环境性跳过——lingshu 可选化后的真实集成项,受限会话如实 SKIP),失败 0(2026-10-15,Node v24.19.0)。
0.9.0-rc.5
修复(用户上报三缺陷 + 关闭链路冲突矩阵)
- 计划先行关闭联动退出:
set planfirst off把本会话仍处 active/pending 的计划模式一并退出(planMode.set(agent,false),服务缺失回退plan/mode {active:false}落账;读不到状态如实降级提示手动/plan off)。该退出不触发「批准计划后自动启用降温」钩子(有测试锁定)。 /memory-lab off按引擎持有者转交:v1 记录缺失且 v2 持有投影(engine.json 激活)时,转交 v2 停用路径(先恢复原文、再停用)。修复「面板关『启用降温』后 v2 引擎照常运行、投影折叠成已关」的失同步(开关已关引擎还在跑)。- 关全历史先恢复原文再翻位:
/memory-lab2 set fullhistory off在翻开关位之前先走 v2 恢复管线(输出报告「已恢复 N/M 段原文」),恢复失败不阻断关闭、逐条如实报告。 - v2 停用恢复补窗口守卫:与 v1
normalizeAndStop同口径——恢复会让组装输入超出模型窗口时跳过恢复、照常停用、原文留冷库可按 ID 回读并给出路(clean confirm delete-session或先缩上下文);「无测量不设闸」与 v1 一致。 - 面板改版:开关行不再渲染状态文字(长状态曾把标签挤成竖排);降温状态、全历史、计划先行三行摘要与最近一次命令输出同显于弹层底部输出框;
.mcl-label强制 nowrap+ellipsis 防竖排。
测试
- 全套 28 文件双副本(plugin/release)全绿:393 pass / 7 skip / 0 fail。
- 新增守卫:planfirst 退出五分支(回退自证红→绿)、off 转交、fullhistory off 先恢复(真实归档→恢复→翻位)、恢复窗口守卫、面板无
mcl-status+底部框摘要。
v0.9.0-rc.4
本版修复 5 条用户上报的遗留缺陷(B1–B5,含 issue #2 的删除安全问题),并落地灵枢重要度驱动的软保留装包(F1):软保留从「按类目一刀切丢弃」改为「按确定性重要度分值排序丢弃(低分先丢)」,分量逐项可解释。收益口径是「丢得准」,不宣称提升容量节省。
修复
- 「全历史记忆上下文」开关关不掉(B1,用户上报):面板 off 路径无条件发
set fullhistory off(v2 未启用时返回「未启用」属可接受空操作);memory-lab2 off的投影折叠同时清掉fullHistory残留位。 - 面板「恢复原文」对 v2 会话误报「未启用」(B2):面板维护动作按当前引擎分流;v2 新增
restore子命令(恢复全部可恢复回执,不停用引擎);v1 的restore/now/dry-run在 v2 持有投影时指路 v2 入口。 /memory-lab off的删除条件不安全(B3,issue #2,P0):restore 失败行(restore-skipped)的原文仍只在冷库;删除判定(off 的 purge、遗留目录回收、clean 确认门禁)统一计入冷依赖,原文仍在冷库时不删库,矛盾文案与clean confirm delete-session指路一并理顺。- 测试环境显式化(B4/B5,issue #2):三条依赖「peer 恰好不在场」的用例改为显式屏蔽或分轨断言;peer 在场时测试进程不退出的成因定位为真实冷库 Python 子进程,
npm test逐条加--test-force-exit兜底。两种环境全套均绿。
新功能
- 软保留按灵枢重要度分值装包(F1,卡片语义版本 v4):确定性白箱评分器(纯函数、零第三方依赖)——
分值 = 0.5·相关性 + 0.3·来源 + 0.1·证据 + 0.1·回读。相关性是与当前人类请求的 bigram 覆盖率(反向校准:与当前任务重合的历史不评低分);装包按分值降序(低分先丢),每段带分量描述,硬保护不参与打分、不被低分丢弃。 - 已知边界:回读次数分量接口就位,当前索引无每记录回读计数,暂如实按 0 计。
测试
- 新增
test/v2-importance.test.mjs(9 项)并入npm test;B1–B4 新增 11 条用例,B2/B3 各做回退自证。 - 全套 27 个测试文件、379 项断言通过(跳过 2 项为既有集成 skip),peer 在场/不在场两种环境均正常退出。
安装方式见 README;peer 依赖 @furongjun1999/dsh-memory@0.8.1。