Skip to content

feat(scope): 写入端 scope 标注存储层(A1,issue #17) - #153

Merged
modusensus merged 3 commits into
mainfrom
feat/scope-storage-a1
Sep 12, 2026
Merged

modusensus merged 3 commits into
mainfrom
feat/scope-storage-a1

Conversation

@modusensus

Copy link
Copy Markdown
Member

v0.8.0 批次 A · A1 存储层(Refs #17,1/4)

scope 隔离的地基:存储层纯增量 + 写入端标注 + 去重键扩展。scopeEnabled 默认关,关闭时行为与改动前逐字节一致;检索加权/过滤在 A2、strictScope 硬过滤在 A3、面板显示在 A4,分开提交。

English TL;DR: additive storage layer for scope isolation — four nullable columns (agent_scope/workspace_scope/sensitivity/occurred_at, no DEFAULT, zero rewrite of existing rows), write-time annotation resolved from the session identity (agentPreset + workspace registry lookup with header-cwd fallback, never blocks the write), and the dedupe key extended from (type, title) to include the scope triple. All behind scopeEnabled (default off).

变更点

  • store:memories 四列可空迁移(只 ADD COLUMN、无 DEFAULT → 存量行零重写,NULL=未标注=全局可见);save 写入归一化(非空 trim 字符串收下,脏值落 NULL 绝不阻塞);occurred_at 归一 UTC ISO(A2 时间过滤按字典序比较);update 路径不触碰 scope 列(写入时标注,落库后不可变)
  • scope(新模块 src/scope.js):createScopeResolver —— agent_scope = session header 的 agentPreset(requestHeader() 优先、静态 .header 兜底);workspace_scope 先走 ctx.workspaceRegistry 按 session.id 反查 canonical path,失败回退 header.cwd,再失败留 NULL;全程 try/catch,registry 故障 warn 一次后降级——绝不让 scope 解析阻断写入
  • service:saveWithDedupe 透传标注;去重键 (type, title) → (type, title, agent_scope, workspace_scope, sensitivity),NULL 归一为未标注(未标注行互相匹配、与已标注行不匹配,存量行语义不变);autoSummarize 每个 turn/end 都触发且无产出上限——建议新增节流、条数上限与同会话主题抑制(实测单会话日铸 198 条) #127 的 _mergeInto 显式并入同样过 scope 门,跨作用域语义相似回落独立新行(防合并泄漏)
  • tools:memory_save 接 exec.agent.session 上下文;新增可选参数 sensitivity / occurred_at;agent_scope/workspace_scope 由会话身份解析,不作为模型参数暴露
  • config/settings:scopeEnabled 默认关 + FEATURE_FLAG_BOOLEANS 白名单(面板可启停=线上回滚开关)

测试

  • 新增 test/scope-storage.test.js 16 项:迁移列形态、存量形状读回、归一化脏值、update 不可变、flag 关=旧去重、flag 开=三元组隔离与 NULL 匹配、_mergeInto 跨 scope 拒绝、解析器降级矩阵、memory_save 端到端接线
  • /features effective 键数断言 49 → 50
  • 全量 949 项:948 pass / 0 fail / 1 skip(既有 skip);check-sync src↔lib 一致

边界说明(给 reviewer)

  1. subagent 继承(issue [Feature Request] 按 agent 与 workspace 隔离记忆:专属记忆 + 全局共享记忆并存 #17 第 7 条)本 PR 未实现——A1 按会话自身 header 落标注;继承策略(读父会话 header)需要宿主持久化访问,随 A3 的 agent 可见性语义一起做。
  2. mirror 分域路径(issue [Feature Request] 按 agent 与 workspace 隔离记忆:专属记忆 + 全局共享记忆并存 #17 第 6 条 scoped/<agent>/<workspace>/)不在 A1 范围;当前带 scope 行仍渲染平铺目录,内容与现行为一致。
  3. dream 只合并同 scope(issue [Feature Request] 按 agent 与 workspace 隔离记忆:专属记忆 + 全局共享记忆并存 #17 第 5 条)的候选集门控随 dream 侧批次做;本 PR 已保证去重入口跨 scope 不合并。
  4. sensitivity 为自由文本标签(存储层不枚举校验),取值语义留给 A2/A3 的可见性规则定义。

v0.8.0 批次 A 第 1 个 PR:scope 隔离的地基——存储层纯增量,feature flag
默认关,关闭时行为与改动前逐字节一致(检索加权/过滤在 A2/A3,面板在 A4)。

- store:memories 新增四列可空迁移 agent_scope/workspace_scope/sensitivity/
  occurred_at(只 ADD COLUMN、不带 DEFAULT,存量行零重写,读侧 NULL=未标注
  =全局可见);save 写入归一化(非空 trim 字符串收下,脏值落 NULL 绝不阻塞
  写入);occurred_at 可解析时间戳统一归一 UTC ISO(A2 时间过滤按字典序比较);
  update/compareAndUpdate 不触碰 scope 列(写入时标注,落库后不可变)
- scope(新模块):写入端解析器 createScopeResolver——agent_scope 取 session
  header 的 agentPreset(requestHeader() 优先、静态 .header 兜底);workspace
  先走 ctx.workspaceRegistry 按 session.id 反查 canonical path,失败回退
  header.cwd,再失败留 NULL;全程 try/catch,registry 故障 warn 一次后降级,
  绝不让 scope 解析阻断写入
- service:saveWithDedupe 透传 scope 标注;去重键由 (type, title) 扩展为
  (type, title, agent_scope, workspace_scope, sensitivity)——不同作用域的同
  标题记忆绝不互相物理合并(NULL 归一为未标注,未标注行互相匹配、与已标注
  行不匹配);#127 的 _mergeInto 显式并入目标同样过 scope 门,跨作用域语义
  相似回落为独立新行,防合并泄漏
- tools:memory_save 接 exec 上下文(exec.agent.session),新增可选参数
  sensitivity / occurred_at;agent_scope/workspace_scope 由会话身份解析,
  不作为模型参数暴露
- config/settings:scopeEnabled 默认关,进 FEATURE_FLAG_BOOLEANS 白名单
  (面板可启停=线上回滚开关)

测试 +16:迁移列形态(可空/无 DEFAULT)、存量形状读回、归一化脏值、update
不可变、flag 关=旧去重、flag 开=三元组隔离与 NULL 匹配语义、_mergeInto 跨
scope 拒绝、解析器降级矩阵(registry 命中/未命中/抛错/无 session/旧宿主)、
memory_save 端到端接线(含 flag 关不标注)。/features effective 键数 49→50。

Refs #17(A1/4,后续 A2 检索加权、A3 strictScope、A4 面板分开提交)
Copilot AI lite review requested due to automatic review settings September 12, 2026 22:36

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Copilot was unable to review this pull request because the user who requested the review has reached their quota limit.

@coderabbitai

coderabbitai Bot commented Sep 12, 2026 •

Copy link
Copy Markdown

Warning

Review limit reached

Next included review available in 12 minutes.

Check out review usage here.

View limit details

Limit details: You’ve used the included review currently available.

You've used all free OSS reviews for now. Wait for the free limit to reset to keep reviewing this public repository.

Learn how review limits work.

Review configuration:

⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Advanced

Run ID: 49c8296c-592e-4eba-8d94-1a609edb01c3

📥 Commits

Reviewing files that changed from the base of the PR and between 6bc3117 and 2e600e5.

📒 Files selected for processing (14)
  • dsh-mneme/lib/config.js
  • dsh-mneme/lib/scope.js
  • dsh-mneme/lib/service.js
  • dsh-mneme/lib/settings.js
  • dsh-mneme/lib/store.js
  • dsh-mneme/lib/tools.js
  • dsh-mneme/src/config.js
  • dsh-mneme/src/scope.js
  • dsh-mneme/src/service.js
  • dsh-mneme/src/settings.js
  • dsh-mneme/src/store.js
  • dsh-mneme/src/tools.js
  • dsh-mneme/test/api.test.js
  • dsh-mneme/test/scope-storage.test.js

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@codecov

codecov Bot commented Sep 12, 2026 •

Copy link
Copy Markdown

Codecov Report

❌ Patch coverage is 96.61017% with 6 lines in your changes missing coverage. Please review.

Files with missing lines Patch % Lines
dsh-mneme/src/scope.js 92.40% 6 Missing ⚠️

📢 Thoughts on this report? Let us know!

@modusensus

modusensus commented Sep 12, 2026 •

Copy link
Copy Markdown
Member Author

@coderabbitai full review

@coderabbitai

coderabbitai Bot commented Sep 12, 2026 •

Copy link
Copy Markdown
⚠️ Action not completed

Review rate limited.


Your included review limit is currently reached under our Fair Usage Limits Policy. This review may still proceed through usage-based billing if eligible. Your next included review will be available in 52 minutes.

Copilot AI review requested due to automatic review settings September 12, 2026 22:50

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Copilot was unable to review this pull request because the user who requested the review has reached their quota limit.

Copilot AI review requested due to automatic review settings September 12, 2026 23:20

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Copilot was unable to review this pull request because the user who requested the review has reached their quota limit.

@modusensus
modusensus merged commit 0e5081b into main Sep 12, 2026
9 checks passed
modusensus added a commit that referenced this pull request Sep 13, 2026
v0.8.0 批次 A 第 2 个 PR,接在 #153(A1 存储层)之后:检索侧软隔离。
scopeEnabled 关闭或调用方未提供会话 scope 时,检索行为与 A2 前逐字节一致。

- service.searchMemories:新增 options.scope(工具层从 exec.agent.session 解析
  后传入)——当前会话 scope 两维命中的候选 ×1.25 加成,带他 scope 的候选 ×0.5
  降权但保留可见(硬过滤是 A3 strictScope);未标注行(NULL)与无法比较的维度
  恒中性,全局/存量记忆不因加权掉位。系数为模块常量,数值等线上反馈再调
- occurred_at 时间窗:store.list/count 新增 occurredFrom/occurredTo 闭区间
  (与 updated_at 共用 updatedAtBounds 归一化,date-only 含当日);按
  COALESCE(occurred_at, created_at) 比较——未标注行回退创建时间,过滤器对
  存量库可用;搜索路径在融合池上先滤再 dedup/slice,rerank 只看窗内候选,
  list 与 count 同口径保证分页 total 与行一致
- tools:memory_search / memory_list 新增可选 occurred_from / occurred_to
  参数;memory_search 接 exec 做会话 scope 加权;三个检索工具的输出 schema
  与 render 透出 agent_scope/workspace_scope/sensitivity/occurred_at(provenance
  附加段只在有标注时出现);toApiList 条件展开——未标注行 DTO 与 A2 前同形
- updatedAtBounds 从 store.js 导出复用(搜索后置过滤与 SQL 过滤共用边界归一)

测试 +13(store/service 透传、搜索窗、加权翻转/中性/flag 关、toApiList 形状、
memory_search/list/get 工具接线),全量 962 项 961 绿 / 1 既有 skip。

Refs #17(A2/4)
modusensus added a commit that referenced this pull request Sep 13, 2026
#153 观察 1:tools.js/inject.js 的 createScopeResolver 补传 logger: ctx.logger,registry 反查失败时 warnOnce 才有出口(否则静默降级无观测)。观察 2(workspaceRegistry 经 cordis Proxy 访问可能抛错)已有 try/catch 兜底降级 header.cwd,维持现状。观察 3:scopeMultiplier 实际语义=只有确立 foreign(记忆带标注+当前维度可解析+值不等)才吃 ×0.5,未标注行与命中行同列吃 BOOST ×1.25 而非 ×1 中性——常量注释、searchMemories 注释与测试标题三处对齐(行为不变,仅注释与标题)。
modusensus added a commit that referenced this pull request Sep 13, 2026
#153 观察 1:tools.js/inject.js 的 createScopeResolver 补传 logger: ctx.logger,registry 反查失败时 warnOnce 才有出口(否则静默降级无观测)。观察 2(workspaceRegistry 经 cordis Proxy 访问可能抛错)已有 try/catch 兜底降级 header.cwd,维持现状。观察 3:scopeMultiplier 实际语义=只有确立 foreign(记忆带标注+当前维度可解析+值不等)才吃 ×0.5,未标注行与命中行同列吃 BOOST ×1.25 而非 ×1 中性——常量注释、searchMemories 注释与测试标题三处对齐(行为不变,仅注释与标题)。
modusensus added a commit that referenced this pull request Sep 13, 2026
* feat(scope): strictScope 硬过滤与注入侧隔离(A3,issue #17)

v0.8.0 批次 A 第 3 个 PR,接在 #155(A2 检索加权)之后。strictScope 关闭时
维持 A2 软隔离(他 scope 降权保留可见);开启后按 issue #17 四象限可见性公式
硬过滤——带他 scope 的记忆在检索、注入、浏览、单取四条用户面路径完全不可见。

- config/settings:新增 strictScope(默认关,进 feature_flags 白名单)。独立于
  scopeEnabled 成键:可先开标注积累数据、观察 A2 加权质量后再切硬过滤。
- service.isVisibleInScope(新导出谓词):可见 ⇔ (agent 维未标注或命中当前
  agent) AND (workspace 维未标注或命中当前 workspace);当前会话某维度解析不到
  时该维度带标注的记忆一律不可见(fail-closed:身份不明只见全局)。sensitivity
  为标签不参与可见性判定。
- searchMemories:strict 开启时在融合池先硬过滤(他 scope 出局)再走 occurred
  窗/dedup/rerank;与 A2 加权叠加——过滤后剩下的命中行仍吃加成。
- injectCandidates:新增 options.scope,strict 开启时注入候选同口径硬过滤——
  scoped 记忆泄进无关注入上下文是最典型的越权通道,仅过滤检索挡不住这里;
  inject.js 在渲染回调按 ctx(agent.session,与工具 exec 同形)解析 scope 传入。
- store.list/count:新增 visibility 选项(SQL 侧与谓词同口径:未标注 NULL 恒
  可见;维度解析不到只放行未标注行),memory_list 分页 total 与行一致;仅显式
  传参的用户面调用过滤,dream/质量过滤等内部 store.list 不受影响。
- tools:memory_get strict 下他 scope 的行按不存在处理(无存在性泄漏);
  memory_list 的 list/count 同口径过滤。
- /features effective 键数 50→51。

测试 +9(四象限语义、匿名 fail-closed、搜索硬过滤、strict 关= A2 行为、SQL
过滤与 total 一致、注入过滤、memory_get 存在性泄漏/行主可取、memory_list
过滤与 total),全量 971 项 970 绿 / 1 既有 skip。

Refs #17(A3/4,剩 A4 面板)

* fix(scope): review 观察点——resolver 透传 logger、scopeMultiplier 注释对齐实际语义

#153 观察 1:tools.js/inject.js 的 createScopeResolver 补传 logger: ctx.logger,registry 反查失败时 warnOnce 才有出口(否则静默降级无观测)。观察 2(workspaceRegistry 经 cordis Proxy 访问可能抛错)已有 try/catch 兜底降级 header.cwd,维持现状。观察 3:scopeMultiplier 实际语义=只有确立 foreign(记忆带标注+当前维度可解析+值不等)才吃 ×0.5,未标注行与命中行同列吃 BOOST ×1.25 而非 ×1 中性——常量注释、searchMemories 注释与测试标题三处对齐(行为不变,仅注释与标题)。
modusensus added a commit that referenced this pull request Sep 13, 2026
* feat(scope): strictScope 硬过滤与注入侧隔离(A3,issue #17)

v0.8.0 批次 A 第 3 个 PR,接在 #155(A2 检索加权)之后。strictScope 关闭时
维持 A2 软隔离(他 scope 降权保留可见);开启后按 issue #17 四象限可见性公式
硬过滤——带他 scope 的记忆在检索、注入、浏览、单取四条用户面路径完全不可见。

- config/settings:新增 strictScope(默认关,进 feature_flags 白名单)。独立于
  scopeEnabled 成键:可先开标注积累数据、观察 A2 加权质量后再切硬过滤。
- service.isVisibleInScope(新导出谓词):可见 ⇔ (agent 维未标注或命中当前
  agent) AND (workspace 维未标注或命中当前 workspace);当前会话某维度解析不到
  时该维度带标注的记忆一律不可见(fail-closed:身份不明只见全局)。sensitivity
  为标签不参与可见性判定。
- searchMemories:strict 开启时在融合池先硬过滤(他 scope 出局)再走 occurred
  窗/dedup/rerank;与 A2 加权叠加——过滤后剩下的命中行仍吃加成。
- injectCandidates:新增 options.scope,strict 开启时注入候选同口径硬过滤——
  scoped 记忆泄进无关注入上下文是最典型的越权通道,仅过滤检索挡不住这里;
  inject.js 在渲染回调按 ctx(agent.session,与工具 exec 同形)解析 scope 传入。
- store.list/count:新增 visibility 选项(SQL 侧与谓词同口径:未标注 NULL 恒
  可见;维度解析不到只放行未标注行),memory_list 分页 total 与行一致;仅显式
  传参的用户面调用过滤,dream/质量过滤等内部 store.list 不受影响。
- tools:memory_get strict 下他 scope 的行按不存在处理(无存在性泄漏);
  memory_list 的 list/count 同口径过滤。
- /features effective 键数 50→51。

测试 +9(四象限语义、匿名 fail-closed、搜索硬过滤、strict 关= A2 行为、SQL
过滤与 total 一致、注入过滤、memory_get 存在性泄漏/行主可取、memory_list
过滤与 total),全量 971 项 970 绿 / 1 既有 skip。

Refs #17(A3/4,剩 A4 面板)

* fix(scope): review 观察点——resolver 透传 logger、scopeMultiplier 注释对齐实际语义

#153 观察 1:tools.js/inject.js 的 createScopeResolver 补传 logger: ctx.logger,registry 反查失败时 warnOnce 才有出口(否则静默降级无观测)。观察 2(workspaceRegistry 经 cordis Proxy 访问可能抛错)已有 try/catch 兜底降级 header.cwd,维持现状。观察 3:scopeMultiplier 实际语义=只有确立 foreign(记忆带标注+当前维度可解析+值不等)才吃 ×0.5,未标注行与命中行同列吃 BOOST ×1.25 而非 ×1 中性——常量注释、searchMemories 注释与测试标题三处对齐(行为不变,仅注释与标题)。

* feat(scope): 面板显示与开关(A4,issue #17)

v0.8.0 批次 A 收官:scope 隔离的面板面。纯前端(lib/client.js,手写不随
sync 覆盖),后端零改动——/features 与 /list 已在 A1-A3 透出所需数据,
未标注行字段缺省即不渲染,前端不感知开关状态(与 heat 徽章同一模式)。

- 设置卡新增「作用域隔离」组:scopeEnabled(作用域标注总开关)与
  strictScope(严格隔离硬过滤)两个开关,i18n 中英双语齐全;开关渲染走
  /features effective + PUT 增量提交,与既有布尔开关同一套 FeatureRow。
- 记忆条目 provenance 展示:
  - 详情抽屉 dmeta 新增四行:发生时间(occurred_at,按日期短格式渲染)、
    Agent 作用域、工作区作用域、敏感度——仅在字段存在时出现。
  - cards 视图脚部与 timeline 行接入 ScopeBadge 徽章(business-primary
    色调,tooltip 展示完整 agent/workspace/sensitivity 归属),未标注条目
    视觉零变化。
- 测试:client.test.js 新增「A4 面板开关与 provenance 展示」断言(分组、
  十个 i18n 键双语齐全、ScopeBadge 组件与三处接线),全量 972 项 971 绿 /
  1 既有 skip。

Refs #17(A4/4,批次 A 完结)

* docs(client): ScopeBadge 与 A4 测试补 JSDoc(CodeRabbit docstring 覆盖率警告)

* fix(client): ScopeBadge tooltip 本地化——标签复用详情抽屉 i18n 键(云端复验观察点)
@modusensus
modusensus deleted the feat/scope-storage-a1 branch September 13, 2026 14:37
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants