Skip to content

Releases: DreamRift/dsh-memory-context-lab

v0.13.1 单引擎收敛:移除 v1、P4 模块拆分、17 处缺陷修复

Choose a tag to compare

@DreamRift DreamRift released this 19 Oct 15:03

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.mjs 1897 → 594 行,storage.mjs 378 → 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.mjs 11 项全部真正执行
    (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.mjs 37 → 5、reliability.test.mjs 29 → 24、
    v2-import.test.mjs 删除(功能已移除)。这些是「不兼容老版本」的直接代价。

P4 模块拆分

  • runtime.mjs 3588 → 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 — 恢复闭环、压力闸门与补丁重打

Choose a tag to compare

@DreamRift DreamRift released this 19 Oct 01:52

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 — 投影经济学与归档-重读循环修复(含面板开关同步补丁)

Choose a tag to compare

@DreamRift DreamRift released this 18 Oct 08:12

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:revert 28/28、probe:lingshu exit 0、probe:host SKIP(未提供 --asar)。
  • 面板开关补丁(同日重打):v2-authoritative-ledger 4 项全绿;源码线 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(会话日志完整性、卡片默认脱敏与成员级排除)

Choose a tag to compare

@DreamRift DreamRift released this 18 Oct 04:40

会话日志完整性与披露边界版:修掉两个「写坏会话日志」的 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-forgotten blocked,同组其余成员永远压不掉。现在只把被遗忘成员排除出参与集:不读其正文、不进 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:lingshu exit 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 项复核修复)

Choose a tag to compare

@DreamRift DreamRift released this 17 Oct 06:57

回读闭环与卡片治理版:别名回读、检索契约修复、工作卡有界治理、助手结论盘点;并完成外部取证复核发现的 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 宽条件同时拦截 verbatim turn.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 加载失败缺陷)

Choose a tag to compare

@DreamRift DreamRift released this 15 Oct 15:26

紧急修复版: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,与同文件既有读取口径一致。

测试

  • 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(首个正式版)

Choose a tag to compare

@DreamRift DreamRift released this 15 Oct 14:23

新增(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

0.9.0-rc.6 Pre-release
Pre-release

Choose a tag to compare

@DreamRift DreamRift released this 15 Oct 10:58

本版合入社区 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

0.9.0-rc.5 Pre-release
Pre-release

Choose a tag to compare

@DreamRift DreamRift released this 15 Oct 08:33

修复(用户上报三缺陷 + 关闭链路冲突矩阵)

  • 计划先行关闭联动退出: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

v0.9.0-rc.4 Pre-release
Pre-release

Choose a tag to compare

@DreamRift DreamRift released this 15 Oct 05:29

本版修复 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。