stratagate-dsh 0.3.7 → 0.3.8

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1,51 +1,51 @@
1
- # 记忆目录与主题整合
2
-
3
- 本次实现两项能力:默认可见的记忆目录,以及按需展开的跨事件主题概览。经验提炼不在本次范围内。
4
-
5
- ## 使用方式
6
-
7
- - 用户画像继续单独常驻。默认目录提供 Chapter 标题、description 和按稳定顺序排列的 Section 标题,并保留主题编号;不注入 `.0` / overview 正文。
8
- - 目录只用于导航;主题概览把已有事件整理为背景、进展、决定、变化和待确认问题,每段保留事件来源。
9
- - 一个 Topic 对应长期的大章节,例如“StrataGate”“求职与职业发展”。节是能持续容纳同类事件的长期类别,例如“缺陷排查与修复”“版本发布与安装”“架构与配置决策”;单个 bug、版本、日期、任务和处理状态留在节内总览与原事件,不独立成节。已有类别能容纳时复用原标题,同类不同状态或不同版本不再拆节。分类随章的实际内容归纳,不套全局固定表,不设硬节数上限;归类不改变任何事件事实。
10
- - 小节归属单独保存在 `sections` 的标题与事件编号中;总览只概括内容并保留各段自己的证据引用。同一章内同名小节及总览按全半角、大小写和空白规范化匹配,与段落类型无关。新总览的展示标题必须匹配本轮声明或继承的小节;省略标题时,其类型对应的默认名称也必须匹配,模型解析和显式 `sections` 写入共用同一校验。总览不能自行建立无事件的小节;旧快照及无 `sections` 的旧 SDK 调用仍按来源和类型名称恢复,有效旧总览可原样保留。节的 `.0 总览` 按各段最早来源在章节中的位置排序并原样展示内容,同位置按最晚来源位置及稳定内容排序;`.1~N` 分页展示归入该节的事件,不要求总览引用每条事件。没有总览的小节仍展示事件,界面不显示空的 `.0 总览`。
11
- - 新模型结果必须为每条本批章节成员分配至少一个小节;总览可为空,旧小节归属和有效概要由存储层继承。只有本批事件可按显式新归属重新分类;非本批旧事件确认某条关系时,保留其其他小节归属。存储层先确定最终小节,再处理总览:重分类使旧小节没有事件时,丢弃对应旧总览,包括本轮原样回传的旧段;新总览指向已消失的小节则拒绝整次写入。小节仍有成员时继续保留有效旧总览,不为保存总览恢复已移走的事件归属。界面“待归类事件”只包含本章尚无小节归属的事件,与未被概括的事件数量分别计算。旧快照按已有总览来源恢复确定的小节归属;0.3.3 首次 writer 打开时,为已完成整理但仍缺少小节关系的旧事件排队一次定向补归类,包括此前已持久化 `sections` 的候选数据。补归类按原章分批,只更新该章的小节成员关系,保留章 ID、章名、描述、成员顺序、已知归属和有效总览,不重新提取事件。某事件属于多个章时逐章补齐;没有总览也必须写入真实归属。迁移标记及剩余关系持久化,重启不反复排队;只读访问不启动补归类。旧 SDK 调用缺少 `sections` 时仍兼容普通整理,补归类任务必须提供显式 `sections`。
12
- - 旧事件补归类复用历史整理后台,全库每 10 分钟最多 2 个历史任务,不重置已有额度;新增或修改的事件仍走优先增量路径。模型不可用或额度耗尽时暂留待归类,后台恢复后继续。工作单位是“章节、事件、来源版本”的关系:一个章节等待重试或耗尽重试不会阻止其他章节补齐同一事件。每个任务最多 3 次尝试,失败可通过现有“重新整理”入口发起新的有限周期;重启不会自动清零重试。目录保留未完成关系数及失败关系数,不把多个章节的关系压成一个事件来判断结算;仍有其他关系待处理时显示处理中,只剩终态失败关系时返回 `failed` 并显示未完成和重新整理入口,不报全部完成,也不保持正在处理的轮询状态。遗忘、归档或来源修改会撤销旧版本的补归类关系及过期结果。为控制输入,补归类候选省略旧总览,最多显示 120 个且合计不超过 4,000 字符的完整小节标题,明确提供省略数量;原章必须在实际模型输入中,不能静默裁掉或改分到其他章。
13
- - 小节按其成员在章内成员列表中的最早位置排序,不跟随模型输出段落的先后顺序;同位置用稳定节编号排序。已有成员在前、新事件追加在后,因此新事件形成的新节置后,旧节不会因为新总览前置而改号。更新后的目录视图版本使旧编号及分页缓存失效。
14
- - 主模型按需打开主题,再通过现有事件、图谱或原文工具取证,继续使用现有证据检查与采用流程。
15
- - 现有自动召回继续工作,目录与概览不能成为唯一检索入口。
16
-
17
- 工具按需要选择:`memory_list_topics` 浏览或查询目录;需要主题脉络时用 `memory_expand_topic` 查看概览,需要事实证据时可直接用 `memory_search_events(query, topic_id)` 核实事件,再进入既有证据评估与采用流程。前两个工具不生成证据批次。空查询可浏览主题事件,使用返回的 `nextOffset` 继续分页;`temporalIntent` 可选择最早或最新记录。
18
-
19
- ## 范围与维护
20
-
21
- - 目录覆盖当前命名空间内可见的对话事件和主动记忆,含没有图谱节点的事件。
22
- - 图谱展示聚类只是可选分组线索,不能将不相连节点的展示拼组当作语义主题。
23
- - 后台用已有事件分批整理历史,后续只处理内容、状态或关联变化。检索时间、采用次数和衰减不触发重新生成。
24
- - 首次写连接打开命名空间时,固定已有历史事件的版本清单,持久记录“待处理 → 处理中 → 已完成”;新命名空间冻结空集合并直接完成,随后新增事件都按增量处理。关闭或重启后接着处理未完成批次,已成功批次和主题编号保留;整理器版本升级时才开启新的回填清单。并发打开沿用先成功保存的清单,只读访问不初始化、不迁移。
25
- - 整个数据库的历史回填每 10 分钟最多启动 2 批,每批最多 12 条事件。额度在调用前持久预扣,各命名空间共用,重启不重置,失败重试也占额度;达到上限后保留简略入口,下一窗口继续。这个上限约束后台整理任务,模型桥内部的格式重试和适配器降级仍分别有固定上限,并不承诺固定金额。新增或语义变化的事件优先整理,不占历史额度。旧章因某条来源或背景依赖变化而整章失效时,其余未变化成员的重建必须共用这份历史额度,不能变成无限制增量任务。重建版本单独持久记录,不改写首次打开冻结的历史清单;旧测试版已失效的积压也保守归入历史额度。
26
- - 每轮最多尝试 3 次,失败等待至少 30 / 60 秒,历史额度不足时等待更久。用尽次数后停止自动重试。用户可在历史整理的失败详情中选择“重新整理这 N 条”:仅将该批当前有效来源排队为新一轮,仍占共享历史额度;成功批次不重做。来源变化、遗忘、过期目录及重复提交均不能强行复用旧失败;新任务编号拒绝旧结果。排队和进度持久保存,重启不重置预算。“已完成”表示本轮任务已结算,不代表所有批次成功。
27
- - 本次主题整理器升级到第 3 代。首次写连接打开第 2 代目录时,保留来源及依赖仍有效的章 ID、章名、成员顺序和创建时间,清空旧细节小节与旧派生任务/进度,冻结当时可见事件按新规则重新分批整理;节及节内编号会因本次重新分组更新。第 1 代碎章及混合/未知代目录仍整体退休,依赖已变化或隐藏的旧章语言不沿用。全程不修改事件、原文、图谱或采用记录,也不重置全库历史额度;新增及发生变化的事件继续优先。只读访问仅在内存预览:保留有效第 2 代章的导航,隐藏旧小节并保留事件入口;不启动历史整理、不写库。第 1 代旧目录仍隐藏。第 3 代成功进度和编号在重启后保留,不反复重建。
28
- - 旧章候选仍最多 12 个,排序结合全部已有节标题以及少量成员标题和标签。每个已展示候选提供全部轻量节标题、最多 4 段正文;节标题不授予未展示事件的引用权限。提示要求可容纳新事项时逐字复用已有节标题,不近义改名。同名章在已展示候选中唯一匹配时复用编号;全局已有同名正式章但未展示时拒绝结果,不静默创建重复章,显式改名也不能撞上另一章;不同项目仍独立归类,不引入永久跨章合并机制。
29
- - 失效只标记一次。模型遗漏主题编号时,存储层为明确的成员延续复用编号;无法唯一对应的旧失效主题,在所有仍可见成员成功处理后移除。分批成功进度不会被旧主题再次清零,过期模型结果仍拒绝。
30
- - 每章每次模型响应最多 8 段概要;这限制单次输出,不是累计段数或节数上限。有效旧段自动保留,不被新段挤掉;同名段仍聚合成一个节。章节累计内容与全量 JSON 存储的增量化另行跟踪。
31
- - 每批模型输入及输出有固定上限,调用有超时、有限重试和重启恢复;主模型上下文组装只读取目录。
32
- - 尚未整理和暂时失败的事件仍提供可验证的简略入口,不阻塞普通检索。
33
- - 每批最多整理 12 个事件,候选旧主题最多 12 个,模型输入含结构约束不超过约 20,000 词元。每段概览注明来源;主题展开限制约 2,400 词元。展开结果优先保留轻量 `sections` 索引(标题和 `sourceEventCount`),包括无总览的小节,并用 `totalSections`、`omittedSections` 说明省略范围;索引、概要、省略计数和外层响应共用预算。全量小节成员关系只在服务端分页,不加入模型展开结果。
34
- - 主题目录按偏好与要求、决定与计划、工作与结果、交流与协作、其他经历分类;分类仅用于浏览,不改变主题内容和编号。完整目录每页最多 20 项。
35
- - 正式主题按创建时间从早到晚排列,新增主题追加;同一时刻仅以不可变的主题编号排序,改名不改变章序。注入目录、主题工具与界面共用这一顺序,待整理入口置后,展示章号不写入数据库。
36
- - Dashboard 只返回主题、节、总览段落及事件数量,不返回事件成员编号、全量标题或摘要;Bootstrap 失败详情也只传数量。完整成员关系保留在服务端。节编号由规范化标题派生,界面与分页共用同一聚合规则。展开节、待整理或失败详情时,用只读接口每页最多读取 9 条事件;数据版本变化时丢弃旧页。同类型但不同标题仍是不同节,同名段落合为一个节。
37
- - 目录默认预算不超过 400 个估算词元,原相关记忆预算为 900 词元。超预算时先预留分类、`memory_list_topics(category, offset)` 分页和 `memory_expand_topic(id)` 小节入口;优先保留章标题与 description,再逐轮为各章加入小节标题。章信息仍放不下时优先保留各分类的章入口,必要时省略 description;全部输出共用预算,未展示的章和小节可继续按需浏览。
38
-
39
- ## 必须始终成立
40
-
41
- 1. 事件和原文是证据底座,目录与概览不写回为新事件,不登记采用证据,不强化记忆。
42
- 2. 主题编号独立于展示聚类成员;每条可见目录文字和概览都有可验证的来源依赖。
43
- 3. 来源被遗忘、归档、撤销或修改后,旧派生文字先停止曝光,后台再重建。不能通过原始对话重新总结来复活已隐藏的事件。
44
- 4. 模型结果提交前重新核对读取时的来源版本;过期任务不能覆盖新版主题。
45
- 5. 主题只在当前命名空间可见;安装级画像不自动并入项目主题。
46
- 6. 历史、计划、取消、争议和当前事实不能在整合时混为一谈;缺少信息保留为待确认问题。
47
- 7. 升级、失败和重启不会修改或删除已有事件、图谱和原始对话;目录可独立重建。
48
-
49
- ## 验收
50
-
51
- 验证模糊查询发现主题、无图谱事件覆盖、按主题取证、增量整合与稳定编号、隐藏来源即时失效、过期提交拒绝、零采用强化、命名空间隔离、旧库升级、重启恢复、有限重试、输入和目录预算,以及后台失败时原搜索继续可用。测试只使用临时数据库与模拟模型。
1
+ # 记忆目录与主题整合
2
+
3
+ 本次实现两项能力:默认可见的记忆目录,以及按需展开的跨事件主题概览。经验提炼不在本次范围内。
4
+
5
+ ## 使用方式
6
+
7
+ - 用户画像继续单独常驻。默认目录提供 Chapter 标题、description 和按稳定顺序排列的 Section 标题,并保留主题编号;不注入 `.0` / overview 正文。
8
+ - 目录只用于导航;主题概览把已有事件整理为背景、进展、决定、变化和待确认问题,每段保留事件来源。
9
+ - 一个 Topic 对应长期的大章节,例如“StrataGate”“求职与职业发展”。节是能持续容纳同类事件的长期类别,例如“缺陷排查与修复”“版本发布与安装”“架构与配置决策”;单个 bug、版本、日期、任务和处理状态留在节内总览与原事件,不独立成节。已有类别能容纳时复用原标题,同类不同状态或不同版本不再拆节。分类随章的实际内容归纳,不套全局固定表,不设硬节数上限;归类不改变任何事件事实。
10
+ - 小节归属单独保存在 `sections` 的标题与事件编号中;总览只概括内容并保留各段自己的证据引用。同一章内同名小节及总览按全半角、大小写和空白规范化匹配,与段落类型无关。新总览的展示标题必须匹配本轮声明或继承的小节;省略标题时,其类型对应的默认名称也必须匹配,模型解析和显式 `sections` 写入共用同一校验。总览不能自行建立无事件的小节;旧快照及无 `sections` 的旧 SDK 调用仍按来源和类型名称恢复,有效旧总览可原样保留。节的 `.0 总览` 按各段最早来源在章节中的位置排序并原样展示内容,同位置按最晚来源位置及稳定内容排序;`.1~N` 分页展示归入该节的事件,不要求总览引用每条事件。没有总览的小节仍展示事件,界面不显示空的 `.0 总览`。
11
+ - 新模型结果必须为每条本批章节成员分配至少一个小节;总览可为空,旧小节归属和有效概要由存储层继承。只有本批事件可按显式新归属重新分类;非本批旧事件确认某条关系时,保留其其他小节归属。存储层先确定最终小节,再处理总览:重分类使旧小节没有事件时,丢弃对应旧总览,包括本轮原样回传的旧段;新总览指向已消失的小节则拒绝整次写入。小节仍有成员时继续保留有效旧总览,不为保存总览恢复已移走的事件归属。界面“待归类事件”只包含本章尚无小节归属的事件,与未被概括的事件数量分别计算。旧快照按已有总览来源恢复确定的小节归属;0.3.3 首次 writer 打开时,为已完成整理但仍缺少小节关系的旧事件排队一次定向补归类,包括此前已持久化 `sections` 的候选数据。补归类按原章分批,只更新该章的小节成员关系,保留章 ID、章名、描述、成员顺序、已知归属和有效总览,不重新提取事件。某事件属于多个章时逐章补齐;没有总览也必须写入真实归属。迁移标记及剩余关系持久化,重启不反复排队;只读访问不启动补归类。旧 SDK 调用缺少 `sections` 时仍兼容普通整理,补归类任务必须提供显式 `sections`。
12
+ - 旧事件补归类复用历史整理后台,全库每 10 分钟最多 2 个历史任务,不重置已有额度;新增或修改的事件仍走优先增量路径。模型不可用或额度耗尽时暂留待归类,后台恢复后继续。工作单位是“章节、事件、来源版本”的关系:一个章节等待重试或耗尽重试不会阻止其他章节补齐同一事件。每个任务最多 3 次尝试,失败可通过现有“重新整理”入口发起新的有限周期;重启不会自动清零重试。目录保留未完成关系数及失败关系数,不把多个章节的关系压成一个事件来判断结算;仍有其他关系待处理时显示处理中,只剩终态失败关系时返回 `failed` 并显示未完成和重新整理入口,不报全部完成,也不保持正在处理的轮询状态。遗忘、归档或来源修改会撤销旧版本的补归类关系及过期结果。为控制输入,补归类候选省略旧总览,最多显示 120 个且合计不超过 4,000 字符的完整小节标题,明确提供省略数量;原章必须在实际模型输入中,不能静默裁掉或改分到其他章。
13
+ - 小节按其成员在章内成员列表中的最早位置排序,不跟随模型输出段落的先后顺序;同位置用稳定节编号排序。已有成员在前、新事件追加在后,因此新事件形成的新节置后,旧节不会因为新总览前置而改号。更新后的目录视图版本使旧编号及分页缓存失效。
14
+ - 主模型按需打开主题,再通过现有事件、图谱或原文工具取证,继续使用现有证据检查与采用流程。
15
+ - 现有自动召回继续工作,目录与概览不能成为唯一检索入口。
16
+
17
+ 工具按需要选择:`memory_list_topics` 浏览或查询目录;需要主题脉络时用 `memory_expand_topic` 查看概览,需要事实证据时可直接用 `memory_search_events(query, topic_id)` 核实事件,再进入既有证据评估与采用流程。前两个工具不生成证据批次。空查询可浏览主题事件,使用返回的 `nextOffset` 继续分页;`temporalIntent` 可选择最早或最新记录。
18
+
19
+ ## 范围与维护
20
+
21
+ - 目录覆盖当前命名空间内可见的对话事件和主动记忆,含没有图谱节点的事件。
22
+ - 图谱展示聚类只是可选分组线索,不能将不相连节点的展示拼组当作语义主题。
23
+ - 后台用已有事件分批整理历史,后续只处理内容、状态或关联变化。检索时间、采用次数和衰减不触发重新生成。
24
+ - 首次写连接打开命名空间时,固定已有历史事件的版本清单,持久记录“待处理 → 处理中 → 已完成”;新命名空间冻结空集合并直接完成,随后新增事件都按增量处理。关闭或重启后接着处理未完成批次,已成功批次和主题编号保留;整理器版本升级时才开启新的回填清单。并发打开沿用先成功保存的清单,只读访问不初始化、不迁移。
25
+ - 整个数据库的历史回填每 10 分钟最多启动 2 批,每批最多 12 条事件。额度在调用前持久预扣,各命名空间共用,重启不重置,失败重试也占额度;达到上限后保留简略入口,下一窗口继续。这个上限约束后台整理任务,模型桥内部的格式重试和适配器降级仍分别有固定上限,并不承诺固定金额。新增或语义变化的事件优先整理,不占历史额度。旧章因某条来源或背景依赖变化而整章失效时,其余未变化成员的重建必须共用这份历史额度,不能变成无限制增量任务。重建版本单独持久记录,不改写首次打开冻结的历史清单;旧测试版已失效的积压也保守归入历史额度。
26
+ - 每轮最多尝试 3 次,失败等待至少 30 / 60 秒,历史额度不足时等待更久。用尽次数后停止自动重试。用户可在历史整理的失败详情中选择“重新整理这 N 条”:仅将该批当前有效来源排队为新一轮,仍占共享历史额度;成功批次不重做。来源变化、遗忘、过期目录及重复提交均不能强行复用旧失败;新任务编号拒绝旧结果。排队和进度持久保存,重启不重置预算。“已完成”表示本轮任务已结算,不代表所有批次成功。
27
+ - 本次主题整理器升级到第 3 代。首次写连接打开第 2 代目录时,保留来源及依赖仍有效的章 ID、章名、成员顺序和创建时间,清空旧细节小节与旧派生任务/进度,冻结当时可见事件按新规则重新分批整理;节及节内编号会因本次重新分组更新。第 1 代碎章及混合/未知代目录仍整体退休,依赖已变化或隐藏的旧章语言不沿用。全程不修改事件、原文、图谱或采用记录,也不重置全库历史额度;新增及发生变化的事件继续优先。只读访问仅在内存预览:保留有效第 2 代章的导航,隐藏旧小节并保留事件入口;不启动历史整理、不写库。第 1 代旧目录仍隐藏。第 3 代成功进度和编号在重启后保留,不反复重建。
28
+ - 旧章候选仍最多 12 个,排序结合全部已有节标题以及少量成员标题和标签。每个已展示候选提供全部轻量节标题、最多 4 段正文;节标题不授予未展示事件的引用权限。提示要求可容纳新事项时逐字复用已有节标题,不近义改名。同名章在已展示候选中唯一匹配时复用编号;全局已有同名正式章但未展示时拒绝结果,不静默创建重复章,显式改名也不能撞上另一章;不同项目仍独立归类,不引入永久跨章合并机制。
29
+ - 失效只标记一次。模型遗漏主题编号时,存储层为明确的成员延续复用编号;无法唯一对应的旧失效主题,在所有仍可见成员成功处理后移除。分批成功进度不会被旧主题再次清零,过期模型结果仍拒绝。
30
+ - 每章每次模型响应最多 8 段概要;这限制单次输出,不是累计段数或节数上限。有效旧段自动保留,不被新段挤掉;同名段仍聚合成一个节。章节累计内容与全量 JSON 存储的增量化另行跟踪。
31
+ - 每批模型输入及输出有固定上限,调用有超时、有限重试和重启恢复;主模型上下文组装只读取目录。
32
+ - 尚未整理和暂时失败的事件仍提供可验证的简略入口,不阻塞普通检索。
33
+ - 每批最多整理 12 个事件,候选旧主题最多 12 个,模型输入含结构约束不超过约 20,000 词元。每段概览注明来源;主题展开限制约 2,400 词元。展开结果优先保留轻量 `sections` 索引(标题和 `sourceEventCount`),包括无总览的小节,并用 `totalSections`、`omittedSections` 说明省略范围;索引、概要、省略计数和外层响应共用预算。全量小节成员关系只在服务端分页,不加入模型展开结果。
34
+ - 主题目录按偏好与要求、决定与计划、工作与结果、交流与协作、其他经历分类;分类仅用于浏览,不改变主题内容和编号。完整目录每页最多 20 项。
35
+ - 正式主题按创建时间从早到晚排列,新增主题追加;同一时刻仅以不可变的主题编号排序,改名不改变章序。注入目录、主题工具与界面共用这一顺序,待整理入口置后,展示章号不写入数据库。
36
+ - Dashboard 只返回主题、节、总览段落及事件数量,不返回事件成员编号、全量标题或摘要;Bootstrap 失败详情也只传数量。完整成员关系保留在服务端。节编号由规范化标题派生,界面与分页共用同一聚合规则。展开节、待整理或失败详情时,用只读接口每页最多读取 9 条事件;数据版本变化时丢弃旧页。同类型但不同标题仍是不同节,同名段落合为一个节。
37
+ - 目录默认预算不超过 400 个估算词元,原相关记忆预算为 900 词元。超预算时先预留分类、`memory_list_topics(category, offset)` 分页和 `memory_expand_topic(id)` 小节入口;优先保留章标题与 description,再逐轮为各章加入小节标题。章信息仍放不下时优先保留各分类的章入口,必要时省略 description;全部输出共用预算,未展示的章和小节可继续按需浏览。
38
+
39
+ ## 必须始终成立
40
+
41
+ 1. 事件和原文是证据底座,目录与概览不写回为新事件,不登记采用证据,不强化记忆。
42
+ 2. 主题编号独立于展示聚类成员;每条可见目录文字和概览都有可验证的来源依赖。
43
+ 3. 来源被遗忘、归档、撤销或修改后,旧派生文字先停止曝光,后台再重建。不能通过原始对话重新总结来复活已隐藏的事件。
44
+ 4. 模型结果提交前重新核对读取时的来源版本;过期任务不能覆盖新版主题。
45
+ 5. 主题只在当前命名空间可见;安装级画像不自动并入项目主题。
46
+ 6. 历史、计划、取消、争议和当前事实不能在整合时混为一谈;缺少信息保留为待确认问题。
47
+ 7. 升级、失败和重启不会修改或删除已有事件、图谱和原始对话;目录可独立重建。
48
+
49
+ ## 验收
50
+
51
+ 验证模糊查询发现主题、无图谱事件覆盖、按主题取证、增量整合与稳定编号、隐藏来源即时失效、过期提交拒绝、零采用强化、命名空间隔离、旧库升级、重启恢复、有限重试、输入和目录预算,以及后台失败时原搜索继续可用。测试只使用临时数据库与模拟模型。
@@ -0,0 +1,104 @@
1
+ {
2
+ "baselineSha": "e954eaf2f2cbbef4bb6226a2ebb35191424868c2",
3
+ "sourceSha": "415096f19d09d9bcc29c44634c7ae78fd6c2f52d",
4
+ "capturedAt": "2026-10-10T11:22:46.467Z",
5
+ "scope": "Synthetic DSH runtime on Windows; not the user database or full DSH UI process.",
6
+ "scenarios": [
7
+ {
8
+ "name": "small",
9
+ "namespaces": 100,
10
+ "rawUserCharsPerNamespace": 8192,
11
+ "databaseBytes": 8941568,
12
+ "rounds": 3,
13
+ "intervalMs": 3000,
14
+ "measurements": {
15
+ "before": {
16
+ "pollsMs": [
17
+ 2035.9983000000002,
18
+ 2204.014,
19
+ 2077.0357000000004
20
+ ],
21
+ "meanPollMs": 2105.682666666667,
22
+ "fullMemoryLoads": 300,
23
+ "cpuMs": 3015,
24
+ "wallMs": 15335.1882,
25
+ "processCpuPercent": 19.660665136147465,
26
+ "rssBefore": 56864768,
27
+ "rssAfter": 73207808,
28
+ "peakRss": 74285056,
29
+ "node": "v24.19.0",
30
+ "platform": "win32",
31
+ "arch": "x64",
32
+ "cpuMeasurementNote": "A zero CPU delta means below Windows counter resolution in this sample, not zero actual CPU work."
33
+ },
34
+ "after": {
35
+ "pollsMs": [
36
+ 32.8809,
37
+ 5.330300000000079,
38
+ 2.298700000000281
39
+ ],
40
+ "meanPollMs": 13.503300000000118,
41
+ "fullMemoryLoads": 0,
42
+ "cpuMs": 31,
43
+ "wallMs": 9071.7334,
44
+ "processCpuPercent": 0.3417208005693818,
45
+ "rssBefore": 56606720,
46
+ "rssAfter": 54337536,
47
+ "peakRss": 57950208,
48
+ "node": "v24.19.0",
49
+ "platform": "win32",
50
+ "arch": "x64",
51
+ "cpuMeasurementNote": "A zero CPU delta means below Windows counter resolution in this sample, not zero actual CPU work."
52
+ }
53
+ }
54
+ },
55
+ {
56
+ "name": "large",
57
+ "namespaces": 100,
58
+ "rawUserCharsPerNamespace": 1572864,
59
+ "databaseBytes": 1519824896,
60
+ "rounds": 3,
61
+ "intervalMs": 3000,
62
+ "measurements": {
63
+ "before": {
64
+ "pollsMs": [
65
+ 12951.9511,
66
+ 8731.1299,
67
+ 9476.834900000005
68
+ ],
69
+ "meanPollMs": 10386.638633333334,
70
+ "fullMemoryLoads": 300,
71
+ "cpuMs": 24844,
72
+ "wallMs": 40200.4599,
73
+ "processCpuPercent": 61.80028801113292,
74
+ "rssBefore": 56283136,
75
+ "rssAfter": 157401088,
76
+ "peakRss": 332111872,
77
+ "node": "v24.19.0",
78
+ "platform": "win32",
79
+ "arch": "x64",
80
+ "cpuMeasurementNote": "A zero CPU delta means below Windows counter resolution in this sample, not zero actual CPU work."
81
+ },
82
+ "after": {
83
+ "pollsMs": [
84
+ 29.53,
85
+ 3.372899999999845,
86
+ 2.309900000000198
87
+ ],
88
+ "meanPollMs": 11.737600000000015,
89
+ "fullMemoryLoads": 0,
90
+ "cpuMs": 109,
91
+ "wallMs": 9061.4375,
92
+ "processCpuPercent": 1.2028996503038287,
93
+ "rssBefore": 52092928,
94
+ "rssAfter": 51056640,
95
+ "peakRss": 54579200,
96
+ "node": "v24.19.0",
97
+ "platform": "win32",
98
+ "arch": "x64",
99
+ "cpuMeasurementNote": "A zero CPU delta means below Windows counter resolution in this sample, not zero actual CPU work."
100
+ }
101
+ }
102
+ }
103
+ ]
104
+ }
@@ -0,0 +1,103 @@
1
+ {
2
+ "baselineSha": "e954eaf2f2cbbef4bb6226a2ebb35191424868c2",
3
+ "capturedAt": "2026-10-09T14:26:54.222Z",
4
+ "scope": "Synthetic DSH runtime on Windows; not the user database or full DSH UI process.",
5
+ "scenarios": [
6
+ {
7
+ "name": "small",
8
+ "namespaces": 100,
9
+ "rawUserCharsPerNamespace": 8192,
10
+ "databaseBytes": 8949760,
11
+ "rounds": 3,
12
+ "intervalMs": 3000,
13
+ "measurements": {
14
+ "before": {
15
+ "pollsMs": [
16
+ 1559.2007,
17
+ 2646.6144999999997,
18
+ 2287.6314999999995
19
+ ],
20
+ "meanPollMs": 2164.482233333333,
21
+ "fullMemoryLoads": 300,
22
+ "cpuMs": 3547,
23
+ "wallMs": 15505.109400000001,
24
+ "processCpuPercent": 22.876330043824133,
25
+ "rssBefore": 56803328,
26
+ "rssAfter": 73904128,
27
+ "peakRss": 74313728,
28
+ "node": "v24.19.0",
29
+ "platform": "win32",
30
+ "arch": "x64",
31
+ "cpuMeasurementNote": "A zero CPU delta means below Windows counter resolution in this sample, not zero actual CPU work."
32
+ },
33
+ "after": {
34
+ "pollsMs": [
35
+ 17.57029999999999,
36
+ 3.0478000000002794,
37
+ 4.158300000000054
38
+ ],
39
+ "meanPollMs": 8.258800000000107,
40
+ "fullMemoryLoads": 0,
41
+ "cpuMs": 16,
42
+ "wallMs": 9039.4974,
43
+ "processCpuPercent": 0.17700099122767599,
44
+ "rssBefore": 56590336,
45
+ "rssAfter": 54194176,
46
+ "peakRss": 57184256,
47
+ "node": "v24.19.0",
48
+ "platform": "win32",
49
+ "arch": "x64",
50
+ "cpuMeasurementNote": "A zero CPU delta means below Windows counter resolution in this sample, not zero actual CPU work."
51
+ }
52
+ }
53
+ },
54
+ {
55
+ "name": "large",
56
+ "namespaces": 100,
57
+ "rawUserCharsPerNamespace": 1572864,
58
+ "databaseBytes": 1519833088,
59
+ "rounds": 3,
60
+ "intervalMs": 3000,
61
+ "measurements": {
62
+ "before": {
63
+ "pollsMs": [
64
+ 13949.606099999999,
65
+ 12921.8561,
66
+ 12388.245900000002
67
+ ],
68
+ "meanPollMs": 13086.569366666668,
69
+ "fullMemoryLoads": 300,
70
+ "cpuMs": 32203,
71
+ "wallMs": 48289.1154,
72
+ "processCpuPercent": 66.687906235698,
73
+ "rssBefore": 56573952,
74
+ "rssAfter": 180330496,
75
+ "peakRss": 284123136,
76
+ "node": "v24.19.0",
77
+ "platform": "win32",
78
+ "arch": "x64",
79
+ "cpuMeasurementNote": "A zero CPU delta means below Windows counter resolution in this sample, not zero actual CPU work."
80
+ },
81
+ "after": {
82
+ "pollsMs": [
83
+ 40.84779999999998,
84
+ 3.018500000000131,
85
+ 3.4000999999998385
86
+ ],
87
+ "meanPollMs": 15.75546666666665,
88
+ "fullMemoryLoads": 0,
89
+ "cpuMs": 63,
90
+ "wallMs": 9055.1278,
91
+ "processCpuPercent": 0.6957383859342107,
92
+ "rssBefore": 56807424,
93
+ "rssAfter": 54194176,
94
+ "peakRss": 57184256,
95
+ "node": "v24.19.0",
96
+ "platform": "win32",
97
+ "arch": "x64",
98
+ "cpuMeasurementNote": "A zero CPU delta means below Windows counter resolution in this sample, not zero actual CPU work."
99
+ }
100
+ }
101
+ }
102
+ ]
103
+ }
@@ -1,32 +1,32 @@
1
- # Event Extractor v2
2
-
3
- 新版规则只用于升级后正常提取的新 Event。不会重放旧 L5、改写旧标题、拆分或合并旧 Event,也不会回填分类提示或版本号。已有待处理任务仍按正常重试规则处理。
4
-
5
- ## 提取判断
6
-
7
- 判断独立含义及遗忘成本,而不是以重要性、criticality 或消息角色作为统一门槛。用户事实、评价、审美反馈、明确要求、纠正、改变决定和可复用指导采用较低提取门槛;普通 Agent / Tool 执行步骤采用较高门槛。已确认根因、平台限制、失败条件、可复用经验和重要结果仍可独立保留。Summarizer 的高召回预筛同步提示这些候选。
8
-
9
- 保守使用现有 scope:单次答复要求保留 session 范围;项目要求使用 project;明确长期指导才可使用 user。重复纠正可以成为经验的证据,但不能把一次局部反馈扩大成永久人格或审美。两个能独立变化、被检索、冲突或替代的事实仍分开;原子化不等于记录每次工具调用。标题保留明确对象、稳定锚点和一个主要变化,详细原因留在 summary。
10
- Extractor 结构化输出必须明确返回合法 scope。工具调用及文本 fallback 都先进行同一 schema 验证;遗漏或非法值触发现有有界重试,重试仍失败时不写入 Event,不再默认扩大为 project。核心旧 Event、手工输入及自定义 Extractor 的兼容类型不变。
11
-
12
- ## 重复与关系
13
-
14
- 同一 Block 内的同义表达由模型识别为一条事实,保留直接支持它的目标消息 ID。适配层额外合并同一次输出中 title、summary、scope、criticality 和 temporal 完全相同的卡片,比较截断前的完整模型文本,合并目标来源及检索标签;不同事实、范围或关系不合并。
15
- 精确重复卡的 catalogHints 保留第一张卡的归一化结果,包括第一张缺省时继续缺省;不合并或追加后续卡的类别。
16
-
17
- 纯重复且没有新增长期信息可不提取;明确强化或延续用 sameEventId,替代/纠正用 supersedesEventIds,无法确认替代的矛盾用 conflictsWithEventIds。历史卡保留。相同项目、关键词近似不能单独建立关系。现有 timeline 仍最多提供 8 条相关及 4 条最近 Event,增加每条最多 400 字符的摘要、范围和历史状态以辅助识别;字段对自定义 Extractor 保持可选。timeline / neighbor 只供理解和关系匹配,不能为新事实提供来源。
18
-
19
- ## 可选字段与兼容
20
-
21
- | 字段 | 语义 | 边界 |
22
- | --- | --- | --- |
23
- | `catalogHints?: string[]` | 长期类别的自由短语,仅供导航 | 最多 2 个,每个最多 64 个 Unicode 字符;可以缺省或为空;不设 enum 或 other/其他兜底,不指定目录 ID/路径,不改写标题来充当类别 |
24
- | `extractorVersion?: number` | 对话提取规则版本 | DSH Extractor 在代码中标记为 `2`,不让模型决定;旧卡、手工卡及其他 Extractor 缺省合法 |
25
-
26
- 运行时限制提示数量,移除空白、重复、非法类型、明显兜底和目录 ID/路径;类别是否有来源、是否只是标题改写等语义约束由 prompt 负责。Topic Projector 可见 catalogHints 用于路由,但不能据此生成事实或决定章/节。Element 和 Graph 都用字段白名单构造 Event 模型输入,物理排除提示和版本号;Element 保留事实正文、引用、目标来源、时间、范围、criticality 和历史关系。检索的事实字段、provenance、时间、criticality 和 admission 机制不变。
27
-
28
- SQLite 用新增的可选 `event_metadata` 附表保存这两个字段,支持 passive / agent 两个 Event 池,随原有事务保存和清理。只为已有字段的卡写元数据行;不 ALTER 旧 Event 表或重建历史数据,存储 schema 仍为 12。旧库没有附表也可以只读打开;普通写入器打开时创建空表。旧 Event 的 API 字段形状保持原样,新字段存在时才输出。
29
-
30
- ## 验证边界
31
-
32
- 确定性测试验证 prompt/schema 合约、模型输出归一化、同 Block 精确去重、目标来源边界、relation 写入、SQLite 往返、旧库只读/升级、无历史重提取/回填,以及旧卡的检索、Topic、Graph、API 和 UI 路径。测试里的模型响应是 mock,并非真实模型语义准确率测量;同义识别、提取敏感度及泛化质量仍取决于实际模型。未新增模型调用、依赖、全局 consolidation 或目录算法。
1
+ # Event Extractor v2
2
+
3
+ 新版规则只用于升级后正常提取的新 Event。不会重放旧 L5、改写旧标题、拆分或合并旧 Event,也不会回填分类提示或版本号。已有待处理任务仍按正常重试规则处理。
4
+
5
+ ## 提取判断
6
+
7
+ 判断独立含义及遗忘成本,而不是以重要性、criticality 或消息角色作为统一门槛。用户事实、评价、审美反馈、明确要求、纠正、改变决定和可复用指导采用较低提取门槛;普通 Agent / Tool 执行步骤采用较高门槛。已确认根因、平台限制、失败条件、可复用经验和重要结果仍可独立保留。Summarizer 的高召回预筛同步提示这些候选。
8
+
9
+ 保守使用现有 scope:单次答复要求保留 session 范围;项目要求使用 project;明确长期指导才可使用 user。重复纠正可以成为经验的证据,但不能把一次局部反馈扩大成永久人格或审美。两个能独立变化、被检索、冲突或替代的事实仍分开;原子化不等于记录每次工具调用。标题保留明确对象、稳定锚点和一个主要变化,详细原因留在 summary。
10
+ Extractor 结构化输出必须明确返回合法 scope。工具调用及文本 fallback 都先进行同一 schema 验证;遗漏或非法值触发现有有界重试,重试仍失败时不写入 Event,不再默认扩大为 project。核心旧 Event、手工输入及自定义 Extractor 的兼容类型不变。
11
+
12
+ ## 重复与关系
13
+
14
+ 同一 Block 内的同义表达由模型识别为一条事实,保留直接支持它的目标消息 ID。适配层额外合并同一次输出中 title、summary、scope、criticality 和 temporal 完全相同的卡片,比较截断前的完整模型文本,合并目标来源及检索标签;不同事实、范围或关系不合并。
15
+ 精确重复卡的 catalogHints 保留第一张卡的归一化结果,包括第一张缺省时继续缺省;不合并或追加后续卡的类别。
16
+
17
+ 纯重复且没有新增长期信息可不提取;明确强化或延续用 sameEventId,替代/纠正用 supersedesEventIds,无法确认替代的矛盾用 conflictsWithEventIds。历史卡保留。相同项目、关键词近似不能单独建立关系。现有 timeline 仍最多提供 8 条相关及 4 条最近 Event,增加每条最多 400 字符的摘要、范围和历史状态以辅助识别;字段对自定义 Extractor 保持可选。timeline / neighbor 只供理解和关系匹配,不能为新事实提供来源。
18
+
19
+ ## 可选字段与兼容
20
+
21
+ | 字段 | 语义 | 边界 |
22
+ | --- | --- | --- |
23
+ | `catalogHints?: string[]` | 长期类别的自由短语,仅供导航 | 最多 2 个,每个最多 64 个 Unicode 字符;可以缺省或为空;不设 enum 或 other/其他兜底,不指定目录 ID/路径,不改写标题来充当类别 |
24
+ | `extractorVersion?: number` | 对话提取规则版本 | DSH Extractor 在代码中标记为 `2`,不让模型决定;旧卡、手工卡及其他 Extractor 缺省合法 |
25
+
26
+ 运行时限制提示数量,移除空白、重复、非法类型、明显兜底和目录 ID/路径;类别是否有来源、是否只是标题改写等语义约束由 prompt 负责。Topic Projector 可见 catalogHints 用于路由,但不能据此生成事实或决定章/节。Element 和 Graph 都用字段白名单构造 Event 模型输入,物理排除提示和版本号;Element 保留事实正文、引用、目标来源、时间、范围、criticality 和历史关系。检索的事实字段、provenance、时间、criticality 和 admission 机制不变。
27
+
28
+ SQLite 用新增的可选 `event_metadata` 附表保存这两个字段,支持 passive / agent 两个 Event 池,随原有事务保存和清理。只为已有字段的卡写元数据行;不 ALTER 旧 Event 表或重建历史数据,存储 schema 仍为 12。旧库没有附表也可以只读打开;普通写入器打开时创建空表。旧 Event 的 API 字段形状保持原样,新字段存在时才输出。
29
+
30
+ ## 验证边界
31
+
32
+ 确定性测试验证 prompt/schema 合约、模型输出归一化、同 Block 精确去重、目标来源边界、relation 写入、SQLite 往返、旧库只读/升级、无历史重提取/回填,以及旧卡的检索、Topic、Graph、API 和 UI 路径。测试里的模型响应是 mock,并非真实模型语义准确率测量;同义识别、提取敏感度及泛化质量仍取决于实际模型。未新增模型调用、依赖、全局 consolidation 或目录算法。
@@ -0,0 +1,55 @@
1
+ # Issue #128:同 revision 续租缓存复审修复
2
+
3
+ 源码提交:`0f0cb8fbce5a116e4670785716aa62f68cdd9c08`。本报告之后的交付提交只增加证据文档;交付 SHA 以离线包 manifest 为准。
4
+
5
+ 上轮交付:`bc73b6b7b2353e9c82726b8976f440672546ce9e`。完整修复基线:`e954eaf2f2cbbef4bb6226a2ebb35191424868c2`。
6
+
7
+ ## 复现与修复
8
+
9
+ 审查指出的边界成立。B 在 A 续租前加载 running Job,A 用真实独立 OS 子进程调用 SQLite 续租接口,业务 revision 不变;推进时钟越过 B 缓存的租约时间,B 尝试处理另一线程的 Block。修复前,Summary、Extraction、Graph、Topic 四个定向用例均出现 `Storage lease conflict`,无法完成另一任务。干净复现日志为 `lease-cache-repro-fixed-fixture.log`,不是仅凭静态推断。
10
+
11
+ 最小修复继续把 Jobs 作为事实来源,不增加业务 revision、不引入新的业务状态机或常驻历史缓存:
12
+
13
+ - SQLite 增加可选的轻量 `loadDerivationLeases()`。一次读事务获取当前 namespace 的 revision 和四类 running 认领元数据,不读取消息、Block 正文、Event 内容或 Graph 节点。Graph/Topic 只向调用者返回 Job 身份、attempt、updatedAt、leaseUntil;Topic 的 JSON 查询在 SQLite 内完成。
14
+ - 本地发现 running 租约已到期时,恢复前先同步持久化元数据。`reloadFromStorage()` 与 `refreshFromStorage()` 在 revision 相同且认领身份一致时,只同步租约字段。业务 revision 变化,或 running 集合、attempt、updatedAt 不一致时,才读取完整权威快照;不能用租约读结果猜测业务状态。
15
+ - Topic claim 使用同一个到期前置同步。正常完成、到期恢复、失败重试和最大次数仍由原有状态机处理,写入仍受 SQLite 事务认领与租约校验保护。
16
+ - 心跳仍可能恰好发生在元数据读取之后、恢复写入之前。SQLite 会拒绝旧租约写入;前台 Block 调度遇到冲突后刷新持久化状态,并至少等待原有 3 秒 Worker 间隔后再试,不为这次正常竞争记录插件错误。其他抛出的异常也受同一个重排下限约束。新任务正常唤醒和既有持久化失败重试时间不变。
17
+
18
+ 没有调大后台轮询间隔。新元数据读取用于实际任务恢复及显式重载,空闲轮询仍只查到期调度/脏键索引、额度和独立 Profile Maintenance,不会因此逐个打开 namespace。旧数据库可按原有迁移与分批脏键重建发现旧任务;跨进程写入仍依赖持久化触发器和轻量轮询,不依赖内存通知。
19
+
20
+ ## 定向验证
21
+
22
+ - 四类真实子进程续租:B 未显式 reload,也不会误恢复 A;A 保持 running、attempt 不变;另一线程任务完成;重复三轮不重复调用模型;续租同步期间完整 `SqliteStorage.load()` 调用为零。观察者的两种显式重载接口也取得同 revision 新租约。
23
+ - 同 revision 下认领 attempt 或状态被外部 SQL 改变:确实加载一次完整权威快照,而不是只替换租约。
24
+ - 前台真实 SQLite 竞争:读取旧元数据后 A 再续租,B 越过旧截止时间,事务拒绝恢复写入。没有插件错误日志;2,999ms 内不重试,3,000ms 后另一任务完成;额外推进 10 秒不再重排;完整加载仍为零。
25
+ - 既有失败恢复测试改用模拟定时器,明确断言退避期间 namespace 仍可打开、退避后任务完成,没有增加测试超时。
26
+ - 全范围自查还复现了最终一次 Summary/Extraction 租约中断后的终止边界:Core 已拒绝再执行,恢复留下的到期时间仍会让前台不断重排一个无法执行的任务。两个修复前回归均发现立即重试定时器;前台增加原有最大尝试次数过滤后,连续四次调度都不再创建定时器,模型调用为零。没有修改持久化重试 ledger 或增加尝试次数。
27
+
28
+ 时间边界使用注入时钟/模拟定时器;续租写入和认领竞争使用真实 SQLite,四类续租各使用真实独立 OS 进程。没有声称在本轮实际等待 5 分钟网络模型调用。
29
+
30
+ ## 整体核查与测试
31
+
32
+ Windows x64 / Node `24.19.0` / `CI=true`:
33
+
34
+ - `npm run check` 通过。
35
+ - `npm test`:Core **312**、DSH **591**、WorkBuddy **10**,共 **913** 项通过、**1** 项既有跳过。
36
+ - Issue #128 两个定向文件共 **41** 项通过(Core 30、DSH 11),包含先前 FTS、坏键公平重建、open tail、租约续期及本轮缓存和最终尝试边界回归。
37
+ - `npm run build` 全部目标通过;`node scripts/verify-package.mjs` 验证 58 个包内文件及干净 tarball 安装,通过。
38
+ - Windows DSH `0.2.0-rc.1` 和 `0.2.0-rc.2` 各自完整兼容脚本通过,均在冻结源码下完成类型检查、591 项 DSH 测试(1 项既有跳过)、构建、干净包安装、真实 CLI 启动、陈旧 peer 可恢复修复、管理能力、两条会话标题/页面和旧迁移,退出码均为 0。
39
+ - 首次 rc.1 流程跨过了最终尝试次数补丁,未作为最终提交的完整证据。冻结后完整补跑日志为 `lease-cache-compat-rc1-final.log`;rc.2 日志为 `lease-cache-compat-rc2.log`。补跑 rc.1 和最后构建/包检查只关闭 npm 附带的 audit/fund 网络请求,依赖安装和全部功能断言保留;未执行安全漏洞审计。环境记录见 `lease-cache-validation-context.json`。
40
+
41
+ 自查覆盖整个调度与 FTS 范围:派生索引与任务保存仍在同一事务;坏键持久化 60 秒退避与 generation 校验保留;未变化消息 UPSERT/FTS UPDATE 触发器仍不污染 dirty 集合;普通打开不再全库检查 FTS,旧库按搜索 namespace 懒回填,显式修复入口保留;只有可封存 open tail 的资格检查与 Worker 一致;Topic Event 版本动态工作及历史额度、模型就绪、重启恢复和独立 Profile Maintenance 相关回归仍通过。
42
+
43
+ 本轮初次全量运行有一项失败:旧测试默认等待窗口短于新增 3 秒异常退避。修正为上述明确的时间边界断言后完整复验通过。离线包保留干净的修复前四类失败日志与最终通过日志,避免混用。
44
+
45
+ ## 性能与验收边界
46
+
47
+ 本轮没有重新采集 CPU/RSS 基准。此前 [Windows 合成数据](benchmarks/issue-128-windows-review.json) 属于源码 `415096f19d09d9bcc29c44634c7ae78fd6c2f52d`,其中 1449.42 MiB 合成库的 Worker CPU 61.80% → 1.20%、三轮完整加载 300 → 0,不能标注为本轮源码的测量。本轮的空闲回归继续验证 100 namespace 多轮、1000 namespace 大规模扫描不打开完整记忆;这不是完整 DSH 桌面进程 CPU 验收。
48
+
49
+ 原用户 168 MB / 14 namespace 数据库、真实网络长模型、桌面界面响应及长期 CPU/RSS 仍需人工验证;远端 CI 未知。没有访问或修改用户生产数据库,没有推送 GitHub、更新 PR、合并或发布版本。
50
+
51
+ ## 离线交付
52
+
53
+ 新包包含完整提交源码 ZIP、完整任务分支历史 Git bundle、相对基线完整补丁、相对上轮增量补丁、测试/兼容日志、报告、中文审查提示词和 SHA-256 manifest。bundle 包含基线及其祖先,无外部 prerequisite;会在本任务的新隔离目录实际克隆并检查 HEAD。它仅包含任务分支引用,不打包其他工作分支。
54
+
55
+ 完整源码包含 lockfile、测试夹具和构建配置。Node/npm 依赖未内嵌,重新执行测试需要可用 npm registry 或预先准备的依赖缓存;Git 仓库恢复本身不依赖 GitHub。历史报告与性能 JSON 保留原来的源码归属,最新结论以本报告和 manifest 为准。
@@ -0,0 +1,58 @@
1
+ # Issue #128 复审修复记录
2
+
3
+ 本轮继续使用独立 Worktree `.worktrees/fix-128-background-worker` 和分支 `codex/fix-128-background-worker`。用户已取消 PR 交付:只保留本地提交、测试及复审材料,不推送、不更新 PR、不合并、不发布。源码固定提交为 `415096f19d09d9bcc29c44634c7ae78fd6c2f52d`(运行时修复提交为 `8a569b911f40f43934406f5362251cf44b2c28f0`,随后增加 Windows CI 并发限制);后续证据提交只增加报告和测量结果。
4
+
5
+ ## 根因与修复
6
+
7
+ 原 Worker 在上一轮结束后重新安排 3 秒轮询,问题不是计时器重叠,而是每轮完整打开所有 namespace 才判断有无任务,以及 SQLite 打开时重复检查各 namespace 的 FTS 完整性。持久化派生索引已消除这一发现路径。本轮进一步修复独立复审发现的三个问题:
8
+
9
+ 1. **未变化的历史消息被重新标记为 FTS dirty。** 快照 UPSERT 会触发 UPDATE,但原触发器不检查变化。现在 UPSERT 跳过完全未变化的消息;FTS 触发器只关注内容、Block 归属、namespace 或 ID 的实际变化。直接 SQL 修改仍会标记旧键和新键,惰性修复保持增量。触发器升级置于事务内,避免安装期间漏掉并发写入。
10
+ 2. **前八个损坏键饿死后续健康键。** 重建新增持久化 `rebuild_after`,失败键等待 60 秒;通过到期索引选择下一批,跨重启继续。源数据变化立即重置等待并更换 generation。脏键不会使用过时的调度条目,失败也不会要求零延迟重排。该字段只属于可重建索引的修复信息,没有替代 Job 重试状态。
11
+ 3. **只有可封存 open tail 时反复加载而不封存。** Worker 使用 Core 的 `hasSealableTail()`,与实际封存使用同一判定;重启后即使没有任何 Job 也能生成 Block,完成后不再重复打开。直接 SQL 移除或移动 open tail 时也会使旧 namespace 失效。
12
+
13
+ 全范围自查及兼容复验另外发现并修复:
14
+
15
+ - **额度恢复的毫秒竞态:** 本轮发现时间和历史额度截止时间原先各读一次时钟,跨毫秒时可能把可用额度当作未来到期;现在共享同一个 `now`,回归刻意让每次时钟读取递增。
16
+ - **长模型超过租约时重复调用:** Summary、Extraction、Graph、Topic 仅在模型执行期间定期续租。续租只更新持久化 Job 元数据,不加载历史记忆,不修改业务 revision。正常保存会合并同一 running attempt 的新租约;恢复或完成写入在同一事务内校验修改前的租约,防止旧快照缩短租约或覆盖新认领。Topic 完成后仍清除租约,既有状态语义保留。租约停止续期后,原有到期恢复和尝试上限继续生效。
17
+ - **空认领产生 revision 写入:** Graph/Topic 无可认领工作时直接返回,避免另一 worker 为一个空认领保存快照并使模型所有者的结果失效。
18
+ - **Windows 测试进程压力:** 本地复验捕获了子进程启动 `EBUSY` 及其引起的 Vitest 进程池错误,不能把该轮断言通过当作整体通过。Windows CI 现在最多启动两个测试 worker;单项超时不变。后续在本任务内独立 Node 24/npm 入口下完整复验通过,未更改系统 Node 或其他任务运行时。
19
+
20
+ ## 空闲路径与旧任务
21
+
22
+ 空闲轮询只检查持久化调度/脏键到期索引、模型是否就绪、历史额度和独立 Profile Maintenance。不会枚举全部 namespace、打开完整记忆、读取原始消息正文、遍历历史 Graph 或重新计算全部 Topic 资格,也不再做全库 FTS 完整性检查。
23
+
24
+ Jobs、Event 及 Topic ledger 始终是事实来源。任务保存与派生索引更新在同一事务中完成;同进程通知只是唤醒提示。跨进程写入由 SQLite 触发器留下持久化脏键,原有 3 秒轻量轮询发现它们。升级只初始化键列表,重建按 namespace 和 Event 批次让出事件循环,发布前校验 generation;重启、失败退避或模型未就绪不会丢掉待重建键。Topic 的 Event 版本变化即使尚无 Job,也参与派生资格计算。历史额度到期后恢复,Profile Maintenance 独立运行。
25
+
26
+ ## 验证
27
+
28
+ - Windows x64 / Node `24.19.0`,`CI=true`:`npm run check`、`npm test`、`npm run build`、`node scripts/verify-package.mjs` 通过。
29
+ - Core **306**、DSH **588**、WorkBuddy **10**,共 **904** 项通过,另有 **1** 项既有跳过。
30
+ - Issue #128 定向回归共 **32** 项(Core 24、DSH 8)。包括 100 个含历史 namespace 十轮零完整加载;1000 个空闲 namespace 不枚举、不加载;只有任务 namespace 打开;四类调度;8 个坏键加第 9 个健康键及重启、退避解除;600 条旧消息在 Event/使用记录保存后 dirty 为零、检索修复调用为零;旧索引/FTS 升级;只有 open tail 的恢复;模型就绪、到期重试、次数上限、额度恢复和独立 Profile。
31
+ - 四类长模型回归使用模拟时钟越过原 5 分钟租约,并启动另一真实 OS 进程;另一个进程模型调用/认领为零,原任务完成,续租计时器清除。另覆盖并发保存合并租约以及过时恢复/完成的事务拒绝。这是时间推进与真实进程竞争测试,不是真实等待数分钟的网络模型测量。
32
+ - Windows DSH `0.2.0-rc.1` 的完整隔离兼容脚本已在上述固定源码、独立 Node 24/npm 入口下通过,包括类型检查、588 项 DSH 测试(1 项既有跳过)、构建、干净包安装、CLI 启动、管理接口、会话页及旧迁移。
33
+ - Windows DSH `0.2.0-rc.2` 在同一固定源码和入口下完整通过同一流程,588 项 DSH 测试通过(1 项既有跳过),以及干净包安装、真实 CLI 启动、管理接口、会话页和旧迁移。两版脚本均正常退出,退出码为 0。
34
+
35
+ 最后一次完整测试中,原超时的 100 namespace 用例为 1.885 秒,历史额度章节重建用例为 2.268 秒;这些耗时包含各自夹具准备,受同机负载影响。没有提高原用例超时。夹具改用一个 writer 准备历史,完整加载计数只从夹具完成后开始。无法读取被封禁账号的 GitHub Actions 日志,因此不能把本地复验解释为已证明此前远端超时的唯一原因,也不声称远端 CI 已通过。
36
+
37
+ 单独的 rc.2 兼容轮中,上述两项分别为 0.959 秒和 0.981 秒,全部 DSH 测试用时 23.26 秒;此前整套测试中的 DSH 部分为 50.35 秒。保留两组结果,不用较快一轮代替较慢一轮。
38
+
39
+ ## 性能证据
40
+
41
+ 前次提交 `bf30690e7a6673f9c2a3a029f7506f368b6f8f9c` 的合成测量保留于 [原始 JSON](benchmarks/issue-128-windows.json),未覆盖。上述固定源码的本轮测量另存为 [本轮 JSON](benchmarks/issue-128-windows-review.json),其中记录了基线、源码 SHA、采集时间、CPU 原始时间和每轮耗时。
42
+
43
+ 命令:`node --expose-gc scripts/benchmark-worker-128.mjs`。Windows x64 / Node 24.19.0,每个场景 100 个 namespace,三轮串行 Worker 轮询,每轮结束后仍等待 3 秒,模型使用 stub。先准备一份已完成派生工作的数据库,再分别复制给基线 `e954eaf2f2cbbef4bb6226a2ebb35191424868c2` 和修复源码。基线副本移除新增调度/FTS dirty 触发器、表及 Summary/Extraction 租约列,避免把新维护成本算到旧代码。数据库准备、构建不计入轮询样本;测量时未并行运行本任务构建或测试。
44
+
45
+ | 合成库 | 实现 | 进程 CPU 平均 | 平均轮询 ms | RSS 测量前/后 MiB | 峰值 RSS MiB | 三轮完整加载 |
46
+ | --- | --- | ---: | ---: | ---: | ---: | ---: |
47
+ | 8.53 MiB | 基线 | 19.66% | 2105.68 | 54.23 / 69.82 | 70.84 | 300 |
48
+ | 8.53 MiB | 修复 | 0.34% | 13.50 | 53.98 / 51.82 | 55.27 | 0 |
49
+ | 1449.42 MiB | 基线 | 61.80% | 10386.64 | 53.68 / 150.11 | 316.73 | 300 |
50
+ | 1449.42 MiB | 修复 | 1.20% | 11.74 | 49.68 / 48.69 | 52.05 | 0 |
51
+
52
+ CPU 使用 Node 进程 CPU 时间除以包含等待的总墙钟时间;RSS 是被测子进程内存,峰值由 `process.resourceUsage()` 提供。历史体积增加约 170 倍后,修复样本未表现出线性增长的轮询开销;零完整加载和索引查询计划另由定向回归保证。这里只测三轮,CPU 计数分辨率、同机负载及缓存会影响结果,不能据此承诺真实长期 CPU 固定为某个百分比。
53
+
54
+ 两次性能测量均是合成库、隔离 Worker 和模拟模型,不是用户 168 MB / 14 namespace 原库或完整 DSH 桌面进程。真实 CLI 兼容验收使用隔离 DSH Home/会话夹具,未接入用户生产数据库。实际原库的长期 CPU、内存、界面响应以及真实网络模型长耗时仍需人工验收。
55
+
56
+ ## 离线独立复审
57
+
58
+ 本轮没有推送或更新 PR #130。交付本地固定提交、相对基线的完整补丁、变更文件的完整当前/基线源码、Git bundle、本报告、两次原始性能 JSON、已通过的测试/兼容性日志以及中文复审提示词。离线包的 `manifest.json` 记录最终交付 SHA 和各文件 SHA-256;源码冻结在上述提交,后续证据提交只增加文档。复审必须检查整个调度与 FTS 改动,而不仅是三个阻塞项的补丁。
@@ -1,30 +1,30 @@
1
- {
2
- "verification": "deterministic mocked streams, not live model generation",
3
- "base": "e954eaf2f2cbbef4bb6226a2ebb35191424868c2",
4
- "rows": [
5
- {
6
- "initialCharacters": 656,
7
- "retryOverview": "same",
8
- "success": true,
9
- "calls": 1
10
- },
11
- {
12
- "initialCharacters": 778,
13
- "retryOverview": "same",
14
- "success": true,
15
- "calls": 1
16
- },
17
- {
18
- "initialCharacters": 1000,
19
- "retryOverview": "same",
20
- "success": true,
21
- "calls": 1
22
- },
23
- {
24
- "initialCharacters": 1001,
25
- "retryOverview": "empty",
26
- "success": true,
27
- "calls": 2
28
- }
29
- ]
30
- }
1
+ {
2
+ "verification": "deterministic mocked streams, not live model generation",
3
+ "base": "e954eaf2f2cbbef4bb6226a2ebb35191424868c2",
4
+ "rows": [
5
+ {
6
+ "initialCharacters": 656,
7
+ "retryOverview": "same",
8
+ "success": true,
9
+ "calls": 1
10
+ },
11
+ {
12
+ "initialCharacters": 778,
13
+ "retryOverview": "same",
14
+ "success": true,
15
+ "calls": 1
16
+ },
17
+ {
18
+ "initialCharacters": 1000,
19
+ "retryOverview": "same",
20
+ "success": true,
21
+ "calls": 1
22
+ },
23
+ {
24
+ "initialCharacters": 1001,
25
+ "retryOverview": "empty",
26
+ "success": true,
27
+ "calls": 2
28
+ }
29
+ ]
30
+ }