Skip to content

[Bug] memory_get 输出 schema 漏声明 scope 来源列:命中任何被标注的行必然报 invalid output(0.8.1) #184

Closed

Description

@lujfsd

环境

  • dsh-mneme 0.8.1(npm view @modusensus/dsh-mneme version → 0.8.1,无已修复版本)
  • 宿主:dsh Web profile(~/.dsh/profiles/web),Windows + node v24.14.1
  • 记忆库规模:13243 行,其中 6 行带 scope 标注

现象

memory_get 对任意被 scope 标注过的记忆 id 返回:

tool "memory_get" returned invalid output: "value.memory.agent_scope_source" is not a declared property (additionalProperties: false); "value.memory.workspace_scope_source" is not a declared property (additionalProperties: false)

未被标注的 id 正常返回,所以外部表现为「个别 id 必失败、多数 id 正常」,容易被当成偶发问题。

复现

  1. 在开启 scope 自动标注(scopeEnabled)的会话里写一条记忆 → 该行落 agent_scope_source='auto' / workspace_scope_source='auto';
  2. memory_get(id=<该行 id>) → 上报表错;
  3. 对照:memory_search / memory_list 对同一行正常,memory_update / memory_forget / memory_archive 也正常。

本机实测(同一 DB):

调用 该行标注 结果
memory_get 9cf1081a-… 无 正常返回
memory_get 5f954bb7-… auto 报错
memory_get 07ae6f40-… auto 报错
写入新记忆后立刻 memory_get 自己 auto 报错

即:在开启标注的会话里,每写一条新记忆就多一条 memory_get 读不回来的行。

SQL 口径:

SELECT COUNT(*) FROM memories
WHERE agent_scope_source IS NOT NULL OR workspace_scope_source IS NOT NULL;  -- 6 / 13243

根因(代码证据)

三处拼起来即构成缺陷,且只在 memory_get 上成立:

  1. 返回体会带这两个键 —— lib/service.js:1489-1495,toApiList() 条件展开:

    ...(m.agent_scope_source !== undefined ? { agent_scope_source: m.agent_scope_source } : {}),
    ...(m.workspace_scope_source !== undefined ? { workspace_scope_source: m.workspace_scope_source } : {}),
    ...(m.scope_decided_at !== undefined ? { scope_decided_at: m.scope_decided_at } : {}),
  2. memory_get 的 output schema 没声明它们 —— lib/tools.js:275-300(memory 对象 properties 只到 agent_scope / workspace_scope),而 additionalProperties: false(lib/tools.js:282)→ 校验直接拒绝。共缺 3 个键:agent_scope_source、workspace_scope_source、scope_decided_at。

  3. 为什么只命中少数行 —— lib/store.js:400-402 把列 NULL 映射为 undefined,条件展开后不带键;只有被标注过的行才带键。

同族工具为什么不炸:memory_search / memory_list 共用 MEMORY_ITEM_SCHEMA(lib/tools.js:18-41,其 33-35 行已声明这三个键);memory_update / memory_forget / memory_archive 返回的是手挑的小对象。src/tools.js:269-305 与 lib 同步缺失(lib 由 scripts/sync-lib.js 从 src 生成)。

推测引入点:这条路径来自 #171(per-dim 来源列)—— 加列时只更新了共享的 MEMORY_ITEM_SCHEMA,漏掉了 memory_get 的内联 schema。test/tools.test.js 里也没有「DTO 键集 ⊆ 各工具 output schema 声明键集」这类断言,所以 CI 没拦住。

影响

  • 功能面:memory_get 对被标注行完全不可用(当前 6/13243,但会随会话持续增长)。
  • 数据面:无损坏、无写入失败,仅读取被输出 schema 校验拦下。

Activity

  1. self-assigned this
    on Sep 15, 2026
  2. added
    bug功能异常、崩溃、数据错误(agent 诊断 → 人工确认)
    on Sep 15, 2026
  3. moved this from 📋 Backlog to 🎯 Ready in dsh-mneme 任务看板on Sep 15, 2026
  4. moved this from 🎯 Ready to 📋 Backlog in dsh-mneme 任务看板on Sep 15, 2026
  5. moved this from 📋 Backlog to 🔨 In Progress in dsh-mneme 任务看板on Sep 15, 2026
  6. modusensus commented on Sep 15, 2026

    @modusensus
    Member

    报告质量极高——三段代码证据链全部核实,getById → toApiList 的返回路径、内联 schema 的漏键、以及「为什么只有 memory_get 炸」的解释都准确。还多亏你的 SQL 口径:我们按它复现时发现实际漏声明的是三个键(你抓到两条,scope_decided_at 在你那几行恰好为 NULL 所以没进报错)。

    已修复:PR #186——memory_get 的输出 schema 不再维护内联副本,直接复用与 memory_search / memory_list 共享的 MEMORY_ITEM_SCHEMA(键集漂移从此不可能发生),并按你的建议补了回归测试:用宿主生产同款校验器 + 全量标注行复现 #184(修前逐字复现你的报错),外加 DTO 键集 ⊆ schema 声明的防漂移断言。

    你推测的引入点也对:#171 加列时只更新了共享 schema,漏了内联那份;CI 缺口(DTO 键集 ⊆ 各工具 output schema 的系统性断言)我们会在独立 issue 里跟进(全工具矩阵比单工具复杂,值得单独做)。

    感谢报告——这是 0.8.1 当天的第三个高质量 issue,修复会随下一个 patch 版本发布。

  7. moved this from 🔨 In Progress to ✅ Done in dsh-mneme 任务看板on Sep 15, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

Labels

bug功能异常、崩溃、数据错误(agent 诊断 → 人工确认)

Type

No type

Projects

No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions