From b371cfe004d459590f65bab09faabbfce1a49908 Mon Sep 17 00:00:00 2001 From: modusensus Date: Mon, 2 Nov 2026 10:27:34 +0000 Subject: [PATCH 1/3] =?UTF-8?q?chore:=20v0.10.0=20=E5=8F=91=E5=B8=83?= =?UTF-8?q?=E5=87=86=E5=A4=87=EF=BC=88=E7=89=88=E6=9C=AC=E5=8F=B7=20+=20?= =?UTF-8?q?=E6=B5=8B=E8=AF=95=E5=BE=BD=E7=AB=A0=20+=20CHANGELOG/=E7=89=88?= =?UTF-8?q?=E6=9C=AC=E8=A1=A8=E5=8D=A0=E4=BD=8D=E8=A1=8C=EF=BC=89?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 机械部分已由 scripts/release-prep.mjs 完成。合并前还需要人来写: - [ ] dsh-mneme/CHANGELOG.md 新节里的条目(现在只有一条「- (待填)」) - [ ] 两个 README 里新占位行的主题描述 - [ ] 根 README 的「📰 最近更新」/「📰 Recent updates」表各加一行头条 - [ ] 跨 minor 时确认 README 路线图上新 minor 行的主题(占位行只写了「(待填)」) - [ ] 跨 minor 时把 SECURITY.md 中英两张支持版本表挪一格(活跃开发 / 尽力维护 / 不支持三段一起挪,含停止维护那段通知) --- README.md | 2 ++ dsh-mneme/CHANGELOG.md | 2 ++ dsh-mneme/README.md | 1 + dsh-mneme/package-lock.json | 4 ++-- dsh-mneme/package.json | 2 +- 5 files changed, 8 insertions(+), 3 deletions(-) diff --git a/README.md b/README.md index 461547ee..f0414f88 100644 --- a/README.md +++ b/README.md @@ -263,6 +263,7 @@ dsh-mneme-serve # 默认 ~/.dsh/memory + 127.0.0.1:8790 | **v0.7** | 自进化记忆:热度衰减 + 睡眠双保护 + 桌面端工作台/功能开关 | ✅ | | **v0.8** | 作用域隔离(agent/workspace 双维隔离 + 检索加权 + opt-in 硬过滤)+ 冲突队列人工裁决 + 归属显式声明 + 生态化(stdio MCP server / 图召回轴 / 冷启动 / 注入截断与状态条 / 蒸馏可靠性 / 注入形态与 agent 主动整理接口 / 配置说明与 issue 模板) | ✅ 已发布(至 v0.8.16) | | **v0.9** | M.O.(Modus Operandi)beta:项目级工作流本体 + 候选分层与升格判据 + 面板清单/图同屏;设置面板按「新手之外」重划折叠线(#427);安全审计与供应链加固(声明式路由鉴权、OSV 阻断、发布签名);**v0.9.1 补上写侧**:执行窗口、运行账、归属候选、观察旁挂与脱节检出、步骤 `assert`/`optional`、沉淀链草稿挖掘、人格定义页(按 agent 多卡);**v0.9.2 让看不见的失败显形**:功能开关第三态「待重启」、作用域级可逆闸门(#471)、巩固 `max_tokens` 超上限自动降级(#478);**v0.9.3 接通自动沉淀**:按会话头 `cwd` 反查项目桶、挂 `turn/end`、冷却 10 分钟、单次预算 4 秒,只产提议不产草稿(#489),并修作用域反查自 v0.8.0 起静默降级(#487)、`/nudge` 写盘口漏拦 `PATCH`/`DELETE`、多帧 zstd 反证断言绑 Node 整块解语义(#490);**v0.9.4 补上三条链的最后一环**:agent 主动整理接口有了工具(`memory_organize`,`organizeEnabled` 默认关,关时模型根本看不到它)、画像可以从记忆提取**草稿**(`profileExtractEnabled` 默认关,只出草稿、采用是用户再点一次,手写的原文不被模型改写)、人格 `default` 卡不再无条件进「没建卡」的身份(#497,`personaStrictAddressing` 默认关),面板那段「注入生效文本」改成由后端单源渲染,另补蒸馏转录围栏与解析失败护栏(#494);**v0.9.5 让记忆递得出去也收得回来**:分享包 `mneme.share/v1`(只含活跃行、scope 与 home 前缀不进包、密钥/PII 整条不进、报告先于下载、3 MiB 水位、一条不合格整包拒、干跑为默认、按 `share_external_id` 幂等、整包退出走物删),「本机巩固不改写别人导入的原文」由单一谓词守在汇流口与九个行池,记忆溯源读出口 `GET /memory/provenance`(@z2Ace0107,409 与 503 两种「没有」分开),并修同标题重复入库(#505)、模式扫描窗口饿死(#515)、五处 prompt 未围栏(#501/#493)与 dream 合并护栏整类误拦(#521),面板加设置页分组目录(#518) | ✅ 已发布(v0.9.5) | +| **v0.10** | (待填) | ✅ 已发布(v0.10.0) | > 完整逐小版本说明见 [CHANGELOG](dsh-mneme/CHANGELOG.md)。 @@ -543,6 +544,7 @@ Community projects that wire mneme into more platforms — not part of this repo | **v0.7** | Self-evolving memory: heat decay + sleep dual-protection + desktop workbench/feature toggles | ✅ | | **v0.8** | Scope isolation (agent/workspace stamping + retrieval weighting + opt-in hard filter) + conflict review queue + explicit attribution + ecosystem (stdio MCP server / graph recall axis / cold-start bootstrap / injection truncation & status bar / distill reliability / injection shaping & agent-driven organize / configuration reference & issue templates) | ✅ Released (up to v0.8.16) | | **v0.9** | M.O. (Modus Operandi) beta: project-level workflows + candidate tiering & promotion criteria + panel list-and-graph view; settings panel re-folded at "beyond the newcomer" (#427); security & supply-chain hardening (declarative route auth, OSV gate, signed releases); **v0.9.1 adds the write side**: execution windows, run ledger, attribution candidates, observation sidecar with drift detection, step `assert`/`optional`, draft mining from session logs, persona page (per-agent cards); **v0.9.2 makes silent failures visible**: feature-flag third state "pending restart", scope-level reversible gate (#471), automatic max_tokens downgrade for consolidation (#478); **v0.9.3 wires up auto-distillation**: resolves the project bucket from the session header's `cwd`, hooks `turn/end`, 10-minute cooldown, 4-second budget, proposals only and never drafts (#489), and fixes the scope reverse-lookup that had been silently degrading since v0.8.0 (#487), the `/nudge` write gate missing `PATCH`/`DELETE`, and a multi-frame zstd counter-assertion bound to Node's whole-buffer decode semantics (#490); **v0.9.4 supplies the missing last link on three chains**: the agent-driven organizing interface finally gets a tool (`memory_organize`, behind `organizeEnabled`, off by default — off means the model cannot even see it), the profile can be drafted from memory (`profileExtractEnabled`, off by default; a draft only — applying it is another user action, and hand-written text is never rewritten by the model), and the persona `default` card is no longer handed to identities that simply have no card (#497, `personaStrictAddressing`, off by default); the panel's "injected text" card is now rendered by a single backend source, plus the distillation transcript fence and parse-failure guard (#494); **v0.9.5 makes memory shareable and recallable**: the `mneme.share/v1` pack (active rows only, no scopes or home prefixes, secret/PII rows dropped whole, report before file, 3 MiB watermark, one bad row rejects the whole pack, dry-run by default, idempotent on `share_external_id`, withdrawal deletes rather than archives), a single predicate guarding "local consolidation never rewrites someone else's imported text" at the dedupe choke point and nine row pools, the provenance read endpoint `GET /memory/provenance` (@z2Ace0107, with 409 and 503 kept as two different answers), plus fixes for duplicate same-title writes (#505), a starved pattern-scan window (#515), five unfenced consolidation prompts (#501/#493) and a merge guard skipping whole categories (#521), and a sticky settings section index (#518) | ✅ Released (v0.9.5) | +| **v0.10** | TBD | ✅ Released (v0.10.0) | > Full per-minor-version changelog in [CHANGELOG](dsh-mneme/CHANGELOG.md). diff --git a/dsh-mneme/CHANGELOG.md b/dsh-mneme/CHANGELOG.md index b65be5be..3bc7dcd5 100644 --- a/dsh-mneme/CHANGELOG.md +++ b/dsh-mneme/CHANGELOG.md @@ -2,6 +2,8 @@ ## [Unreleased] +## [0.10.0] - 2026-11-02 + ## 🆕 新增 - **溯源读出口补上反方向:`GET /memory/provenance?sessionId=`——「这个会话蒸出了哪几个窗口」第一次可直接查,此前只能「从一条记忆往回找」(#524,从 #421 拆出方向 2)**:#421 当初拆成两个方向,方向 1(记忆 → 窗口 → `distill_records` 原文)由 #509 交付,方向 2(会话 → 它产出的蒸馏窗口)一直没做。底下其实早就齐了——`memory_provenance` 自 #399 就在写、`idx_memory_provenance_session` 自那时就建着——缺的只是入参方向:`parseProvenanceQuery` 只认 `?id=`,`session_id` 只在响应里躺着。**复用同一条路径而不是新开一条**:多一条路径就多四处要登记的地方(`SECURITY.md` 两张表、包 README 路由表、`test/security-doc.test.js` 的清单锁),而两个方向读的是同一批数据、只是入口不同;`SECURITY.md` 只登记路径不登记 query 形状,所以方向 2 在那两张表里一行都不用加。两个主键**互斥**:都缺 `400 missing-id`、都给 `400 ambiguous-id`——**刻意不做「都给则择一」**,择一意味着调用方可以发一个自己也不知道会被读哪个主键的请求,而两个方向的答复形状不同,那种静默选择只会在出事之后才被发现。 diff --git a/dsh-mneme/README.md b/dsh-mneme/README.md index 0661e773..e8c8cbad 100644 --- a/dsh-mneme/README.md +++ b/dsh-mneme/README.md @@ -284,6 +284,7 @@ v0.3.0 起新增**记忆基因**层:从记忆里抽取**命名实体**、**带 | **v0.9.3**(2026-10-20) | M.O. 从「挖得出来」到「会被叫去挖」:沉淀链算法自 v0.9.1 起就完整实现(多帧 zstd → 重复序列 → 缺席对照 → draft 草稿),运行时却没有任何调用点——机器挖得出来、却永远不会被叫去挖。这一版把归属与触发接上:按会话头 `cwd` 反查项目桶(桶名是路径的有损变形,查不到整跑跳过而不是降级成全局普查)、挂 `turn/end`、冷却 10 分钟、单次预算 4 秒、延到宏任务、一次一个项目、抛错只 `warn`,**只产提议不产草稿**(`actionNudgeEnabled`,beta,默认关);面板加「现在沉淀一次」,与自动跑同一条入口,区别只有它不改仓库;另修作用域反查自 v0.8.0 起每次都抛错走降级(#487)、`/nudge` 三处「没看全」被报成「确实没有」(#489 评审)、多帧 zstd 反证断言绑了 Node 整块解语义(#490),并把整个 M.O. 的「手法」改回「工作流」 | | **v0.9.4**(2026-10-21) | 三条链各自补上「最后一环」——东西早就造好了,只差没人能叫它:**agent 主动整理**(`memory_organize`,先 dryRun 出比对报告 → agent 判断 → apply 落库,筛除只归档不删、全程留审计回执;`organizeEnabled` 默认关,关时工具根本不注册);**画像提取草稿**(面板按钮读活跃记忆 + 一次模型调用,产一段「助手眼中的用户」草稿,`profileExtractEnabled` 默认关)——**只出草稿**,采用是用户再点一次,手写的画像原文不会被模型改写,空库与解析失败都直接报错、绝不回空草稿冒充「没提炼出东西」;**人格寻址收口**(`default` 卡以前无条件落给所有没建卡的身份,宿主里自带身份的 bot 每帧收到两句「你是谁」;`personaStrictAddressing` 默认关,把「没建卡」与「卡被显式关掉」都收回为不注入)。同版补蒸馏的**转录围栏 + 解析失败护栏**(#494:一条会话被同一窗口卡死、重试 20 次越试越贵的根因;失败行现在恒带原始输出形状),把面板自称「注入生效文本」的只读区改成后端单源渲染(并修它从不显示人格行),评审另收掉两处「坏了却不报」:整理报告侧的存在性探测口(`strictScope` 下按调用方可见性过滤落点并重算计数)、画像保存不判 `res.ok` 却提示已保存 | | **v0.9.5**(2026-10-30) | 记忆能安全地递给别人,也能整包收回来:**分享包 `mneme.share/v1`**(`dsh-mneme share` / `receive` / `undo-share`,面板「⋯」里同一批三件事)只含活跃行,scope 与 home 前缀不进包,命中密钥 / PII 的行整条不进;出包先给报告再给文件,超 3 MiB 水位回 413、按 `--type` / `--tag` 分批;入包一条不合格整包拒、干跑为默认、按 `share_external_id` 幂等,整包退出走物删。「本机巩固不许改写别人导入的原文」由单一谓词 `isImportedRow` 守在汇流口与九个行池上。同版给记忆来源加了读出口 `GET /memory/provenance`(#421,@z2Ace0107 实现;409 = 用户关了、503 = 装配坏了),修掉同标题重复入库(#505)、扫描谎报「没东西可扫」(#515)、五处未围栏的巩固 prompt(#501)与 dream 合并护栏整类误拦(#521),面板新增设置页分组目录(#518) | +| **v0.10.0**(2026-11-02) | (待填) | | **v0.8.x** | 作用域隔离(agent / workspace 双维 + opt-in 硬过滤)、冲突队列人工裁决、生态化(stdio MCP server / 图召回轴 / 冷启动 / 注入截断) | diff --git a/dsh-mneme/package-lock.json b/dsh-mneme/package-lock.json index 4c4b6864..a5b3f974 100644 --- a/dsh-mneme/package-lock.json +++ b/dsh-mneme/package-lock.json @@ -1,12 +1,12 @@ { "name": "@modusensus/dsh-mneme", - "version": "0.9.5", + "version": "0.10.0", "lockfileVersion": 3, "requires": true, "packages": { "": { "name": "@modusensus/dsh-mneme", - "version": "0.9.5", + "version": "0.10.0", "license": "MIT", "dependencies": { "morphicons": "^1.7.1" diff --git a/dsh-mneme/package.json b/dsh-mneme/package.json index 317c5e84..cb1583f9 100644 --- a/dsh-mneme/package.json +++ b/dsh-mneme/package.json @@ -1,7 +1,7 @@ { "name": "@modusensus/dsh-mneme", "description": "Cross-session memory plugin for DeepSeek Harness with autoDream consolidation: SQLite store, Markdown mirrors, 10 model tools, automatic injection, session summarization, user profile/rules, custom slash commands, vector (semantic) search, and a Web GUI panel", - "version": "0.9.5", + "version": "0.10.0", "license": "MIT", "repository": { "type": "git", From 5b13f93635668d3a2a873fed507f3b4b795c8bc2 Mon Sep 17 00:00:00 2001 From: modusensus Date: Mon, 2 Nov 2026 18:52:23 +0800 Subject: [PATCH 2/3] =?UTF-8?q?docs:=20v0.10.0=20=E5=8F=91=E5=B8=83?= =?UTF-8?q?=E5=87=86=E5=A4=87=E2=80=94=E2=80=94=E7=89=88=E6=9C=AC=E8=A1=A8?= =?UTF-8?q?=E4=B8=BB=E9=A2=98=E3=80=81News=20=E5=A4=B4=E6=9D=A1=E3=80=81?= =?UTF-8?q?=E6=94=AF=E6=8C=81=E7=89=88=E6=9C=AC=E8=A1=A8=E4=B8=8B=E7=A7=BB?= =?UTF-8?q?=E4=B8=8E=E8=B4=A1=E7=8C=AE=E8=80=85=E5=B0=8F=E8=8A=82?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 发版准备脚本只写机械部分,判断部分按 CONTRIBUTING 由人补: - 双 README 的 v0.10 版本表主题(中文两处、英文一处); - 双 README 的 News 头条各一条(2026-11-02 / v0.10.0); - CHANGELOG 0.10.0 节的贡献者 / Thanks 小节(四位外部贡献者,含分工与编号); - CHANGELOG 里唯一一处内部实验代号(E12)改写成中性措辞; - SECURITY.md 中英两张支持版本表跨 minor 下移一格,Out of scope 的「不支持版本」边界同步到 < 0.9.0。 另修 test/release-docs.test.js 的一处定时炸弹:目标版本写死成 0.10.0, 在 release-prep 分支上占位行已存在,于是「中英各插一行」退化成零插入必红。 改为取现存最高 major 再高一档,断言与「这次发的是哪一版」无关。 --- README.md | 6 ++++-- SECURITY.md | 20 ++++++++++---------- dsh-mneme/CHANGELOG.md | 9 ++++++++- dsh-mneme/README.md | 2 +- dsh-mneme/test/release-docs.test.js | 8 +++++++- 5 files changed, 30 insertions(+), 15 deletions(-) diff --git a/README.md b/README.md index f0414f88..1ff226d6 100644 --- a/README.md +++ b/README.md @@ -31,6 +31,7 @@ | 日期 | 版本 | 头条 | |------|------|------| +| 2026-11-02 | **v0.10.0** | **记忆开始按「哪一轮」算账,而不只是「哪一段」** — 这一版补的都是同一件事:给已经发生的事补上它自己的身份。① **蒸馏有了运行身份**([#512](https://github.com/slow-stack/mneme/issues/512)):此前归因只到「会话区间」——那是**输入**的坐标,不是**运行**的身份,于是「这段原文被重蒸过几次、哪一轮失败了」库里一个字都没存。现在窗口级记 `distill_runs`(含 `ok`/`degraded`/`noop`/`failed`/`aborted` 与 `audit_id`),行级另开 `memory_mints` 记「这条记忆出生自哪一轮巩固」;历史行一律留空**不猜**,模型流失败与解析失败也真记一行。② **溯源补上反方向**([#524](https://github.com/slow-stack/mneme/issues/524)):`GET /memory/provenance?sessionId=` 让「这个会话蒸出了哪几个窗口」可直接查,此前只能从一条记忆往回找;两个主键互斥,`limit` 越界直接 400 而不静默截断,撞上限带 `truncated: true`。③ **闸门落到单个会话**([#539](https://github.com/slow-stack/mneme/issues/539)):`sessionGateEnabled` 让指定会话与子代理「不进不出」(不注入、不收 `memory_*`、不蒸馏),其余会话照常——此前能关的只有全局,关插件会连带打死别的会话。子代理判据只认宿主自己的委派标记,`parentSession` **不是**判据:本机 641 个真实会话头逐条核过,用它会把 3 个 fork 出来的主会话判成子代理。④ **防谄媚补到写入面**([#530](https://github.com/slow-stack/mneme/issues/530)):蒸馏与总览的提示词此前对谄媚一字未提,而这两处写出的内容完全不过写入准入——现在补上「立场纪律」四条(不记对用户性格能力的评价、助手推断不写成事实、冲突如实记录)与「叙述纪律」,且排在与时间换算的指令之前。另修 `differentiate` 的正反馈闭环(同一段注记追加到两侧正文 → 向量靠拢 → 下一轮再判重复,实测单条堆 19 段、正文膨胀到 2200+ 字,现在只落账本不改正文,#533)、sleep 冲突相位的输入侧预算与续排(单请求曾打满 163,054 / 163,840 token,分批后隔夜才轮到,现在一轮跑完接着追,#529)、面板「最近巩固」不再把一次整理的回执冒充巩固([#495](https://github.com/slow-stack/mneme/issues/495)),以及面板在 320–519px 上原本根本没有断点([#542](https://github.com/slow-stack/mneme/issues/542))。 | | 2026-10-30 | **v0.9.5** | **记忆能安全地递出去,也能整包收回来** — 「分享记忆」从一个文件变成有协议的动作([#386](https://github.com/slow-stack/mneme/issues/386)):包只含活跃行,scope 与 home 前缀不进包,命中密钥 / PII 的行整条不进;出包先给报告再给文件,超水位回 413、按类型或标签分批;收包一条不合格整包拒、干跑为默认、按 `share_external_id` 幂等,`undo-share` 整包物删,所以收回后还能再导。来源也第一次可查:`GET /memory/provenance`([#421](https://github.com/slow-stack/mneme/issues/421),@z2Ace0107 实现),409 与 503 分开答「用户关了」与「装配坏了」。另修同标题重复入库(#505)、扫描谎报「没东西可扫」(#515)与未围栏的巩固 prompt(#501)。 | | 2026-10-21 | **v0.9.4** | **三条链各自补上「最后一环」** — 这一版的三件事同一种形状:东西早就造好了,只差没人能叫它。① **agent 主动整理**([#231](https://github.com/slow-stack/mneme/issues/231)):引擎在 v0.8 就落在 `src/organize.js`(先 dryRun 出比对报告 → agent 判断 → apply 落库,筛除只归档不删,全程复用 `dream_runs` 回执),可它**没有任何调用入口**——工具表里没有它、两张 API 脸 0 命中、全仓 `.organize(` 零调用点,只有测试能调到。现在它有工具了:`memory_organize`,`organizeEnabled` 默认关(关 = 工具根本不注册,模型看不到就不会调)。② **画像能被反向提取了**([#497](https://github.com/slow-stack/mneme/issues/497)):面板「用户画像」加一个按钮,读活跃记忆、花一次宿主模型调用,产一段「助手眼中的用户」**草稿**——**只出草稿**:采用是你在面板上再点一次,你手写的原文不会被模型改写;空库和模型不配合都直接报错,绝不回一张空草稿冒充「这次没提炼出东西」(`profileExtractEnabled` 默认关)。③ **人格不再无条件进别人的会话**:`default` 卡以前会落给所有没建卡的身份,于是宿主里自带身份的外部 bot 每一帧都收到两句「你是谁」撞在一起,而界面上「关掉这张卡」实际不生效——新增 `personaStrictAddressing`(默认关,历史行为逐字节不变)把「身份没建卡」与「卡被显式关掉」都收回到不注入。同版补上蒸馏的**转录围栏 + 解析失败护栏**([#494](https://github.com/slow-stack/mneme/pull/494):一条会话被同一个窗口卡死、重试 20 次越试越贵的根因;失败行现在恒带原始输出形状,事后能回答「模型到底吐了什么」),并把面板里那段自称「注入生效文本」的只读区改成由后端渲染——它以前既没有人格三行也没有表头和前缀,标题却承诺了模型实际看到的东西。 | | 2026-10-20 | **v0.9.3** | **M.O. 从「挖得出来」跑到「会被叫去挖」** — 沉淀链的算法自 v0.9.1 起就写完了(多帧 zstd → 重复序列 → 缺席对照 → draft 草稿),可它在运行时**没有任何调用点**:全仓引用只出现在测试里。机器挖得出来、却永远不会被叫去挖——缺的从来不是算法,是**归属**与**触发**。这一版把三处接上:按会话头里的 `cwd` 反查项目桶(桶名是路径的**有损**变形,规则不在本仓,查不到就整跑跳过,而不是降级成全局普查——后者会把 A 项目的动作算到 B 头上,且结果看起来完全正常);新增 `nudgeForProject` 把「归属 → 挖掘 → 落盘」收成一个入口;挂 `turn/end` 按项目跑,冷却 10 分钟、单次预算 4 秒、延到宏任务、一次一个项目、抛错只 `warn`。**它只产提议,不产草稿**([#489](https://github.com/slow-stack/mneme/pull/489)):升格仍然要人批,面板也多了「现在沉淀一次」,与自动跑同一条入口、区别只有不改仓库。同版修掉三处「坏了却不报」:作用域反查自 v0.8.0 起每次都抛错走降级、canonical 归一与成员校验静默失效([#487](https://github.com/slow-stack/mneme/issues/487));`/nudge` 的写盘口只拦 `PUT`/`POST`,带 token 的 `PATCH`/`DELETE` 会静默写盘、归属解析不看预算、桶名边收边截把「没看全」报成「确实没有」;多帧 zstd 的反证断言绑了 Node 的整块解语义,24.22.0 起过期([#490](https://github.com/slow-stack/mneme/pull/490))。 | @@ -263,7 +264,7 @@ dsh-mneme-serve # 默认 ~/.dsh/memory + 127.0.0.1:8790 | **v0.7** | 自进化记忆:热度衰减 + 睡眠双保护 + 桌面端工作台/功能开关 | ✅ | | **v0.8** | 作用域隔离(agent/workspace 双维隔离 + 检索加权 + opt-in 硬过滤)+ 冲突队列人工裁决 + 归属显式声明 + 生态化(stdio MCP server / 图召回轴 / 冷启动 / 注入截断与状态条 / 蒸馏可靠性 / 注入形态与 agent 主动整理接口 / 配置说明与 issue 模板) | ✅ 已发布(至 v0.8.16) | | **v0.9** | M.O.(Modus Operandi)beta:项目级工作流本体 + 候选分层与升格判据 + 面板清单/图同屏;设置面板按「新手之外」重划折叠线(#427);安全审计与供应链加固(声明式路由鉴权、OSV 阻断、发布签名);**v0.9.1 补上写侧**:执行窗口、运行账、归属候选、观察旁挂与脱节检出、步骤 `assert`/`optional`、沉淀链草稿挖掘、人格定义页(按 agent 多卡);**v0.9.2 让看不见的失败显形**:功能开关第三态「待重启」、作用域级可逆闸门(#471)、巩固 `max_tokens` 超上限自动降级(#478);**v0.9.3 接通自动沉淀**:按会话头 `cwd` 反查项目桶、挂 `turn/end`、冷却 10 分钟、单次预算 4 秒,只产提议不产草稿(#489),并修作用域反查自 v0.8.0 起静默降级(#487)、`/nudge` 写盘口漏拦 `PATCH`/`DELETE`、多帧 zstd 反证断言绑 Node 整块解语义(#490);**v0.9.4 补上三条链的最后一环**:agent 主动整理接口有了工具(`memory_organize`,`organizeEnabled` 默认关,关时模型根本看不到它)、画像可以从记忆提取**草稿**(`profileExtractEnabled` 默认关,只出草稿、采用是用户再点一次,手写的原文不被模型改写)、人格 `default` 卡不再无条件进「没建卡」的身份(#497,`personaStrictAddressing` 默认关),面板那段「注入生效文本」改成由后端单源渲染,另补蒸馏转录围栏与解析失败护栏(#494);**v0.9.5 让记忆递得出去也收得回来**:分享包 `mneme.share/v1`(只含活跃行、scope 与 home 前缀不进包、密钥/PII 整条不进、报告先于下载、3 MiB 水位、一条不合格整包拒、干跑为默认、按 `share_external_id` 幂等、整包退出走物删),「本机巩固不改写别人导入的原文」由单一谓词守在汇流口与九个行池,记忆溯源读出口 `GET /memory/provenance`(@z2Ace0107,409 与 503 两种「没有」分开),并修同标题重复入库(#505)、模式扫描窗口饿死(#515)、五处 prompt 未围栏(#501/#493)与 dream 合并护栏整类误拦(#521),面板加设置页分组目录(#518) | ✅ 已发布(v0.9.5) | -| **v0.10** | (待填) | ✅ 已发布(v0.10.0) | +| **v0.10** | 归因与闸门:蒸馏归因补上「运行」身份(`distill_runs` 窗口级 + `memory_mints` 行级,历史行不猜)、溯源补上反方向 `?sessionId=`、会话级无痕闸门(`sessionGateEnabled`,判据只认宿主委派标记 + 有界记账)、防谄媚补到写入面(蒸馏与总览的立场 / 叙述纪律)、`differentiate` 改落账本不改正文(#533)、sleep 冲突相位输入侧预算与续排(#529)、面板「最近巩固」区分 organize 回执(#495)、面板首次有移动端与 481–519px 中间带断点(#542) | ✅ 已发布(v0.10.0) | > 完整逐小版本说明见 [CHANGELOG](dsh-mneme/CHANGELOG.md)。 @@ -312,6 +313,7 @@ dsh-mneme 的机制设计与下列公开研究相互印证(以下引用均逐 | Date | Version | Headline | |------|---------|----------| +| 2026-11-02 | **v0.10.0** | **Memory now keeps accounts per run, not only per span** — everything in this release adds one missing thing: an identity for what already happened. ① **Distillation gets a run identity** ([#512](https://github.com/slow-stack/mneme/issues/512)): provenance only reached "which session span", a coordinate of the **input**, never of the **run** — so "how many times was this text re-distilled, and which rounds failed" was nowhere in the store. Window level now records `distill_runs` (`ok` / `degraded` / `noop` / `failed` / `aborted`, plus `audit_id`), row level gets its own `memory_mints` table for "which consolidation run minted this memory"; historical rows stay NULL rather than guessed, and failed rounds are recorded too. ② **Provenance gains the other direction** ([#524](https://github.com/slow-stack/mneme/issues/524)): `GET /memory/provenance?sessionId=` answers "which windows did this session produce", where before you could only walk back from one memory. The two keys are mutually exclusive, an out-of-range `limit` is a 400 rather than a silent truncation, and hitting the cap sets `truncated: true`. ③ **The gate reaches individual sessions** ([#539](https://github.com/slow-stack/mneme/issues/539)): `sessionGateEnabled` makes chosen sessions and subagents receive nothing and record nothing — no injection, no `memory_*` calls, no distillation — while every other session carries on; previously the only switch was global, and turning the plugin off took other sessions down with it. Subagent detection uses only the host's own delegation markers, never `parentSession`: verified against 641 real session headers on one machine, where it misclassified 3 forked main sessions. ④ **Anti-sycophancy reaches the write side** ([#530](https://github.com/slow-stack/mneme/issues/530)): the distillation and overview prompts said nothing about flattery, and what they write never passes write admission — now they carry a stance discipline (no judging the user's character or ability, assistant inference is not written as fact, conflicts recorded rather than adjudicated) and a narration discipline, placed ahead of the timestamp-conversion instruction. Also fixed: the `differentiate` positive-feedback loop (the same note appended to both sides → vectors converge → judged duplicate again; one row carried 19 notes and grew from 150 to 2200+ characters — the note now lives in a ledger, not in the text, #533), the sleep conflict phase's missing input budget and catch-up (one request filled 163,054 of 163,840 tokens and the rest waited overnight; a clean round now continues immediately, #529), the panel's "last consolidation" card no longer passing an organize receipt off as consolidation ([#495](https://github.com/slow-stack/mneme/issues/495)), and the panel gaining its first breakpoints for 320–519px ([#542](https://github.com/slow-stack/mneme/issues/542)). | | 2026-10-30 | **v0.9.5** | **Memory can be handed over safely — and taken back** — sharing memory stops being a file and becomes a protocolled action ([#386](https://github.com/slow-stack/mneme/issues/386)): the pack carries active rows only, with no scopes, no home prefixes and no secret/PII rows; shipping returns a report before the file, answers 413 over the watermark and batches by type or tag; receiving rejects the whole pack on one bad row, dry-runs by default, stays idempotent on `share_external_id`, and `undo-share` deletes outright, so a withdrawn pack can be re-imported. Provenance becomes readable too: `GET /memory/provenance` ([#421](https://github.com/slow-stack/mneme/issues/421), by @z2Ace0107), where 409 and 503 answer "the user switched it off" and "the wiring is missing" apart. Plus #505, #515 and the unfenced consolidation prompts (#501). | | 2026-10-21 | **v0.9.4** | **Three chains each get their missing last link** — the three items in this release share one shape: the thing was already built, nothing could call it. ① **Agent-driven organizing** ([#231](https://github.com/slow-stack/mneme/issues/231)): the engine landed in `src/organize.js` back in v0.8 (dryRun comparison report → the agent decides → apply persists, screening out means archive rather than delete, every step leaving a `dream_runs` receipt), but it had **no entry point at all** — absent from the tool table, zero hits on both API surfaces, zero `.organize(` call sites in the repo; only its own tests could reach it. Now it has a tool: `memory_organize`, behind `organizeEnabled`, off by default (off = the tool is not even registered, so a model that cannot see it never calls it). ② **The profile can finally be derived** ([#497](https://github.com/slow-stack/mneme/issues/497)): the panel's profile card gained a button that reads the active memories, spends one host model call and returns an "as the assistant sees them" **draft** — **a draft only**: applying it is another click you make, and your hand-written text is never rewritten by the model; an empty store or a misbehaving model is an error, never an empty draft masquerading as "nothing to extract this time" (`profileExtractEnabled`, off by default). ③ **Personas no longer leak into someone else's session**: the `default` card used to be handed to every identity without a card, so a third-party bot running in the same host — one that carries its own identity — received two "you are ..." claims in every turn, while "switch this card off" in the panel changed nothing; the new `personaStrictAddressing` (off by default, existing behaviour byte-identical) reclaims both "no card for this identity" and "card explicitly switched off" as inject-nothing. The same release adds the **transcript fence and the parse-failure guard** for distillation ([#494](https://github.com/slow-stack/mneme/pull/494): the root cause of one session being stuck on the same window, retried 20 times and growing more expensive each time; failed rows now always carry the raw output shape, so "what did the model actually print" is answerable afterwards), and the panel's read-only card that called itself "injected text" is now rendered by the backend — it used to show neither the persona lines nor the header and prefix it claimed to mirror. | | 2026-10-20 | **v0.9.3** | **M.O. goes from “diggable” to “actually summoned to dig”** — the distillation chain has been fully implemented since v0.9.1 (multi-frame zstd → repeated sequences → absence contrast → draft workflows), yet it had **no call site at runtime**: every reference in the repo lived in tests. The machine could dig, but nothing ever called it. What was missing was never the algorithm — it was **attribution** and **triggering**. This release wires up three things: resolving a project's session bucket from the `cwd` in the session header (bucket names are a **lossy** transform of paths whose rule lives outside this repo; when the lookup fails the whole run is skipped rather than degraded into a global sweep — the latter attributes project A's actions to project B, and the result looks perfectly normal); a new `nudgeForProject` that folds “attribute → mine → persist” into one entry point; and a `turn/end` hook that runs per project with a 10-minute cooldown, a 4-second budget, deferred to a macrotask, one project at a time, errors only warned. **It produces proposals, never drafts** ([#489](https://github.com/slow-stack/mneme/pull/489)): promotion still needs a human, and the panel gained a "distill now" button on the same entry point, differing only in that it does not touch the repo. The same version fixes three “broken but silent” defects: the scope reverse-lookup that had been throwing and silently degrading on every call since v0.8.0, disabling canonical normalization and membership checks ([#487](https://github.com/slow-stack/mneme/issues/487)); `/nudge`'s write gate, which only intercepted `PUT`/`POST` so a token-bearing `PATCH`/`DELETE` persisted proposals silently, plus attribution resolution ignoring the budget and bucket names being truncated while being collected — reporting “did not look at everything” as “there is genuinely nothing”; and a multi-frame zstd counter-assertion bound to Node's whole-buffer decode semantics, expired from 24.22.0 ([#490](https://github.com/slow-stack/mneme/pull/490)). | @@ -544,7 +546,7 @@ Community projects that wire mneme into more platforms — not part of this repo | **v0.7** | Self-evolving memory: heat decay + sleep dual-protection + desktop workbench/feature toggles | ✅ | | **v0.8** | Scope isolation (agent/workspace stamping + retrieval weighting + opt-in hard filter) + conflict review queue + explicit attribution + ecosystem (stdio MCP server / graph recall axis / cold-start bootstrap / injection truncation & status bar / distill reliability / injection shaping & agent-driven organize / configuration reference & issue templates) | ✅ Released (up to v0.8.16) | | **v0.9** | M.O. (Modus Operandi) beta: project-level workflows + candidate tiering & promotion criteria + panel list-and-graph view; settings panel re-folded at "beyond the newcomer" (#427); security & supply-chain hardening (declarative route auth, OSV gate, signed releases); **v0.9.1 adds the write side**: execution windows, run ledger, attribution candidates, observation sidecar with drift detection, step `assert`/`optional`, draft mining from session logs, persona page (per-agent cards); **v0.9.2 makes silent failures visible**: feature-flag third state "pending restart", scope-level reversible gate (#471), automatic max_tokens downgrade for consolidation (#478); **v0.9.3 wires up auto-distillation**: resolves the project bucket from the session header's `cwd`, hooks `turn/end`, 10-minute cooldown, 4-second budget, proposals only and never drafts (#489), and fixes the scope reverse-lookup that had been silently degrading since v0.8.0 (#487), the `/nudge` write gate missing `PATCH`/`DELETE`, and a multi-frame zstd counter-assertion bound to Node's whole-buffer decode semantics (#490); **v0.9.4 supplies the missing last link on three chains**: the agent-driven organizing interface finally gets a tool (`memory_organize`, behind `organizeEnabled`, off by default — off means the model cannot even see it), the profile can be drafted from memory (`profileExtractEnabled`, off by default; a draft only — applying it is another user action, and hand-written text is never rewritten by the model), and the persona `default` card is no longer handed to identities that simply have no card (#497, `personaStrictAddressing`, off by default); the panel's "injected text" card is now rendered by a single backend source, plus the distillation transcript fence and parse-failure guard (#494); **v0.9.5 makes memory shareable and recallable**: the `mneme.share/v1` pack (active rows only, no scopes or home prefixes, secret/PII rows dropped whole, report before file, 3 MiB watermark, one bad row rejects the whole pack, dry-run by default, idempotent on `share_external_id`, withdrawal deletes rather than archives), a single predicate guarding "local consolidation never rewrites someone else's imported text" at the dedupe choke point and nine row pools, the provenance read endpoint `GET /memory/provenance` (@z2Ace0107, with 409 and 503 kept as two different answers), plus fixes for duplicate same-title writes (#505), a starved pattern-scan window (#515), five unfenced consolidation prompts (#501/#493) and a merge guard skipping whole categories (#521), and a sticky settings section index (#518) | ✅ Released (v0.9.5) | -| **v0.10** | TBD | ✅ Released (v0.10.0) | +| **v0.10** | Attribution and gates: distillation provenance gains a **run** identity (`distill_runs` per window plus `memory_mints` per row; historical rows left NULL rather than guessed), provenance gains the reverse direction `?sessionId=`, a per-session incognito gate (`sessionGateEnabled`, keyed on the host's own delegation markers with a bounded ledger), anti-sycophancy rules reaching the write side (stance and narration discipline in distillation and overview), `differentiate` moving to a ledger instead of rewriting text (#533), an input budget and catch-up for the sleep conflict phase (#529), the "last consolidation" card no longer showing organize receipts (#495), and the panel's first mobile and 481–519px breakpoints (#542) | ✅ Released (v0.10.0) | > Full per-minor-version changelog in [CHANGELOG](dsh-mneme/CHANGELOG.md). diff --git a/SECURITY.md b/SECURITY.md index 51ddf4e0..be1ceac3 100644 --- a/SECURITY.md +++ b/SECURITY.md @@ -10,11 +10,11 @@ We actively maintain the latest minor version. Security fixes are backported to | Version | Supported | Status | |---|---|---| -| 0.9.x | ✅ Yes | Active development | -| 0.8.x | ⚠️ Best-effort | Critical fixes only | -| < 0.8.0 | ❌ No | Please upgrade to 0.9.x | +| 0.10.x | ✅ Yes | Active development | +| 0.9.x | ⚠️ Best-effort | Critical fixes only | +| < 0.9.0 | ❌ No | Please upgrade to 0.10.x | -**End-of-life notice**: 0.8.x is in best-effort maintenance (critical fixes only). Its end-of-life date will be announced in advance; after that date no security fixes will be provided for 0.8.x. Security support for 0.7.x and below is no longer provided — please upgrade to 0.9.x. +**End-of-life notice**: 0.9.x is in best-effort maintenance (critical fixes only). Its end-of-life date will be announced in advance; after that date no security fixes will be provided for 0.9.x. Security support for 0.8.x and below is no longer provided — please upgrade to 0.10.x. --- @@ -86,7 +86,7 @@ The plugin can optionally start its own HTTP server (`externalApiEnabled`, defau **Out of scope** — we will not act on: - Social engineering or phishing against maintainers or users - DoS claims that require unrealistic local resource exhaustion with no product defect -- Vulnerabilities present only in unsupported versions (`< 0.8.0`) +- Vulnerabilities present only in unsupported versions (`< 0.9.0`) - Best-practice hardening suggestions with no demonstrable security impact Not sure whether your finding is in scope? Report it anyway via the private channel — we will triage and respond. @@ -396,11 +396,11 @@ This project is licensed under the **MIT License**. See [LICENSE](https://github | 版本 | 支持状态 | 说明 | |---|---|---| -| 0.9.x | ✅ 支持 | 活跃开发中 | -| 0.8.x | ⚠️ 尽力维护 | 仅关键修复 | -| < 0.8.0 | ❌ 不支持 | 请升级至 0.9.x | +| 0.10.x | ✅ 支持 | 活跃开发中 | +| 0.9.x | ⚠️ 尽力维护 | 仅关键修复 | +| < 0.9.0 | ❌ 不支持 | 请升级至 0.10.x | -**停止维护通知**:0.8.x 处于尽力维护阶段(仅关键修复)。停止维护的具体日期将提前公布;该日期之后将不再提供 0.8.x 的安全修复。0.7.x 及更早版本的安全支持已终止——请升级至 0.9.x。 +**停止维护通知**:0.9.x 处于尽力维护阶段(仅关键修复)。停止维护的具体日期将提前公布;该日期之后将不再提供 0.9.x 的安全修复。0.8.x 及更早版本的安全支持已终止——请升级至 0.10.x。 --- @@ -472,7 +472,7 @@ This project is licensed under the **MIT License**. See [LICENSE](https://github **不受理范围**——以下问题我们不予处理: - 针对维护者或用户的社工 / 钓鱼类问题 - 仅通过不现实的本地资源耗尽触发、且无产品缺陷支撑的 DoS 声明 -- 仅存在于不支持版本(`< 0.8.0`)的问题 +- 仅存在于不支持版本(`< 0.9.0`)的问题 - 无可证明安全影响的"最佳实践建议"类问题 不确定你的发现是否在受理范围内?仍请通过私有渠道提交——我们会评估并回复。 diff --git a/dsh-mneme/CHANGELOG.md b/dsh-mneme/CHANGELOG.md index 3bc7dcd5..e1fa8cb6 100644 --- a/dsh-mneme/CHANGELOG.md +++ b/dsh-mneme/CHANGELOG.md @@ -34,7 +34,7 @@ 回归测试 +9(`test/session-gate.test.js`:默认关 / `parentSession` 单独不判 / 手动名单与子代理开关互相独立且配置活读 / 无 id 子代理照判 / 记账有界淘汰 / 四个注入面为空 / 全部工具在副作用前拒绝 / 热重载后旧执行器跟随新闸门 / 蒸馏早退)与 +2(`test/pipeline-nudge.test.js`:fork 主会话的观测不许被滤掉、非 session 首行不许当会话头)。变异自证:把 `parentSession` 判据加回去 → fork 那两条红;把 `if (!id) return false` 加回去 → 无 id 那条红;把 `?? row?.data ?? row` 加回去 → 非 session 首行那条红。 -- **蒸馏与总览的提示词第一次对「谄媚」开口:写入侧补「立场纪律」与「叙述纪律」(#530,承接 #380)**:`preInjectGate` 把防谄媚做在**注入面**(E12 实测谄媚率 26.9% → 2.5%),代价是它只是最后一道门、而且默认关;而落到库里**之前**的两个写作环节——蒸馏(`src/lang.js` 的 `summary` / `codingSummary`)与总览(`dreamSummary`)——对谄媚一字未提。这两处写出的内容**完全不过** `writeAdmission`(`src/write-admission.js:285` 的 `if (!sessionKey) return verdict;`,而 `sessionKey` 唯一来源是 `src/tools.js:187` 的 `memory_save` 路径,蒸馏与 dream 写入都不带),所以提示词是唯一能施加约束的地方。**① 立场纪律**(`summary` 与 `codingSummary` 中英各一份)四条:只记事实/偏好/决策/约束、不记对用户本人性格能力情绪品行的评价(无论褒贬);转录三种角色可信度不同——`用户:` 是用户陈述,`助手:` 与 `子会话交付:` 的结论是推断不是事实,除非用户明确采纳否则不写成记忆,确需保留要在 content 里注明是推断;用户陈述与助手推断冲突时以用户陈述为准、冲突如实写进 content 而不替用户裁决;`importance` 只看事实对后续工作的影响面,用户的满意/赞许/情绪都不是抬高它的理由。开头那句「**与上条原则冲突时以本条为准**」不是修辞:「偏好照常记录」与「不记评价」表面有张力,没有优先级条款模型会靠丢弃合法偏好来解张力。**② 叙述纪律**(`dreamSummary` 中英各一份):只写记忆里已写明的事实与偏好,不给用户添性格/能力/情绪评价,不把助手自己的判断写成「用户认为」,某条记忆本身带褒贬口气时只取事实内核。放它的理由是总览是个**放大器**——`src/dream.js:1562` 的落库判据只有 `summaryText.trim()`(无长度、形状、内容判据),`:1568` 固定 `importance:5` + `type:"summary"`,于是 `src/service.js:1696-1706` 进 priority 0 最高注入档、且 `type=summary` 在 `service.js:1665-1671` 的池过滤里**跳过 importanceThreshold**:池里一条谄媚条目会被复述进总览、常驻注入、每轮都见。**两处都必须插在字面量内部且排在 JSON 输出形状之前**——`src/summarize.js:825` 在提示词之后拼 `STR.distillTimeAnchor`(「据此换算 occurred_at」),规则接在锚点之后就变成「先按时间换算、再谈记什么」,指令优先级反了。**规则 b 里那半句「工具输出、报错、命令结果直接给出的技术结论豁免」不能删**:`pitfall` / `constraint` 的内容本来就是工具给出的技术结论,没有豁免就等于把编码回溯功能一并否掉,这是全文最容易被后人顺手删掉的高危句,已单独立锁。**不加配置开关**:仓库既有的 opt-in 开关没有一个是否提示词文本键(全是「要不要跑某条路径」),本批零新增 LLM 调用、零新增配置键,加开关要连带白名单 + schema + 旗标计数锁,而默认关 = 默认无保护,恰好放弃要防的东西——先例是 v0.9.3 的转录围栏(#493)无条件上线。**`preInjectGate` 的池刻意不套围栏**(本轮只补一条「为什么」注释):它的 system 契约把 user 形状写死成「你将收到一个 JSON 对象」,套围栏会让提示词与载荷互相矛盾,而判定池靠 `JSON.parse` 取 `m#i` 局部序号;`JSON.stringify` 本就结构性转义引号与花括号(实测 roundtrip 一致),围栏反而让伪造闭合标记从 1 次变 2 次——不增加防护只增加攻击面,该路径的真防线是整池 wipeout fail-open 加「判定结果绝不进模型上下文」。**明确不在本批**(写进 issue 与本文,别读成「防谄媚已闭环」):巩固 merge 会整段重写正文(`src/dream/decisions.js:627-629` 走 `service.update`),而护栏类型表 `ARCHIVE_GUARDED_TYPES` 不含 `project` / `decision` / `history` / `summary`——正是「对用户的评价」最常落的类型,谄媚在那里从「搬运」升级成「改写放大」且源条目随即归档;`consolidation` 的「合并后取最高」、`conflict` 的「更可信」判据、`pattern` 从夸赞炼人格三处同类;`importance` 单调不减是代码保证(`src/service.js:1443` 的 `Math.max`),规则 d 救不回已被抬到 5 的存量行;给 `quality-filter` 加确定性立场信号这条路是死的(`service.js:1598` 的 `importanceExempt >= 4` 正好豁免谄媚最可能落的那一档);`codingSummary` 缺 type 枚举锁是既有缺陷(`summarize.js:100` 的 `VALID` 只认 7 个 type,自造分类会被静默丢弃且失败路径不推进游标导致同窗口重放),建议独立小 PR。**提示词测试只锁形状不锁行为**:`test/prompt-stance.test.js` 能断言「文本里有这条约束、位置对」,锁不了「模型是否遵守」——后者要 LLM 在环加预注册判据(E12 那类),本轮不做,**不得把本批写成「已验证降低谄媚率」**。新用例 6 条:中英成对、位置锁、工具豁免条款在场、散文契约不破(`doesNotMatch(/JSON 数组|JSON array/)`,总览要的是散文)、总览落库判据不放宽(空串仍 `summary:false` 且旧总览存活)。改动只碰提示词字面量与一条注释,既有锁一条未改。 +- **蒸馏与总览的提示词第一次对「谄媚」开口:写入侧补「立场纪律」与「叙述纪律」(#530,承接 #380)**:`preInjectGate` 把防谄媚做在**注入面**(实测谄媚率 26.9% → 2.5%),代价是它只是最后一道门、而且默认关;而落到库里**之前**的两个写作环节——蒸馏(`src/lang.js` 的 `summary` / `codingSummary`)与总览(`dreamSummary`)——对谄媚一字未提。这两处写出的内容**完全不过** `writeAdmission`(`src/write-admission.js:285` 的 `if (!sessionKey) return verdict;`,而 `sessionKey` 唯一来源是 `src/tools.js:187` 的 `memory_save` 路径,蒸馏与 dream 写入都不带),所以提示词是唯一能施加约束的地方。**① 立场纪律**(`summary` 与 `codingSummary` 中英各一份)四条:只记事实/偏好/决策/约束、不记对用户本人性格能力情绪品行的评价(无论褒贬);转录三种角色可信度不同——`用户:` 是用户陈述,`助手:` 与 `子会话交付:` 的结论是推断不是事实,除非用户明确采纳否则不写成记忆,确需保留要在 content 里注明是推断;用户陈述与助手推断冲突时以用户陈述为准、冲突如实写进 content 而不替用户裁决;`importance` 只看事实对后续工作的影响面,用户的满意/赞许/情绪都不是抬高它的理由。开头那句「**与上条原则冲突时以本条为准**」不是修辞:「偏好照常记录」与「不记评价」表面有张力,没有优先级条款模型会靠丢弃合法偏好来解张力。**② 叙述纪律**(`dreamSummary` 中英各一份):只写记忆里已写明的事实与偏好,不给用户添性格/能力/情绪评价,不把助手自己的判断写成「用户认为」,某条记忆本身带褒贬口气时只取事实内核。放它的理由是总览是个**放大器**——`src/dream.js:1562` 的落库判据只有 `summaryText.trim()`(无长度、形状、内容判据),`:1568` 固定 `importance:5` + `type:"summary"`,于是 `src/service.js:1696-1706` 进 priority 0 最高注入档、且 `type=summary` 在 `service.js:1665-1671` 的池过滤里**跳过 importanceThreshold**:池里一条谄媚条目会被复述进总览、常驻注入、每轮都见。**两处都必须插在字面量内部且排在 JSON 输出形状之前**——`src/summarize.js:825` 在提示词之后拼 `STR.distillTimeAnchor`(「据此换算 occurred_at」),规则接在锚点之后就变成「先按时间换算、再谈记什么」,指令优先级反了。**规则 b 里那半句「工具输出、报错、命令结果直接给出的技术结论豁免」不能删**:`pitfall` / `constraint` 的内容本来就是工具给出的技术结论,没有豁免就等于把编码回溯功能一并否掉,这是全文最容易被后人顺手删掉的高危句,已单独立锁。**不加配置开关**:仓库既有的 opt-in 开关没有一个是否提示词文本键(全是「要不要跑某条路径」),本批零新增 LLM 调用、零新增配置键,加开关要连带白名单 + schema + 旗标计数锁,而默认关 = 默认无保护,恰好放弃要防的东西——先例是 v0.9.3 的转录围栏(#493)无条件上线。**`preInjectGate` 的池刻意不套围栏**(本轮只补一条「为什么」注释):它的 system 契约把 user 形状写死成「你将收到一个 JSON 对象」,套围栏会让提示词与载荷互相矛盾,而判定池靠 `JSON.parse` 取 `m#i` 局部序号;`JSON.stringify` 本就结构性转义引号与花括号(实测 roundtrip 一致),围栏反而让伪造闭合标记从 1 次变 2 次——不增加防护只增加攻击面,该路径的真防线是整池 wipeout fail-open 加「判定结果绝不进模型上下文」。**明确不在本批**(写进 issue 与本文,别读成「防谄媚已闭环」):巩固 merge 会整段重写正文(`src/dream/decisions.js:627-629` 走 `service.update`),而护栏类型表 `ARCHIVE_GUARDED_TYPES` 不含 `project` / `decision` / `history` / `summary`——正是「对用户的评价」最常落的类型,谄媚在那里从「搬运」升级成「改写放大」且源条目随即归档;`consolidation` 的「合并后取最高」、`conflict` 的「更可信」判据、`pattern` 从夸赞炼人格三处同类;`importance` 单调不减是代码保证(`src/service.js:1443` 的 `Math.max`),规则 d 救不回已被抬到 5 的存量行;给 `quality-filter` 加确定性立场信号这条路是死的(`service.js:1598` 的 `importanceExempt >= 4` 正好豁免谄媚最可能落的那一档);`codingSummary` 缺 type 枚举锁是既有缺陷(`summarize.js:100` 的 `VALID` 只认 7 个 type,自造分类会被静默丢弃且失败路径不推进游标导致同窗口重放),建议独立小 PR。**提示词测试只锁形状不锁行为**:`test/prompt-stance.test.js` 能断言「文本里有这条约束、位置对」,锁不了「模型是否遵守」——后者要 LLM 在环加预注册判据,本轮不做,**不得把本批写成「已验证降低谄媚率」**。新用例 6 条:中英成对、位置锁、工具豁免条款在场、散文契约不破(`doesNotMatch(/JSON 数组|JSON array/)`,总览要的是散文)、总览落库判据不放宽(空串仍 `summary:false` 且旧总览存活)。改动只碰提示词字面量与一条注释,既有锁一条未改。 ## 🎨 面板 @@ -65,6 +65,13 @@ - **main 的 Security 变红跟代码无关,是上游两小时前才发的两条公告:`glob@13.0.6` 与 `minimatch@10.2.6` 都落在 devDependency 链上(#533/#534 合并之后暴露)**:2026-10-31 04:42 的 `277779f` 与 03:29 的 `1931508` 两次 push 的 Security workflow 都红,而 CI 四条腿全绿——红的不是测试,是 osv-scanner 那一步:`Total 2 packages affected by 2 known vulnerabilities (0 Critical, 0 High, 2 Medium …)`,`GHSA-3g3m-2fjr-6pw4`(CVSS 6.3,glob 的 AbortSignal 取消绕过,超时后仍继续遍历文件系统,别名 CVE-2026-118773)与 `GHSA-g3hv-75wg-m249`(CVSS 6.9,minimatch 的 globparts 放大 DoS,别名 CVE-2026-118764)。两条公告的 `published` 都是 **2026-10-30T23:09Z**,而 `2139237` 的 Security 是当天 08:36 跑的、当时还是 success;`git diff 2139237 277779f -- dsh-mneme/package-lock.json` **完全为空**——同一个 lockfile 隔了 15 小时从未绿变红,所以这不是回归,是「规则变了」。来源链只有一条:`c8@12.0.0`(devDep)→ `test-exclude@8.0.0` → `glob@13.0.6` + `minimatch@10.2.6`(deduped);`c8` 与 `test-exclude` 都已是 npm 上的最新版,其 deps 仍写 `glob: ^13.0.6` / `minimatch: ^10.2.2`,**上游还没跟上**,所以只能在本仓库 overrides 抬 pin 号——与 `adm-zip@0.6.1`、`brace-expansion@5.0.12` 同一手法(PR #345 那次就是这样清零的)。glob 抬到 14.0.3、minimatch 抬到 11.0.3,`npm audit` 双口径 0 vulnerabilities。**为什么钉死而不是写 `^`**:overrides 的职责是「这个闭包就装这一版」,写范围等于把选择权交回解析器,下一次上游发新版时 lockfile 会在某个「只更新 lockfile」的 PR 里悄悄漂走,而 osv-scanner 只看 lockfile——红绿灯本该由人决定。**代价与验证**:glob 14 把 `path-scurry` 从 2.x 提到 3.x、minimatch 11 多带一个 `@isaacs/nonrecursive-glob-match`(都是 dev-only,不进发布包、不参与运行时);这条链唯一的生产用途是 `npm run test:coverage` 的 `c8` 文件筛选,全量 `npm test` **2569 / 2568 pass / 0 fail / 1 skipped**,另在临时工程里跑过 `c8 --include/--exclude/--all` 三种走 glob 的入口,覆盖率表正常。**没有 `ignore`/allowlist**:把公告静音等于让下一条真公告也一起静音,而 `security.yml` 里 osv-scanner 的 `fail-on-vuln: true` 正是为了不让它只当提醒。 +### 贡献者 / Thanks + +- **@wuchichiumike** — 会话级无痕闸门的实现(#540,#539):三个 opt-in 键、子代理判据只认宿主自己的委派标记、拿不到 id 也照判、记账表有界。本版唯一的外部代码贡献。 +- **@chengxinshengglj-png** — #529 的两轮实测:先用一份 3,400 条活跃的库回填「封顶 24h 够不够、60 对默认值准不准」,再指出上一批修复「预算造 backlog、退避没接住」——续排这一批就是从这条反馈展开的。 +- **@xueyue33** — #533 的现场数据:37 轮 sleep 之后活跃记忆里 100 条被重复追加同一段差异注记,最狠的一条 19 段、正文从 150 字膨胀到 2200+ 字。 +- **@strange2000** — #493 的复核:指出失败计数只活在进程里、围栏断链只长在一处,本版两条补充都来自这份复核。 + ## [0.9.5] - 2026-10-30 ## 🆕 新增 diff --git a/dsh-mneme/README.md b/dsh-mneme/README.md index e8c8cbad..626f8f09 100644 --- a/dsh-mneme/README.md +++ b/dsh-mneme/README.md @@ -284,7 +284,7 @@ v0.3.0 起新增**记忆基因**层:从记忆里抽取**命名实体**、**带 | **v0.9.3**(2026-10-20) | M.O. 从「挖得出来」到「会被叫去挖」:沉淀链算法自 v0.9.1 起就完整实现(多帧 zstd → 重复序列 → 缺席对照 → draft 草稿),运行时却没有任何调用点——机器挖得出来、却永远不会被叫去挖。这一版把归属与触发接上:按会话头 `cwd` 反查项目桶(桶名是路径的有损变形,查不到整跑跳过而不是降级成全局普查)、挂 `turn/end`、冷却 10 分钟、单次预算 4 秒、延到宏任务、一次一个项目、抛错只 `warn`,**只产提议不产草稿**(`actionNudgeEnabled`,beta,默认关);面板加「现在沉淀一次」,与自动跑同一条入口,区别只有它不改仓库;另修作用域反查自 v0.8.0 起每次都抛错走降级(#487)、`/nudge` 三处「没看全」被报成「确实没有」(#489 评审)、多帧 zstd 反证断言绑了 Node 整块解语义(#490),并把整个 M.O. 的「手法」改回「工作流」 | | **v0.9.4**(2026-10-21) | 三条链各自补上「最后一环」——东西早就造好了,只差没人能叫它:**agent 主动整理**(`memory_organize`,先 dryRun 出比对报告 → agent 判断 → apply 落库,筛除只归档不删、全程留审计回执;`organizeEnabled` 默认关,关时工具根本不注册);**画像提取草稿**(面板按钮读活跃记忆 + 一次模型调用,产一段「助手眼中的用户」草稿,`profileExtractEnabled` 默认关)——**只出草稿**,采用是用户再点一次,手写的画像原文不会被模型改写,空库与解析失败都直接报错、绝不回空草稿冒充「没提炼出东西」;**人格寻址收口**(`default` 卡以前无条件落给所有没建卡的身份,宿主里自带身份的 bot 每帧收到两句「你是谁」;`personaStrictAddressing` 默认关,把「没建卡」与「卡被显式关掉」都收回为不注入)。同版补蒸馏的**转录围栏 + 解析失败护栏**(#494:一条会话被同一窗口卡死、重试 20 次越试越贵的根因;失败行现在恒带原始输出形状),把面板自称「注入生效文本」的只读区改成后端单源渲染(并修它从不显示人格行),评审另收掉两处「坏了却不报」:整理报告侧的存在性探测口(`strictScope` 下按调用方可见性过滤落点并重算计数)、画像保存不判 `res.ok` 却提示已保存 | | **v0.9.5**(2026-10-30) | 记忆能安全地递给别人,也能整包收回来:**分享包 `mneme.share/v1`**(`dsh-mneme share` / `receive` / `undo-share`,面板「⋯」里同一批三件事)只含活跃行,scope 与 home 前缀不进包,命中密钥 / PII 的行整条不进;出包先给报告再给文件,超 3 MiB 水位回 413、按 `--type` / `--tag` 分批;入包一条不合格整包拒、干跑为默认、按 `share_external_id` 幂等,整包退出走物删。「本机巩固不许改写别人导入的原文」由单一谓词 `isImportedRow` 守在汇流口与九个行池上。同版给记忆来源加了读出口 `GET /memory/provenance`(#421,@z2Ace0107 实现;409 = 用户关了、503 = 装配坏了),修掉同标题重复入库(#505)、扫描谎报「没东西可扫」(#515)、五处未围栏的巩固 prompt(#501)与 dream 合并护栏整类误拦(#521),面板新增设置页分组目录(#518) | -| **v0.10.0**(2026-11-02) | (待填) | +| **v0.10.0**(2026-11-02) | 归因与闸门——给已经发生的事补上它自己的身份:**蒸馏有了运行身份**(窗口级 `distill_runs` 记 `ok`/`degraded`/`noop`/`failed`/`aborted` 与 `audit_id`,行级 `memory_mints` 记「这条记忆出生自哪一轮巩固」;历史行留空**不猜**,失败轮也真记一行),此前归因只到「会话区间」——那是输入的坐标不是运行的身份;**溯源补上反方向** `GET /memory/provenance?sessionId=`(两个主键互斥,`limit` 越界 400 不静默截断,撞上限带 `truncated: true`);**会话级无痕闸门** `sessionGateEnabled`(指定会话与子代理不进不出,其余会话照常;子代理判据只认宿主委派标记,`parentSession` 不是判据——本机 641 个会话头实测会误判 3 个 fork 主会话);**防谄媚补到写入面**(蒸馏与总览加「立场纪律」四条与「叙述纪律」,排在与时间换算的指令之前)。另修 `differentiate` 正反馈闭环(注记改落 `differentiated_pairs` 账本、正文一个字节都改不了,实测单条曾堆 19 段)、sleep 冲突相位的输入侧预算与续排(分批后不再隔夜才轮到)、面板「最近巩固」区分 organize 回执(#495)、面板首次有移动端与 481–519px 中间带断点(#542) | | **v0.8.x** | 作用域隔离(agent / workspace 双维 + opt-in 硬过滤)、冲突队列人工裁决、生态化(stdio MCP server / 图召回轴 / 冷启动 / 注入截断) | diff --git a/dsh-mneme/test/release-docs.test.js b/dsh-mneme/test/release-docs.test.js index 10e0493b..2ee09ab2 100644 --- a/dsh-mneme/test/release-docs.test.js +++ b/dsh-mneme/test/release-docs.test.js @@ -51,7 +51,13 @@ test("根 README 的两段式路线图能插进新 minor 占位行(旧实现 test("真实根 README 的中英两张路线图各插一行(同一版本号,不能只插一张)", () => { // 两张表版本行完全一样,旧实现把全文件版本行合成一个数组判断「已存在」, // 于是先插的中文表会让英文表被跳过——英文读者永远等不到那一行。 - const { actions } = syncReadmeTables(rootReadme, "0.10.0", "2026-11-01"); + // + // 目标版本**不能写死**:写死当次要发的版本,这条用例在 release-prep 分支上必红——那一行 + // 恰好已经由发版准备脚本插进去了,「各插一行」于是退化成零插入。取比现存的最高 major 再高一档, + // 断言就与「这次发的是哪一版」彻底无关,也不会在下一个 minor 上重新长成定时炸弹。 + const maxMajor = Math.max(...scanReleaseRows(rootReadme).two.map((r) => Number(r.ver.split(".")[0]))); + const target = `${maxMajor + 1}.0`; + const { actions } = syncReadmeTables(rootReadme, target, "2026-11-01"); const inserts = actions.filter((a) => a.kind === "insert"); assert.equal(inserts.length, 2, "中英路线图各一行,实际:" + JSON.stringify(actions)); }); From f9a16776f4634dee4088a3b1062de2280fa50471 Mon Sep 17 00:00:00 2001 From: modusensus Date: Mon, 2 Nov 2026 19:03:11 +0800 Subject: [PATCH 3/3] =?UTF-8?q?docs:=20=E8=A1=A5=E9=BD=90=E7=AB=8B?= =?UTF-8?q?=E5=9C=BA=E7=BA=AA=E5=BE=8B=E7=AC=AC=E5=9B=9B=E6=9D=A1=EF=BC=8C?= =?UTF-8?q?=E5=B9=B6=E6=8A=8A=E4=BC=9A=E8=AF=9D=E9=97=B8=E9=97=A8=E5=AF=B9?= =?UTF-8?q?=20memory=5F*=20=E7=9A=84=E6=8E=AA=E8=BE=9E=E6=94=B9=E6=88=90?= =?UTF-8?q?=E3=80=8C=E6=8B=92=E7=BB=9D=E3=80=8D?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 两处都是发布说明的措辞与本版实际行为不一致(CodeRabbit 两条评审): - 立场纪律在正文里写成「四条」,括号里只列了三项;补上第四条 (importance 只看事实对后续工作的影响面,不因用户满意或情绪抬高), 与 CHANGELOG 一致。中英两版都补。 - 会话闸门那处原写「不收 memory_* 与 set_scope_state」,读起来像 「这些调用不会发生」;实际行为是插件在工具注册期统一包一层, 受闸门会话发起的调用直接抛错拒绝。改成「一律被拒」,并补上 set_scope_state(闸门包在注册期,对每个注册工具都生效)。 --- README.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index 1ff226d6..1b056f21 100644 --- a/README.md +++ b/README.md @@ -31,7 +31,7 @@ | 日期 | 版本 | 头条 | |------|------|------| -| 2026-11-02 | **v0.10.0** | **记忆开始按「哪一轮」算账,而不只是「哪一段」** — 这一版补的都是同一件事:给已经发生的事补上它自己的身份。① **蒸馏有了运行身份**([#512](https://github.com/slow-stack/mneme/issues/512)):此前归因只到「会话区间」——那是**输入**的坐标,不是**运行**的身份,于是「这段原文被重蒸过几次、哪一轮失败了」库里一个字都没存。现在窗口级记 `distill_runs`(含 `ok`/`degraded`/`noop`/`failed`/`aborted` 与 `audit_id`),行级另开 `memory_mints` 记「这条记忆出生自哪一轮巩固」;历史行一律留空**不猜**,模型流失败与解析失败也真记一行。② **溯源补上反方向**([#524](https://github.com/slow-stack/mneme/issues/524)):`GET /memory/provenance?sessionId=` 让「这个会话蒸出了哪几个窗口」可直接查,此前只能从一条记忆往回找;两个主键互斥,`limit` 越界直接 400 而不静默截断,撞上限带 `truncated: true`。③ **闸门落到单个会话**([#539](https://github.com/slow-stack/mneme/issues/539)):`sessionGateEnabled` 让指定会话与子代理「不进不出」(不注入、不收 `memory_*`、不蒸馏),其余会话照常——此前能关的只有全局,关插件会连带打死别的会话。子代理判据只认宿主自己的委派标记,`parentSession` **不是**判据:本机 641 个真实会话头逐条核过,用它会把 3 个 fork 出来的主会话判成子代理。④ **防谄媚补到写入面**([#530](https://github.com/slow-stack/mneme/issues/530)):蒸馏与总览的提示词此前对谄媚一字未提,而这两处写出的内容完全不过写入准入——现在补上「立场纪律」四条(不记对用户性格能力的评价、助手推断不写成事实、冲突如实记录)与「叙述纪律」,且排在与时间换算的指令之前。另修 `differentiate` 的正反馈闭环(同一段注记追加到两侧正文 → 向量靠拢 → 下一轮再判重复,实测单条堆 19 段、正文膨胀到 2200+ 字,现在只落账本不改正文,#533)、sleep 冲突相位的输入侧预算与续排(单请求曾打满 163,054 / 163,840 token,分批后隔夜才轮到,现在一轮跑完接着追,#529)、面板「最近巩固」不再把一次整理的回执冒充巩固([#495](https://github.com/slow-stack/mneme/issues/495)),以及面板在 320–519px 上原本根本没有断点([#542](https://github.com/slow-stack/mneme/issues/542))。 | +| 2026-11-02 | **v0.10.0** | **记忆开始按「哪一轮」算账,而不只是「哪一段」** — 这一版补的都是同一件事:给已经发生的事补上它自己的身份。① **蒸馏有了运行身份**([#512](https://github.com/slow-stack/mneme/issues/512)):此前归因只到「会话区间」——那是**输入**的坐标,不是**运行**的身份,于是「这段原文被重蒸过几次、哪一轮失败了」库里一个字都没存。现在窗口级记 `distill_runs`(含 `ok`/`degraded`/`noop`/`failed`/`aborted` 与 `audit_id`),行级另开 `memory_mints` 记「这条记忆出生自哪一轮巩固」;历史行一律留空**不猜**,模型流失败与解析失败也真记一行。② **溯源补上反方向**([#524](https://github.com/slow-stack/mneme/issues/524)):`GET /memory/provenance?sessionId=` 让「这个会话蒸出了哪几个窗口」可直接查,此前只能从一条记忆往回找;两个主键互斥,`limit` 越界直接 400 而不静默截断,撞上限带 `truncated: true`。③ **闸门落到单个会话**([#539](https://github.com/slow-stack/mneme/issues/539)):`sessionGateEnabled` 让指定会话与子代理「不进不出」(不注入、不蒸馏,`memory_*` 与 `set_scope_state` 调用一律被拒),其余会话照常——此前能关的只有全局,关插件会连带打死别的会话。子代理判据只认宿主自己的委派标记,`parentSession` **不是**判据:本机 641 个真实会话头逐条核过,用它会把 3 个 fork 出来的主会话判成子代理。④ **防谄媚补到写入面**([#530](https://github.com/slow-stack/mneme/issues/530)):蒸馏与总览的提示词此前对谄媚一字未提,而这两处写出的内容完全不过写入准入——现在补上「立场纪律」四条(不记对用户性格能力的评价、助手推断不写成事实、冲突如实记录、`importance` 只看事实对后续工作的影响面而不因用户满意或情绪抬高)与「叙述纪律」,且排在与时间换算的指令之前。另修 `differentiate` 的正反馈闭环(同一段注记追加到两侧正文 → 向量靠拢 → 下一轮再判重复,实测单条堆 19 段、正文膨胀到 2200+ 字,现在只落账本不改正文,#533)、sleep 冲突相位的输入侧预算与续排(单请求曾打满 163,054 / 163,840 token,分批后隔夜才轮到,现在一轮跑完接着追,#529)、面板「最近巩固」不再把一次整理的回执冒充巩固([#495](https://github.com/slow-stack/mneme/issues/495)),以及面板在 320–519px 上原本根本没有断点([#542](https://github.com/slow-stack/mneme/issues/542))。 | | 2026-10-30 | **v0.9.5** | **记忆能安全地递出去,也能整包收回来** — 「分享记忆」从一个文件变成有协议的动作([#386](https://github.com/slow-stack/mneme/issues/386)):包只含活跃行,scope 与 home 前缀不进包,命中密钥 / PII 的行整条不进;出包先给报告再给文件,超水位回 413、按类型或标签分批;收包一条不合格整包拒、干跑为默认、按 `share_external_id` 幂等,`undo-share` 整包物删,所以收回后还能再导。来源也第一次可查:`GET /memory/provenance`([#421](https://github.com/slow-stack/mneme/issues/421),@z2Ace0107 实现),409 与 503 分开答「用户关了」与「装配坏了」。另修同标题重复入库(#505)、扫描谎报「没东西可扫」(#515)与未围栏的巩固 prompt(#501)。 | | 2026-10-21 | **v0.9.4** | **三条链各自补上「最后一环」** — 这一版的三件事同一种形状:东西早就造好了,只差没人能叫它。① **agent 主动整理**([#231](https://github.com/slow-stack/mneme/issues/231)):引擎在 v0.8 就落在 `src/organize.js`(先 dryRun 出比对报告 → agent 判断 → apply 落库,筛除只归档不删,全程复用 `dream_runs` 回执),可它**没有任何调用入口**——工具表里没有它、两张 API 脸 0 命中、全仓 `.organize(` 零调用点,只有测试能调到。现在它有工具了:`memory_organize`,`organizeEnabled` 默认关(关 = 工具根本不注册,模型看不到就不会调)。② **画像能被反向提取了**([#497](https://github.com/slow-stack/mneme/issues/497)):面板「用户画像」加一个按钮,读活跃记忆、花一次宿主模型调用,产一段「助手眼中的用户」**草稿**——**只出草稿**:采用是你在面板上再点一次,你手写的原文不会被模型改写;空库和模型不配合都直接报错,绝不回一张空草稿冒充「这次没提炼出东西」(`profileExtractEnabled` 默认关)。③ **人格不再无条件进别人的会话**:`default` 卡以前会落给所有没建卡的身份,于是宿主里自带身份的外部 bot 每一帧都收到两句「你是谁」撞在一起,而界面上「关掉这张卡」实际不生效——新增 `personaStrictAddressing`(默认关,历史行为逐字节不变)把「身份没建卡」与「卡被显式关掉」都收回到不注入。同版补上蒸馏的**转录围栏 + 解析失败护栏**([#494](https://github.com/slow-stack/mneme/pull/494):一条会话被同一个窗口卡死、重试 20 次越试越贵的根因;失败行现在恒带原始输出形状,事后能回答「模型到底吐了什么」),并把面板里那段自称「注入生效文本」的只读区改成由后端渲染——它以前既没有人格三行也没有表头和前缀,标题却承诺了模型实际看到的东西。 | | 2026-10-20 | **v0.9.3** | **M.O. 从「挖得出来」跑到「会被叫去挖」** — 沉淀链的算法自 v0.9.1 起就写完了(多帧 zstd → 重复序列 → 缺席对照 → draft 草稿),可它在运行时**没有任何调用点**:全仓引用只出现在测试里。机器挖得出来、却永远不会被叫去挖——缺的从来不是算法,是**归属**与**触发**。这一版把三处接上:按会话头里的 `cwd` 反查项目桶(桶名是路径的**有损**变形,规则不在本仓,查不到就整跑跳过,而不是降级成全局普查——后者会把 A 项目的动作算到 B 头上,且结果看起来完全正常);新增 `nudgeForProject` 把「归属 → 挖掘 → 落盘」收成一个入口;挂 `turn/end` 按项目跑,冷却 10 分钟、单次预算 4 秒、延到宏任务、一次一个项目、抛错只 `warn`。**它只产提议,不产草稿**([#489](https://github.com/slow-stack/mneme/pull/489)):升格仍然要人批,面板也多了「现在沉淀一次」,与自动跑同一条入口、区别只有不改仓库。同版修掉三处「坏了却不报」:作用域反查自 v0.8.0 起每次都抛错走降级、canonical 归一与成员校验静默失效([#487](https://github.com/slow-stack/mneme/issues/487));`/nudge` 的写盘口只拦 `PUT`/`POST`,带 token 的 `PATCH`/`DELETE` 会静默写盘、归属解析不看预算、桶名边收边截把「没看全」报成「确实没有」;多帧 zstd 的反证断言绑了 Node 的整块解语义,24.22.0 起过期([#490](https://github.com/slow-stack/mneme/pull/490))。 | @@ -313,7 +313,7 @@ dsh-mneme 的机制设计与下列公开研究相互印证(以下引用均逐 | Date | Version | Headline | |------|---------|----------| -| 2026-11-02 | **v0.10.0** | **Memory now keeps accounts per run, not only per span** — everything in this release adds one missing thing: an identity for what already happened. ① **Distillation gets a run identity** ([#512](https://github.com/slow-stack/mneme/issues/512)): provenance only reached "which session span", a coordinate of the **input**, never of the **run** — so "how many times was this text re-distilled, and which rounds failed" was nowhere in the store. Window level now records `distill_runs` (`ok` / `degraded` / `noop` / `failed` / `aborted`, plus `audit_id`), row level gets its own `memory_mints` table for "which consolidation run minted this memory"; historical rows stay NULL rather than guessed, and failed rounds are recorded too. ② **Provenance gains the other direction** ([#524](https://github.com/slow-stack/mneme/issues/524)): `GET /memory/provenance?sessionId=` answers "which windows did this session produce", where before you could only walk back from one memory. The two keys are mutually exclusive, an out-of-range `limit` is a 400 rather than a silent truncation, and hitting the cap sets `truncated: true`. ③ **The gate reaches individual sessions** ([#539](https://github.com/slow-stack/mneme/issues/539)): `sessionGateEnabled` makes chosen sessions and subagents receive nothing and record nothing — no injection, no `memory_*` calls, no distillation — while every other session carries on; previously the only switch was global, and turning the plugin off took other sessions down with it. Subagent detection uses only the host's own delegation markers, never `parentSession`: verified against 641 real session headers on one machine, where it misclassified 3 forked main sessions. ④ **Anti-sycophancy reaches the write side** ([#530](https://github.com/slow-stack/mneme/issues/530)): the distillation and overview prompts said nothing about flattery, and what they write never passes write admission — now they carry a stance discipline (no judging the user's character or ability, assistant inference is not written as fact, conflicts recorded rather than adjudicated) and a narration discipline, placed ahead of the timestamp-conversion instruction. Also fixed: the `differentiate` positive-feedback loop (the same note appended to both sides → vectors converge → judged duplicate again; one row carried 19 notes and grew from 150 to 2200+ characters — the note now lives in a ledger, not in the text, #533), the sleep conflict phase's missing input budget and catch-up (one request filled 163,054 of 163,840 tokens and the rest waited overnight; a clean round now continues immediately, #529), the panel's "last consolidation" card no longer passing an organize receipt off as consolidation ([#495](https://github.com/slow-stack/mneme/issues/495)), and the panel gaining its first breakpoints for 320–519px ([#542](https://github.com/slow-stack/mneme/issues/542)). | +| 2026-11-02 | **v0.10.0** | **Memory now keeps accounts per run, not only per span** — everything in this release adds one missing thing: an identity for what already happened. ① **Distillation gets a run identity** ([#512](https://github.com/slow-stack/mneme/issues/512)): provenance only reached "which session span", a coordinate of the **input**, never of the **run** — so "how many times was this text re-distilled, and which rounds failed" was nowhere in the store. Window level now records `distill_runs` (`ok` / `degraded` / `noop` / `failed` / `aborted`, plus `audit_id`), row level gets its own `memory_mints` table for "which consolidation run minted this memory"; historical rows stay NULL rather than guessed, and failed rounds are recorded too. ② **Provenance gains the other direction** ([#524](https://github.com/slow-stack/mneme/issues/524)): `GET /memory/provenance?sessionId=` answers "which windows did this session produce", where before you could only walk back from one memory. The two keys are mutually exclusive, an out-of-range `limit` is a 400 rather than a silent truncation, and hitting the cap sets `truncated: true`. ③ **The gate reaches individual sessions** ([#539](https://github.com/slow-stack/mneme/issues/539)): `sessionGateEnabled` makes chosen sessions and subagents receive nothing and record nothing — no injection, no distillation, and any `memory_*` or `set_scope_state` call is refused — while every other session carries on; previously the only switch was global, and turning the plugin off took other sessions down with it. Subagent detection uses only the host's own delegation markers, never `parentSession`: verified against 641 real session headers on one machine, where it misclassified 3 forked main sessions. ④ **Anti-sycophancy reaches the write side** ([#530](https://github.com/slow-stack/mneme/issues/530)): the distillation and overview prompts said nothing about flattery, and what they write never passes write admission — now they carry a stance discipline (no judging the user's character or ability, assistant inference is not written as fact, conflicts recorded rather than adjudicated, and `importance` driven only by how much a fact affects later work — never raised by user satisfaction or mood) and a narration discipline, placed ahead of the timestamp-conversion instruction. Also fixed: the `differentiate` positive-feedback loop (the same note appended to both sides → vectors converge → judged duplicate again; one row carried 19 notes and grew from 150 to 2200+ characters — the note now lives in a ledger, not in the text, #533), the sleep conflict phase's missing input budget and catch-up (one request filled 163,054 of 163,840 tokens and the rest waited overnight; a clean round now continues immediately, #529), the panel's "last consolidation" card no longer passing an organize receipt off as consolidation ([#495](https://github.com/slow-stack/mneme/issues/495)), and the panel gaining its first breakpoints for 320–519px ([#542](https://github.com/slow-stack/mneme/issues/542)). | | 2026-10-30 | **v0.9.5** | **Memory can be handed over safely — and taken back** — sharing memory stops being a file and becomes a protocolled action ([#386](https://github.com/slow-stack/mneme/issues/386)): the pack carries active rows only, with no scopes, no home prefixes and no secret/PII rows; shipping returns a report before the file, answers 413 over the watermark and batches by type or tag; receiving rejects the whole pack on one bad row, dry-runs by default, stays idempotent on `share_external_id`, and `undo-share` deletes outright, so a withdrawn pack can be re-imported. Provenance becomes readable too: `GET /memory/provenance` ([#421](https://github.com/slow-stack/mneme/issues/421), by @z2Ace0107), where 409 and 503 answer "the user switched it off" and "the wiring is missing" apart. Plus #505, #515 and the unfenced consolidation prompts (#501). | | 2026-10-21 | **v0.9.4** | **Three chains each get their missing last link** — the three items in this release share one shape: the thing was already built, nothing could call it. ① **Agent-driven organizing** ([#231](https://github.com/slow-stack/mneme/issues/231)): the engine landed in `src/organize.js` back in v0.8 (dryRun comparison report → the agent decides → apply persists, screening out means archive rather than delete, every step leaving a `dream_runs` receipt), but it had **no entry point at all** — absent from the tool table, zero hits on both API surfaces, zero `.organize(` call sites in the repo; only its own tests could reach it. Now it has a tool: `memory_organize`, behind `organizeEnabled`, off by default (off = the tool is not even registered, so a model that cannot see it never calls it). ② **The profile can finally be derived** ([#497](https://github.com/slow-stack/mneme/issues/497)): the panel's profile card gained a button that reads the active memories, spends one host model call and returns an "as the assistant sees them" **draft** — **a draft only**: applying it is another click you make, and your hand-written text is never rewritten by the model; an empty store or a misbehaving model is an error, never an empty draft masquerading as "nothing to extract this time" (`profileExtractEnabled`, off by default). ③ **Personas no longer leak into someone else's session**: the `default` card used to be handed to every identity without a card, so a third-party bot running in the same host — one that carries its own identity — received two "you are ..." claims in every turn, while "switch this card off" in the panel changed nothing; the new `personaStrictAddressing` (off by default, existing behaviour byte-identical) reclaims both "no card for this identity" and "card explicitly switched off" as inject-nothing. The same release adds the **transcript fence and the parse-failure guard** for distillation ([#494](https://github.com/slow-stack/mneme/pull/494): the root cause of one session being stuck on the same window, retried 20 times and growing more expensive each time; failed rows now always carry the raw output shape, so "what did the model actually print" is answerable afterwards), and the panel's read-only card that called itself "injected text" is now rendered by the backend — it used to show neither the persona lines nor the header and prefix it claimed to mirror. | | 2026-10-20 | **v0.9.3** | **M.O. goes from “diggable” to “actually summoned to dig”** — the distillation chain has been fully implemented since v0.9.1 (multi-frame zstd → repeated sequences → absence contrast → draft workflows), yet it had **no call site at runtime**: every reference in the repo lived in tests. The machine could dig, but nothing ever called it. What was missing was never the algorithm — it was **attribution** and **triggering**. This release wires up three things: resolving a project's session bucket from the `cwd` in the session header (bucket names are a **lossy** transform of paths whose rule lives outside this repo; when the lookup fails the whole run is skipped rather than degraded into a global sweep — the latter attributes project A's actions to project B, and the result looks perfectly normal); a new `nudgeForProject` that folds “attribute → mine → persist” into one entry point; and a `turn/end` hook that runs per project with a 10-minute cooldown, a 4-second budget, deferred to a macrotask, one project at a time, errors only warned. **It produces proposals, never drafts** ([#489](https://github.com/slow-stack/mneme/pull/489)): promotion still needs a human, and the panel gained a "distill now" button on the same entry point, differing only in that it does not touch the repo. The same version fixes three “broken but silent” defects: the scope reverse-lookup that had been throwing and silently degrading on every call since v0.8.0, disabling canonical normalization and membership checks ([#487](https://github.com/slow-stack/mneme/issues/487)); `/nudge`'s write gate, which only intercepted `PUT`/`POST` so a token-bearing `PATCH`/`DELETE` persisted proposals silently, plus attribution resolution ignoring the budget and bucket names being truncated while being collected — reporting “did not look at everything” as “there is genuinely nothing”; and a multi-frame zstd counter-assertion bound to Node's whole-buffer decode semantics, expired from 24.22.0 ([#490](https://github.com/slow-stack/mneme/pull/490)). |