Repository navigation
feat(provenance): 溯源读出口补上方向 2——按 session_id 列该会话的蒸馏窗口(#524) - #546
Conversation
#421 把溯源读出口拆成两个方向:方向 1(记忆 → 窗口 → 蒸馏原文)由 #509 交付, 方向 2(会话 → 它产出的蒸馏窗口)一直缺着。底下其实早就齐了:memory_provenance 自 #399 就在写、idx_memory_provenance_session 自那时就建着——缺的只是入参方向, parseProvenanceQuery 只认 ?id=<memoryId>,session_id 只在响应里躺着。 复用同一条路径而不是新开一条:多一条路径就多四处要登记的地方(SECURITY.md 两张 表、包 README 路由表、security-doc 的清单锁),而两个方向读的是同一批数据,只是 入口不同;SECURITY.md 只登记路径不登记 query 形状,所以方向 2 在那两张表里一行 都不用加。 两个主键互斥:都缺 400 missing-id、都给 400 ambiguous-id。刻意不做「都给则择 一」——择一意味着调用方可以发一个自己也不知道会被读哪个主键的请求,而两个方向的 答复形状不同,那种静默选择只会在出事之后才被发现。 limit 不是可选的礼貌参数,是这条方向的前置条件:按会话读是这张脸里天然最容易放 大的方向(一个会话几十个窗口、每个窗口都是整段逐字原文),不限量就是「按会话导出 全量转录」。默认 20、上限 100,只收十进制整数字面量——不走 Number(),因为它把 "" / " " / 0x10 / 1e3 都化成数,于是 ?limit= 会静默变成 0 个窗口。撞上限时答复带 truncated:少了它,被截断的答复与「本来就只有这么多」逐字节相同。实现上 session 侧向 store 要 limit + 1 行、多出来那条只当探针不出口。 方向 2 不能逐链接返回:memory_provenance 的粒度是「一条记忆 → 一个窗口」,而一次 蒸馏窗口通常产出多条记忆,照原样列会让「这个会话蒸了几次」被重复行淹没。新增 store.distillWindowsFor 走 GROUP BY session_id, seq_start, seq_end,带 COUNT(*) AS link_count;ORDER BY seq_start 而不是 created_at(seq 是会话内的先后)。 window_id 也不能当分组键——它是逐条记录生成的 session:<id>:<seq>,分组会退化成 列原文。 503 改成按方向判:REQUIRED_METHODS 分 memory / session 两套,只缺 session 那侧 方法时方向 1 仍然 200——把一个方向的问题报成整张脸坏了,会让人去查一个没坏的部署。 provenanceReply 的入参从 {service, id, config, warn} 改成 {service, selector, config, warn},selector 由 parseProvenanceSelector 产出,两个壳都换成它,静态锁的 regex 同步改成 selector: parsed.selector。 回归测试 +11(provenance-http:两个主键都缺/都给/裁空白、limit 十二种畸形与越界、 session 方向一行一窗口 + link_count + 顺序、两方向各自的 truncated、503 按方向判、 session 方向开关关也 409 且零 SQL)、+3(api:GROUP BY 并行 + link_count=2 + 跨会话 不串、两主键都给 400、limit=0 400 与 limit=2 truncated)、+2(standalone-api: ?sessionId= 列出窗口、两主键都给 400 且 limit 六种畸形全 400)。
There was a problem hiding this comment.
Copilot was unable to review this pull request because the user who requested the review has insufficient remaining quota.
An organization owner can choose the repository organization as the billing source for reviews requested by members with a paid Copilot license. Learn about Copilot code review billing.
|
Warning Review limit reachedYou've used all free OSS reviews for now. Wait for the free limit to reset to keep reviewing this public repository. Next included review available in 33 minutes. View limit details
No actionable comments were generated in the recent review.
|
| Layer / File(s) | Summary |
|---|---|
会话窗口存储与服务 dsh-mneme/lib/store.js, dsh-mneme/src/store.js, dsh-mneme/lib/service.js, dsh-mneme/src/service.js |
新增按会话与序号区间聚合窗口的存储查询,返回最早创建时间和关联记忆数;服务对象新增对应的转发方法。 |
查询入口、响应与校验 dsh-mneme/lib/provenance-http.js, dsh-mneme/src/provenance-http.js, dsh-mneme/lib/api*.js, dsh-mneme/src/api*.js, dsh-mneme/test/*, dsh-mneme/README.md, dsh-mneme/docs/*, dsh-mneme/CHANGELOG.md, README.md |
入口将 id、sessionId 和 limit 交给共用选择器。共用模块校验互斥主键和 limit,按查询方向检查可用方法,并返回窗口及 truncated。测试和文档覆盖新增行为;测试数量说明更新为 2623。 |
Estimated code review effort: 3 (Moderate) | ~25 minutes
Change: Feature
Sequence Diagram(s)
sequenceDiagram
participant ApiRoute as API路由
participant Selector as parseProvenanceSelector
participant Reply as provenanceReply
participant Service as createService
participant Store as createStore
ApiRoute->>Selector: 解析 id、sessionId 和 limit
Selector-->>ApiRoute: 返回 selector
ApiRoute->>Reply: 传入 selector 和配置
Reply->>Service: 请求会话窗口
Service->>Store: 调用 distillWindowsFor
Store-->>Service: 返回聚合窗口
Service-->>Reply: 返回窗口数据
Reply-->>ApiRoute: 返回 sessionId、窗口和 truncated
Possibly related issues
slow-stack/mneme#524:该 issue 要求增加会话维度溯源读取,并设置结果上限;本次变更实现了会话查询、limit限制和截断标记。
Possibly related PRs
- slow-stack/mneme#509:该 PR 首次加入溯源读出口和共用 HTTP 模块;本次变更扩展了同一接口和模块,增加会话查询方向。
Suggested reviewers: z2ace0107
Merge Risk: 
Minimal · previous review 2991b
-
The session query appears ready to merge after normal checks. No unresolved issue requiring a change was identified.
Pre-merge checks: 
4 · 
1
-
Failed checks: 1 warning Passed checks: 4 passedFull details: Docstring Coverage
-
Explanation
Docstring coverage is 66.67% which is insufficient. The required threshold is 80.00%. Docstring coverage is scoped to functions touched by this diff with cyclomatic complexity of at least 2. Documentation-only edits and deletions within surviving functions are included; unchanged diff context and fully deleted functions are excluded. Analyzed 15 functions across 13 files. (5 skipped: 5 unsupported.)
Resolution
Write docstrings for the functions missing them to satisfy the coverage threshold.
-
Finishing Touches
-
Generate docstrings
-
- Commit to this branch
- Create a new PR
Generate unit tests (beta)
-
- Commit to this branch
- Create a new PR
-
- Autofix · Keep fixing CodeRabbit findings and required CI, and resolving merge conflicts
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.
Codecov Report✅ All modified and coverable lines are covered by tests. 📢 Thoughts on this report? Let us know! |
There was a problem hiding this comment.
Copilot was unable to review this pull request because the user who requested the review has insufficient remaining quota.
An organization owner can choose the repository organization as the billing source for reviews requested by members with a paid Copilot license. Learn about Copilot code review billing.
这个 PR 修什么
#421 把溯源读出口拆成两个方向,方向 1(记忆 → 窗口 → 蒸馏原文)由 #509 交付,方向 2(会话 → 它产出的那些蒸馏窗口)一直缺着。
底下其实早就齐了:
memory_provenance自 #399 就在写,idx_memory_provenance_session自那时就建着。缺的只是入参方向——parseProvenanceQuery只认?id=<memoryId>,session_id只在响应里躺着。现在:
怎么修
存储侧新增
store.distillWindowsFor(sessionId, limit):不能逐链接返回:这张表的粒度是「一条记忆 → 一个窗口」,而一次蒸馏窗口通常产出多条记忆,照原样列会让「这个会话蒸了几次」这个唯一有意义的计数被重复行淹没。
link_count说明该窗口派生出几条记忆。两个分组键的选择都踩过坑:
window_id不能当分组键(它是逐条记录生成的session:<id>:<seq>,一行一个 seq,拿它分组会退化成「列原文」);ORDER BY seq_start而不是created_at(seq 是会话内的先后,按created_at排会把同一批重跑的行打散)。协议层(
src/provenance-http.js,两个壳共用的唯一一份)加了三个导出:parseProvenanceLimit、parseProvenanceSelector、两个常量。provenanceReply的入参从{service, id, config, warn}改成{service, selector, config, warn},两个壳都换成parseProvenanceSelector,静态锁的 regex 同步改成selector: parsed.selector。三处刻意的取舍
① 复用同一条路径,不新开一条。 多一条路径就多四处要登记的地方(
SECURITY.md两张表、包 README 路由表、test/security-doc.test.js的清单锁),而两个方向读的是同一批数据、只是入口不同。SECURITY.md只登记路径不登记 query 形状,所以方向 2 在那两张表里一行都不用加——这也正是「同一条路径」在文档面上的直接好处。② 两个主键互斥,不静默择一。 都缺
400 missing-id、都给400 ambiguous-id。择一意味着调用方可以发一个自己也不知道会被读哪个主键的请求,而两个方向的答复形状不同(memoryId/sessionId各认领自己那一侧)——那种静默选择只会在出事之后才被发现。③
limit是前置条件,不是礼貌参数。 按会话读是这张脸里天然最容易放大的方向:一个会话几十个窗口、每个窗口都是整段逐字原文,不限量就是「按会话导出全量转录」,与/export(一次拿全库)同量级只是换了形状,而它同样受门控。默认 20、上限 100;只收十进制整数字面量,""/" "/0x10/1e3/"+1"/"12abc"一律 400——走Number()的话?limit=会静默变成 0 个窗口,一个畸形输入拿到最坏解释(reclaim-http.js的parseReclaimQuery为同一理由立过这条规矩)。越界也给 400 而不截到 100:要 1000 个、实际给 100 还不吭声,比直接拒更糟。两处顺手改准的既有语义
truncated字段:少了它,被截断的答复与「本来就只有这么多」逐字节相同,调用方会把半份转录当成全部——那正是这张脸最容易骗人的地方。实现上 session 侧向 store 要limit + 1行、多出来那条只当探针不出口;memory 侧provenanceFor本来就全量返回,按长度判即可。store 侧只照 limit 取,不替调用方判断「还有没有」——那是协议层的事,判据只许有一份。503 改成按方向判:
REQUIRED_METHODS分memory: [provenanceFor, distillRecordsFor]/session: [distillWindowsFor, distillRecordsFor],只缺 session 那侧方法时方向 1 仍然 200。把一个方向的问题报成整张脸坏了,会让人去查一个没坏的部署。409 与 503 的分工不动:前者是「用户关了distillRecords.enabled」,后者是「装配没接线」。回归测试 +16
test/provenance-http.test.js+11(21 条全绿):两个主键都缺 / 都给 / 裁空白、limit十二种畸形与越界、session 方向一行一窗口 +link_count+ 顺序、两个方向各自的truncated、503 按方向判(只缺 session 方法时 memory 仍 200)、session 方向开关关也 409 且零 SQL。test/api.test.js+3:GROUP BY并行 +link_count=2+ 跨会话不串、两主键都给 400ambiguous-id、limit=0400 与limit=2truncated。test/standalone-api.test.js+2:?sessionId=列出窗口、两主键都给 400 且limit六种畸形全 400。验收
npm testnpm run syncnode scripts/check-sync.jsCo-Authored-By、无 "Generated with"文档
四处 + CHANGELOG,都写清了「为什么」而不只是「是什么」:
dsh-mneme/README.md路由表:方法栏补?sessionId=与&limit=,说明栏补两方向共用路径、互斥 400、GROUP BY+link_count、truncated、503 按方向判;dsh-mneme/docs/DISTILL.md§10:新增「两个读方向共用同一条路径」「为什么不新开一条路径」「limit 与 truncated」三段,状态码表补ambiguous-id与invalid-limit两行;dsh-mneme/docs/DAEMON.md:路由面与状态码阶梯同步,并补一整段方向说明;dsh-mneme/CHANGELOG.md:[Unreleased] / 🆕 新增段首。SECURITY.md一处都没动——路径没变,两张清单按 path 比对,方向 2 不需要新增登记行。给报告者
@modusensus 这条是你在 #524 里自己拆出来的(原文四件事:入参形状 / limit / 门与状态码 / 文档登记),四件都按你列的次序做了,逐条对应在上面「三处刻意的取舍」与「两处顺手改准的既有语义」里。
第 ① 件你留的是开放项(「都给 → 400 还是择一,须写死」)——我写死成 400
ambiguous-id,理由见上。第 ② 件你只说「必须有 limit」,我把默认值与上界也一起定死了(20 / 100),并且把「截断必须说出来」当成同一条诉求的组成部分,而不是可选的礼貌。#524关不关留给你——如果你在 #524 里还有第 5 件事想加,这条可以先不合。Summary by CodeRabbit