@a9i5k4/dsh-auto-memory 3.0.1 → 3.1.1

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.
Files changed (134) hide show
  1. package/README.md +13 -8
  2. package/README.zh-CN.md +13 -8
  3. package/docs/HANDBOOK.md +92 -52
  4. package/docs/USER-GUIDE.en.md +9 -9
  5. package/docs/USER-GUIDE.zh-CN.md +9 -9
  6. package/docs/screenshots/promo/promo-0-banner-v4.png +0 -0
  7. package/docs/screenshots/promo/promo-1b-auto-recall.png +0 -0
  8. package/lib/activation-host.js +6 -1
  9. package/lib/client.js +1376 -255
  10. package/lib/config-io.js +59 -6
  11. package/lib/context-host.js +17 -2
  12. package/lib/episodic-store.js +90 -16
  13. package/lib/evidence-store.js +27 -1
  14. package/lib/fact-store.js +463 -41
  15. package/lib/hub-io.js +217 -0
  16. package/lib/index.js +904 -87
  17. package/lib/intent-clean-safe.js +1 -1
  18. package/lib/jsonl-tail-cursor.js +75 -0
  19. package/lib/m7-index-sync-host.js +4 -6
  20. package/lib/memory-hub.js +62 -7
  21. package/lib/migrate-pack.js +351 -0
  22. package/lib/note-status.js +9 -1
  23. package/lib/procedure-store.js +252 -31
  24. package/lib/procedure-switch.js +38 -0
  25. package/lib/python-setup.js +109 -27
  26. package/lib/python-sidecar-client.js +285 -8
  27. package/lib/recall-stats.js +242 -0
  28. package/lib/rules-layer.js +106 -15
  29. package/lib/semantic-js.js +25 -7
  30. package/lib/shadow-host.js +41 -2
  31. package/package.json +6 -2
  32. package/docs/internal/ACCEPT-35-LIVE.md +0 -143
  33. package/docs/internal/ACCEPTANCE-20260914.md +0 -90
  34. package/docs/internal/ARCH-REVIEW-BRIEF.md +0 -411
  35. package/docs/internal/ARCH-REVIEW-REQUEST.md +0 -201
  36. package/docs/internal/ARCH-REVIEW-ROUND2.md +0 -169
  37. package/docs/internal/ARCH-REVIEW-ROUND3.md +0 -206
  38. package/docs/internal/ARCHITECTURE-FOR-ZCODE-20260920.md +0 -397
  39. package/docs/internal/ART-DIRECTION-DEEPSEEK-20260920.md +0 -351
  40. package/docs/internal/ART-DIRECTION-WIREFRAME.md +0 -191
  41. package/docs/internal/ART-DIRECTION-WIREFRAME.md.bak-superseded +0 -181
  42. package/docs/internal/AUDIT-WB-GRAPH-FULL-20260916.md +0 -314
  43. package/docs/internal/BATTLE-PLAN-20260917.md +0 -871
  44. package/docs/internal/CONCURRENCY-INVESTIGATION-20260917.md +0 -192
  45. package/docs/internal/CROSS-SESSION-SEARCH-PATH-DECISION.md +0 -72
  46. package/docs/internal/CROSS-SESSION-SEARCH-RESEARCH.md +0 -131
  47. package/docs/internal/CUA-VISION-FIX-NOTES.md +0 -78
  48. package/docs/internal/DECISIONS-20260914-SESSION.md +0 -269
  49. package/docs/internal/DESIGN-OVERHAUL-PRE-RESEARCH.md +0 -292
  50. package/docs/internal/DESIGN-P1-STATE-COMMIT-20260915.md +0 -219
  51. package/docs/internal/DIRECTION-CHECK-WB-GRAPH-20260916.md +0 -132
  52. package/docs/internal/FEATURE-INVENTORY.md +0 -531
  53. package/docs/internal/FEEDBACK-TO-DSHAPI-RELAY.md +0 -13
  54. package/docs/internal/G-SERIES-EXECUTION-20260917.md +0 -248
  55. package/docs/internal/G3-DESIGN-20260918.md +0 -82
  56. package/docs/internal/G3-DISK-FORMAT-GAP-20260919.md +0 -92
  57. package/docs/internal/GH-DISCUSSION-5732-COMMENT.md +0 -74
  58. package/docs/internal/GPT-ACCEPTANCE-PROMPT-20260916.md +0 -352
  59. package/docs/internal/GPT-REVIEW-PROMPT.md +0 -216
  60. package/docs/internal/GROUP-DIGEST-SETUP.md +0 -62
  61. package/docs/internal/GROUP-LISTENER-SETUP.md +0 -49
  62. package/docs/internal/GROUP-WEBHOOK-SETUP.md +0 -93
  63. package/docs/internal/HANDOFF-TO-ZCODE-20260920.md +0 -309
  64. package/docs/internal/HANDOFF-TO-ZCODE.md +0 -168
  65. package/docs/internal/HERMES-DATA-VERIFICATION-20260919.md +0 -120
  66. package/docs/internal/HERMES-LEGACY-STATUS-20260919.md +0 -74
  67. package/docs/internal/ISSUE-55-58-VERIFICATION-20260918.md +0 -175
  68. package/docs/internal/ISSUE10-FIX-EXECUTION-20260919.md +0 -389
  69. package/docs/internal/ISSUE10-PLAN-20260919.md +0 -254
  70. package/docs/internal/ISSUE10B-FORENSICS-20260919.md +0 -468
  71. package/docs/internal/ISSUE9-PURGE-AND-R1-PLAIN-20260919.md +0 -150
  72. package/docs/internal/ISSUE9-RESIDUAL-FORENSICS-20260919.md +0 -114
  73. package/docs/internal/KICKOFF-P0.md +0 -254
  74. package/docs/internal/LESSON-TO-CANDIDATE-STATUS-20260919.md +0 -79
  75. package/docs/internal/MASTER-PLAN-3.0.md +0 -411
  76. package/docs/internal/MEMORY-GOVERNANCE-20260917.md +0 -309
  77. package/docs/internal/MEMORY-MUTATION-AND-INDEX-DESIGN.md +0 -85
  78. package/docs/internal/MERGE-CONFLICT-SCAN-20260914.md +0 -222
  79. package/docs/internal/NEXT-VERSION-TODO.md +0 -95
  80. package/docs/internal/OFFICIAL-DISCUSSION-DRAFT.md +0 -80
  81. package/docs/internal/PENDING-FIXES-20260916.md +0 -289
  82. package/docs/internal/PRE-FRONTEND-CHECKLIST-20260919.md +0 -705
  83. package/docs/internal/PRE-FRONTEND-CHECKLIST-20260919.md.bak-s10 +0 -649
  84. package/docs/internal/PROCEDURAL-MEMORY-AND-APPROVAL-DESIGN-20260918.md +0 -225
  85. package/docs/internal/PROGRESS-20260917.md +0 -93
  86. package/docs/internal/PROMPT-GAP-AUDIT-20260920.md +0 -128
  87. package/docs/internal/R1-DEGRADE-AUDIT-20260918.md +0 -163
  88. package/docs/internal/R1-READABILITY-FORENSICS-20260919.md +0 -127
  89. package/docs/internal/R2-EVIDENCE-DEEP-AUDIT-20260918.md +0 -140
  90. package/docs/internal/R3-DEGRADE-LEDGER-DESIGN-20260918.md +0 -138
  91. package/docs/internal/R4-RECALL-QUOTA-PLAN-20260918.md +0 -218
  92. package/docs/internal/RAG-KARPATHY-PROGRAM.md +0 -229
  93. package/docs/internal/RELEASE-PROCESS.md +0 -99
  94. package/docs/internal/REPORT-P0-NIGHTLY.md +0 -212
  95. package/docs/internal/REPORT-P5-ACCEPTANCE.md +0 -31
  96. package/docs/internal/REPORT-WB-GRAPH-NIGHTLY.md +0 -153
  97. package/docs/internal/RESUME-20260918.md +0 -171
  98. package/docs/internal/RESUME-20260919.md +0 -104
  99. package/docs/internal/REVIEW-WB-GRAPH-SELF.md +0 -81
  100. package/docs/internal/RHINELAB-TO-DEEPSEEK-FEASIBILITY.md +0 -198
  101. package/docs/internal/ROADMAP-20260917-WEEK.md +0 -439
  102. package/docs/internal/ROADMAP.md +0 -106
  103. package/docs/internal/RUN-P0-NIGHTLY.md +0 -227
  104. package/docs/internal/S10-CONSTRUCTION-HANDOFF-20260917.md +0 -185
  105. package/docs/internal/S10-GAP-INVENTORY-20260917.md +0 -239
  106. package/docs/internal/S10-GAPS-PLAIN-20260917.md +0 -125
  107. package/docs/internal/SEMANTIC-ARCHITECTURE-SPEC.md +0 -360
  108. package/docs/internal/SESSION-FILE-REPAIR-PROTOCOL.md +0 -90
  109. package/docs/internal/SUBAGENT-REPORT-ROUTING-PRE-RESEARCH.md +0 -261
  110. package/docs/internal/T6-EXECUTION-20260920.md +0 -130
  111. package/docs/internal/TELEMETRY-EFFECT-REPORT-DESIGN-20260918.md +0 -146
  112. package/docs/internal/THESIS-GAP-ANALYSIS-20260918.md +0 -89
  113. package/docs/internal/THESIS-OUTLINE-20260918.md +0 -147
  114. package/docs/internal/THREE-LAYER-CONTRACT.md +0 -219
  115. package/docs/internal/TODO-BACKLOG.md +0 -263
  116. package/docs/internal/TODO-GRAPH.html +0 -715
  117. package/docs/internal/TODO-GRAPH.html.bak-20260914-v2 +0 -493
  118. package/docs/internal/TODO-GRAPH.html.bak-20260915-alsfix +0 -710
  119. package/docs/internal/TODO-GRAPH.html.bak-20260915-p1 +0 -710
  120. package/docs/internal/TODO-GRAPH.html.bak-20260915-p6a-rev +0 -703
  121. package/docs/internal/TODO-GRAPH.html.bak-20260915-wshint +0 -710
  122. package/docs/internal/TODO-GRAPH.html.bak-20260916-batch +0 -715
  123. package/docs/internal/UPSTREAM-ISSUE-PR-TRIAGE-20260919.md +0 -297
  124. package/docs/internal/UPSTREAM-ISSUES-3RD-AUDIT-20260920.md +0 -104
  125. package/docs/internal/WB-FORMAT-CONVENTION.md +0 -112
  126. package/docs/internal/WB-GRAPH-DECISIONS-20260914.md +0 -71
  127. package/docs/internal/WB-GRAPH-INTEGRATION-PLAN.md +0 -386
  128. package/docs/internal/WB-GRAPH-RESEARCH-BRIEF.md +0 -118
  129. package/docs/internal/WB-GRAPH-RESEARCH-EXTERNAL.md +0 -228
  130. package/docs/internal/WB-GRAPH-RESEARCH-LOCAL.md +0 -190
  131. package/docs/internal/reviews/CLAIM-VERIFICATION-20260914.md +0 -56
  132. package/docs/internal/reviews/PLAN-gpt6astra-round2-20260914.md +0 -787
  133. package/docs/internal/reviews/REVIEW-gpt6astra-20260914.md +0 -112
  134. package/docs/internal/reviews/ROUND3-REVIEW-INTEGRATION-20260914.md +0 -230
@@ -1,95 +0,0 @@
1
- # 下一版待改(用户 2026-09-10 19:0x 指定)
2
-
3
- > 来源:用户实机观察 —— 「自动接续又触发了,而且确实才刚过半,太浪费;你现在依靠那个 max output 来算,但官方压缩也是等到上下文真正占到 80% 才开始;新窗口依旧没有按正确序号排序。接续流程我已经关掉了,只要记着下一版怎么改就行。」
4
- > 状态:**✅ 三项已于 v2.5.0(2026-09-13)落地**:①分母=官方声明窗口(reserve 退出分母,新增预测性硬墙 estTokens+reserve>判定窗)②cont-seq.json 持久计数器(全局单调/失败回滚/标题扫描兜底,smoke-test-contseq-pre.mjs)③docs/prompts/RELEASE-AGENT.md 等四份任务书 + RELEASE-PROCESS.md 角色分工。`autoContinueEnabled` 出厂默认仍为 false,是否翻回待用户实机验证后定夺。
5
-
6
- ---
7
-
8
- ## 改点 1 · 水位判据口径:不要把「预留输出」当成分母
9
-
10
- ### 现状(取证到行)
11
- | 位置 | 事实 |
12
- | --- | --- |
13
- | `lib/index.js:1884-1886` | `win = sessModel.contextWindow`(官方声明窗口,本机 deepseek-flash = 1,048,576) |
14
- | `lib/index.js:1899` | `reserve = sessModel.maxTokens`(该路由预留输出,实测 384,000) |
15
- | `lib/index.js:1900` | `effectiveWin = (reserve > 0 && reserve < win*0.9) ? win - reserve : win` → 本机 **664,576** |
16
- | `lib/index.js:1967` | `waterLevelRing = estTokens / win`(声明窗口口径) |
17
- | `lib/index.js:1971` | `waterLevelWall = max(0, hardWin − reserve)`(距硬墙余量) |
18
- | 触发判据 | 走**可用额度口径**(`estTokens / effectiveWin`):实测阈值落在 ≈46 万 token,而**官方压缩要等到约 80% ≈ 83.9 万**才动手 → **早触发约 45%** |
19
-
20
- ### 根因
21
- 把「单次请求的最大可用额度」(`win − reserve`)当成了水位分母。它确实是**单请求硬失败**的边界,但不是**官方压缩**的坐标系 —— 于是水位数被系统性放大,接续在"刚过半"时就触发。
22
-
23
- ### 下一版改法(两条线并行,别只改一半)
24
- 1. **正常接续触发线与官方压缩同坐标系**:分母改用**官方声明窗口 `win`**(或 provider 自报硬限 `hardWin`,取能得到的最小可信值),阈值默认 **0.75–0.78**(略早于官方 0.80,好在压缩丢细节之前完成一次干净交接)。
25
- 2. **保留硬墙保护,但降级为"真会失败才触发"**:仅当 `estTokens + reserve > min(win, hardWin)`(下一次请求就会被拒)时才硬触发。**不要把 reserve 从分母里扣掉** —— reserve 只用于"距硬墙余量"展示与这条硬判据。
26
- 3. **展示与判据解耦**:面板继续显示双口径(本会话水位 / 官方小圈读数 / 距硬墙余量),但**触发只认第 1 条的坐标**;`CONTEXT_WINDOW_EXCEEDED` 与 compaction 事件继续作硬触发(不变)。
27
- 4. 迁移注意:老配置里已落盘的 `autoContinueThreshold`(0.75)在新坐标系下语义等价于"窗口的 75% ≈ 78.6 万",正好落在合理位置;**不需要强制迁移**,但要在设置页 hint 里改口径说明("按官方窗口计,官方在 80% 压缩")。
28
-
29
- ### 验收
30
- - 本机 deepseek-flash 路由:阈值 0.75 时,触发点 ≈ 78.6 万 token(而非 46 万);`waterLevelRing` 与触发比例**同分母**。
31
- - 单请求硬失败保护仍在:构造一条 `estTokens + reserve > win` 的场景,应走硬触发而不是等到比例线。
32
- - 回归:`water-window-pre` / `water-hard-trigger` / `autocont-host` / `water-step` 四个套件全绿(含新增"不得把 reserve 计入分母"的反向锁)。
33
-
34
- ---
35
-
36
- ## 改点 2 · 接续序号(新窗口没按正确序号)
37
-
38
- ### 现状(取证到行)
39
- | 位置 | 事实 |
40
- | --- | --- |
41
- | `lib/index.js:2646-2648` | `contSeq = (handoff 目录里 /^prev-session-.*\.md$/ 的文件数) + 1` |
42
- | `lib/index.js:2533` | 转写包落盘名:`prev-session-<sid8>-<stamp>.md` |
43
- | `lib/index.js:2182-2187` | 宿主兜底路径补的 `sc.rename({sessionId, title: '接续 #' + contSeq + ' · ' + wsBase})`(2026-09-10 才补,此前只有浏览器路径有) |
44
-
45
- ### 疑似根因(下版按序排除)
46
- 1. **计数来源不稳**:序号来自**文件枚举**,而包是"接续时/之后"才落盘的 → 落盘失败、被清理、或写到**别的工作区的 handoffDir**(`p.handoffDir` 是按工作区解析的)时,计数不递增或**跨工作区重复**。
47
- 2. **取数时机**:`contSeq` 在 `buildContinueCarry` 里算,若该次 carry 复用了缓存/旧 pack,`contSeq` 可能为空 → `if (d.contSeq ...)` 不成立 → **不 rename**,标题退回自动生成的"接续上一会话的任务。材料已…"(此现象早前出现过一次)。
48
- 3. **路径覆盖不全**:三条入口(面板一键接续 / 宿主兜底接续 / 重启后接续)是否都拿到了 `contSeq` 并成功 rename,需逐一核对 diag 日志。
49
-
50
- ### 下一版改法
51
- 1. **序号改持久计数器**:`handoff/cont-seq.json`(键 = workspaceId,值 = 已发出的最大序号),取数即 `++`;若文件缺失则回退为"从现有 `接续 #N` 标题/`prev-session-*` 包名里解析最大值 + 1"(兼容老数据)。
52
- 2. **rename 兜底**:把 `contSeq` 为空的情况改为"用持久计数器兜底值"而不是跳过;rename 失败写 diag(现状只有 catch 里一条 diag,需确认两条入口都写)。
53
- 3. **会话列表排序依据**:若侧栏排序仍不按序号,检查是否需要在 rename 后同步排序字段(sequence/title 排序键),不要只改标题。
54
- 4. **落盘顺序**:确认"写包 → 算序号"还是"算序号 → 写包",把序号分配与包落盘做成**同一次事务的顺序**(先分配序号、再写包、失败回滚计数器)。
55
-
56
- ### 验收
57
- - 连续接续 3 次:标题依次为 `接续 #N`、`#N+1`、`#N+2`;换到另一个工作区接续**不重复**已有序号。
58
- - 三条入口各测一次,diag 里都能看到 rename 成功记录。
59
- - 新增 smoke:计数器持久化 + 跨工作区不重复 + 包落盘失败时不跳号。
60
-
61
- ---
62
-
63
- ## 关联现状(改这两个点之前要知道)
64
-
65
- - 用户**已手动关闭自动接续**(`autoContinueEnabled = false`)以免浪费 token;改完需用户自行开启并重启 dsh web 验证。
66
- - `v2.4.1` 已含「已接续闩锁」(`~/.dsh/memory/auto-continue-done.json`),本次"又触发"是在**该闩锁之前就已 arm 的会话**上发生的,不代表闩锁失效;下版验证时要区分"闩锁没拦住"与"口径太早"。
67
- - 相关 diag:`~/.dsh/dsh-auto-memory-pre-diagnose.log`(`auto-continue armed / deferred / deadline reached / rejected at edge / host-executed` 全在这条线上)。
68
-
69
- ---
70
-
71
- ## 改点 3 · 固定流程外包给子代理(主对话只做决策)
72
-
73
- > 用户 2026-09-10 提出:「这种固定流程(尤其是已经多次固化成 skill 的),比如发版本,不应该由主对话来处理,主对话太耗上下文了,应该丢给一个 sub agent,思考强度不用特别高。他做完了或者出错了就扔回主对话,让主对话决定怎么解决。」
74
-
75
- ### 目标形态
76
- - **主对话只做三件事**:①开闸前确认前置门(脏树范围核实 + 全量回归结果)②收到回报后判定放行/中止 ③失败时决定处置方向。**不逐步执行流程**。
77
- - **子代理执行**:按检查表全跑,**出错即停**,回报一个结构化结论:
78
- `{ ok, version, pre_sha, rel_sha, tag, npm_latest, failed_step, error_tail(≤20 行) }`
79
- - **凭据不进提示词**:子代理自行从 `--D--dsh_debug--/MEMORY.md` 读(该处明确「只存本地,严禁写入任何会上传 GitHub/npm 的文件」)。
80
-
81
- ### 落地形态(下版做)
82
- 1. **`docs/prompts/RELEASE-AGENT.md`** —— 给子代理的完整任务书:照 `docs/internal/RELEASE-PROCESS.md` 逐条展开 + 回报格式 + 出错即停规则 + 禁止事项(无 PAT 不得 push、未过闸门不得发布、除版本标识与 CHANGELOG 外不得改文件)。
83
- 2. **`RELEASE-PROCESS.md` 顶部加「角色分工」段**:主对话=决策者 / 子代理=执行者,并写明「主对话不得逐步执行本清单」。
84
- 3. **同类流程一并外包**:全量回归、docs 双语对账、子代理痕迹巡检,各写一份任务书(`docs/prompts/*-AGENT.md`)。
85
-
86
- ### 已知约束(先记下来,免得下版踩)
87
- - **当前工具面无法给 `subagent` 指定思考强度**:`subagent` 只接受 `description/prompt/run_in_background`,`workflow` 的 `agent()` 会**显式拒绝** `effort`/`agentType`。要真压到 low/off 只有两条路:①在 DSH 侧给该路由/预设配默认推理强度;②**由插件自己 spawn** —— 插件已有 `subagentReasoningEffort: off|low|high|max`,经 `ctx.subagents.start({ agentOptions })` 下发。
88
- - **子代理看不到主对话**:任务书必须自包含(路径、命令、判据、回报格式全写死)。
89
- - **不得并发**:同一工作区的写盘流程(尤其发版)必须串行。
90
- - 子代理同样受「不重启宿主」约束:需要重启才生效的事只能回报给用户,不能自己动手。
91
-
92
- ### 验收
93
- - 主对话跑一次发版:其上下文增量只含「开闸判断 + 子代理回报 + 三处复核」三块;
94
- - 故意造一次失败(如抽掉 CHANGELOG 的 `## [<ver>]` 小节):子代理回报 `failed_step=5.05` 且 `error_tail` 含闸门原文,主对话据此给处置;
95
- - 子代理输出里不出现凭据明文(除命令行本身;不落盘、不入 git)。
@@ -1,80 +0,0 @@
1
- # 官方反馈定稿(子代理报告路由)
2
-
3
- > 目标仓库:`deepseek-ai/deepseek-harness`(Discussions · 分类 **General**)
4
- > 发帖入口:https://github.com/deepseek-ai/deepseek-harness/discussions/new?category=general
5
- > 说明:第三方插件 dsh-auto-memory 为**非官方**项目,帖内已按社区规则标注。
6
-
7
- ---
8
-
9
- ## 标题
10
-
11
- ```
12
- [Bug Report] 会话接续后,后台子代理的完成报告仍投递给旧会话;父会话不在册时通知被静默丢弃
13
- ```
14
-
15
- ## 正文
16
-
17
- ```markdown
18
- ## 环境
19
- - `@deepseek-ai/dsh` **0.1.5-rc.1**,Windows 11,web profile
20
- - preset:`standard`(`agent.cordis.yml` 里 `backgroundMode: continuable`,所以后台子代理默认走 continuable 路径)
21
- - 场景:用第三方插件(非官方,我自己维护的 dsh-auto-memory)实现**会话接续**——上下文水位到阈值时新建会话 B、把交接材料注入 B,旧会话 A 仍然 live。
22
-
23
- ## 现象
24
- 1. 会话 A 派出的后台子代理结束后,报告落在 **A** 里;接续出来的会话 **B 收不到**任何东西——用户在 B 里等结果,永远等不到。
25
- 2. 更严重:如果 A 已经被 dispose,这条报告**彻底消失**——没有任何日志、告警或替代投递,表现为“子代理跑了但什么都没回来”。
26
-
27
- ## 最小复现
28
- 1. 在会话 A 里让 agent 起一个后台子代理(`subagent` 工具,默认 `run_in_background`)
29
- 2. 在子代理结束**之前**,把工作搬到会话 B(接续、或手工直接开新会话继续都一样)
30
- 3. 子代理结束后回到 A:报告在 A;B 里什么都没有
31
- 4. 若先关掉 A 再等子代理结束:两边都收不到,也没有任何提示
32
-
33
- ## 代码定位(0.1.5-rc.1,`@deepseek-ai/dsh-subagent/lib/index.js`)
34
- - **运行时绑定**:`activation.parentSession = parent.id`(:1087-1098)在 spawn / cold-resume 时写死为**字符串**;durable 侧 `SessionHeader.parentSession` 也是 readonly(`dsh-session/lib/types/types.d.ts:71`)。
35
- - **结算投递**:`notifySettlement()`(:1244-1259)
36
- \`\`\`js
37
- const parent = this.ctx.agents.get(activation.parentSession)
38
- if (parent === void 0) return // ← 静默丢弃,无日志
39
- const message = createSettlementMessage(activation.childId, terminal)
40
- this.sendWaking(parent, message, parent.status === "idle" ? "queue" : "steer")
41
- \`\`\`
42
- - **契约里没有 re-parent**:`SubagentRuntime` 的公开方法是 `start / startContinuable / sendMessage / interrupt / listChildren / listDescendants / remoteExportList / prompt / interruptByParent / drainContinuableChildren / drainContinuableDescendants / registerProvider / getProvider / list`,**没有 transfer / reassign / attach / rebind**。
43
- - **新会话接不过去**:`sendMessage` → coldResume → `authorizeLineage` 直接抛 `UNAUTHORIZED`(“belongs to another parent session”)。
44
- - **查询侧同父过滤**:`listChildren(newSessionId)` 查不到旧子代理(:2073 按 `record.header.parentSession === parentSessionId` 过滤),只有拿旧 id 才查得到。
45
-
46
- ## 影响
47
- - 任何“会话迁移 / 接续 / 交接”类工作流(插件或人工)都会丢上下文;上下文满得越快,这个操作越常规(我们这边 30 分钟一满)。
48
- - 静默丢弃让问题不可见:没有日志行可查,用户只能看到“子代理没回话”。
49
- - 长跑子代理尤其致命:它们往往正是最需要投递结果的那批。
50
-
51
- ## 建议(任意一条都能覆盖)
52
- 1. 给一个**显式的转发口子**:例如 `subagents.reassign(childId, newParentSessionId)`,或在 `notifySettlement` 前提供可挂载的 hook,让宿主/插件把结算通知投到指定会话;
53
- 2. 或至少把“父不在册”从静默 `return` 改为**可见**:`logger.warn` 一行,并考虑把 `lastAssistantMessage` 落到子会话持久文件、在 catalog 里标出来;
54
- 3. 或让 `listChildren` / `remoteExportList` 支持按**根会话树 / 工作区**查询(现在只有“直系父 id”这一条路),这样接续后的新会话至少能自己发现并读取还在外面跑的子代理。
55
-
56
- ## 我们目前的绕过方案(仅供参考,不要求官方照做)
57
- - 接续前用旧会话 id 调 `listChildren`,把未完成子代理清单写进交接材料;
58
- - 插件旁听 `subagent/end` / `session/event`,收到结算通知就把文本**复制**投给新会话(`agents.get(newId)` → `followup` / `inject`)。
59
- - 局限:这只是“复制”,旧会话仍会收到原件;而且依赖旧会话在结算时仍 live,否则连复制都没有素材。
60
-
61
- (我是 dsh-auto-memory 插件作者,上面提到的插件是**第三方、非官方**项目。)
62
- ```
63
-
64
- ---
65
-
66
- ## 微信群短文案(约 200 字,可直接粘)
67
-
68
- ```
69
- 【DSH 0.1.5-rc.1 · Bug 反馈】子代理完成报告在会话接续后会投错窗口
70
-
71
- 现象:会话 A 派出的后台子代理结束后,报告落在 A;用新会话 B 接着干活时 B 什么都收不到。
72
- 更麻烦的是,如果 A 已关闭,报告会**静默消失**(无日志无告警),看起来就像“子代理跑了但没回话”。
73
- 定位到 dsh-subagent 的 notifySettlement:父会话 id 在 spawn 时写死,结束时按它现查注册表,查不到直接 return。
74
- 插件的落点:dsh-subagent/lib/index.js:1244-1259(静默丢弃在 :1249)。
75
-
76
- 已在官方 Discussions 提了详细报告(含最小复现、代码定位与三条建议):
77
- <在此粘贴讨论链接>
78
-
79
- 希望官方能给一个结算通知的转发/重定向口子,或至少让“父会话不在册”这件事可见。
80
- ```
@@ -1,289 +0,0 @@
1
- # 压缩后施工清单 · 送审前待改项(2026-09-16 归档)
2
-
3
- > **用途**:本窗口上下文将满,本文件是压缩后新窗口的**唯一施工依据**。
4
- > **纪律**:本清单一律以代码/git/API 硬证据为准,不采信卡片自述或记忆自述。
5
- > **时序**:改完 → 全量回归 → 找 ChatGPT 验收 → 一起提交推送。
6
-
7
- ---
8
-
9
- ## ★ 施工完成回执(2026-09-16 本窗口执行)
10
-
11
- **结果:全量回归 `PASS 104 / FAIL 0 / TIMEOUT 0(159.0s)`**(基线 96 ⇒ 净增 8 套件,零失败)。
12
- 工作区改动 **235 项**,仍**未 commit 未 push**(遵守 pre 线纪律)。
13
-
14
- | # | 项 | 状态 | 证据 |
15
- |---|---|---|---|
16
- | 1 | **issue #54** 写入侧保留语法过滤 + 可诊断性 | ✅ 已修 | 新增 `checkReservedSyntaxInContent()`(复用既有 `MARKER_OPEN`);三处写入原语前置拦截;`conflict:` reason 带 `@行号`。套件 `smoke-test-issue54-pre.mjs` 12/12;变异 A/B 真失败(5 条 / 1 条) |
17
- | 2 | **PR #53** DATE_RE 锚定(issue #51) | ✅ 已移植 | `ws-overview-rank.js` 改 `^(\d{4})-(\d{2})-(\d{2})$`(与 `index.js:578` 同源)。套件 `smoke-test-issue51.mjs` 29/29 |
18
- | 3 | **PR #50** EPERM 退避 + 写入失败不降级(issue #48) | ✅ 已移植 | 新增 `lib/fs-retry-pre.js`(有界退避,无 unlink 回退);`atomicReplace` 保留候选快照 + `recoveryPath`;`memory_log/note/user` 失败改为**抛出**(DSH 记 isError,不再假装成功)。套件 37/37;变异真失败(15 条) |
19
- | 4 | **PR #46** welcomeTourEnabled 失效(issue #40) | ✅ 已移植 | 三个自动弹出分支全部过 `allowTour` 闸;配置未知不自动播放;✕ 直接关闭;焦点陷阱。套件 20/20;变异真失败(5 条) |
20
- | 5 | **PR #44** 容量整理净增长(issue #38) | ✅ 已按根因修 | **在 pre 线源码上实测复现**(67→77→87 每轮 +10,8 轮单调 +80)。根因 A:`compactLegacyLayer` 无条件重序列化占位段 (文件头) ⇒ 引入 `synthetic` 标记 + `seqOf()`;根因 B:`replace` 误按旧文件额度计费 ⇒ 按动作分口径。套件 `smoke-test-issue38-pre.mjs` 12/12;变异真失败(6 条) |
21
- | 6 | **PR #49** recall 256 截断(issue #45) | ✅ 已移植 | 移除 `l0Corpus.length = 256` 与 `semanticArm` 的记录预算截断;新增窗口受限提示(未命中≠从未记录)。套件 `smoke-test-issue45-recall-corpus.mjs` 45/45 + `smoke-test-p2-semantic-recall-pre.mjs` 15/15 |
22
- | 7 | **PR #36** 技能晋升(issue #30) | ✅ 已移植 | 新增 `procedure-observation-pre.js` + `intent-clean-safe-pre.js`;去重口径由 **title 改指纹**(标题不是身份);观察行显式 `observationOnly` 且晋升短接为 `observation-only`。套件 36/36 + m81 41/41 + m84 37/37。**并补齐 PR 自身缺失的根因断言**(同名碰撞链),变异真失败(4 条) |
23
- | 8 | **issue #52** 子代理模型被旧 cfg 覆盖 | ✅ 已修 | `set()` 改**函数式更新** + 新增 `setMany()`;三个成对入口改原子更新。套件 `smoke-test-issue52-pre.mjs` 9/9;变异真失败(3 条) |
24
- | 9 | **群反馈 #4 / P0-④d** 注入上限 + 可排除来源 | ✅ 已修 | 新增 `injectExcludeSources` 配置 + `filterExcludedSourcesPre()`(id/整层/目录前缀/精确路径四种口径);在注入闸门**之前**挡下并渲染 `[降级]`;配置端点加类型门。套件 `smoke-test-p0-4d-inject-exclude-pre.mjs` 17/17;变异真失败(3 条)。**上限部分经查已存在**(冻结常量 `TIER_BUDGET_PRE_V1` + `injectBudgetChars`/`tier0BudgetShare`/`tier0MaxTokens`),非缺失项 |
25
- | 10 | **PR #37** 自动接续(issue #35) | ⛔ **未移植(与用户裁定冲突,待裁定)** | pre 线已于 2026-09-14 按**用户裁定方案**修好:`hostAutoContinue()` 先 `sessionController.cancel()` 停旧回合,再仪式、再建新会话;套件 `smoke-test-autocont-host-pre.mjs` 钉死调用顺序 `cancel → prompt → create` 并覆盖降级路径。PR #37 的 `continuation-safety.js` 文件头明写 **"no cancel of source work"**、改用 idle 门 —— 与 `index.js:3222` 记录的用户裁定**直接相反**。**须用户裁决后再动** |
26
- | 11 | **群反馈 #1** 接续互锁 | ✅ 已确认为已修 | 见 §5(四处带日期解耦 + 回归套件) |
27
-
28
- ### 施工期间发现并修掉的**额外**缺陷(不在原清单内)
29
-
30
- **issue #54 守卫暴露出一个既有的静默结构损坏**(由 `smoke-test-m3b3-pre.mjs` E7 抓出):
31
- `maintain()` 的"无 AI 蒸馏"回退分支把 `archive/` 里日志**原文**内联进 `MEMORY.md`,而原文首行是
32
- **旧日志自己的 anchor marker** ⇒ 该 marker 变成 `MEMORY.md` 的结构锚点,产生一条**幻影记录**
33
- (身份属于旧日志、却挂在笔记上)。修前之所以"没报错",是因为整行合法 marker 能被 `parseAnchors`
34
- 当锚点吃下 —— 属**静默结构损坏**,比报错更危险。
35
-
36
- - 修法:新增 `stripAnchorLines()`(只剥整行合法 marker,正文一字不动),并在 `appendText()` 的
37
- **写入边界统一收口**(一处覆盖全部调用方),而非逐调用点打补丁。
38
- - 实测证据:未剥离 ⇒ `appendAnchoredRecord` 直接**拒绝**(fail-closed);剥离后 ⇒ 锚点恰为 2 条
39
- 合法记录、无幻影、`旧日志条目` 正文仍可读。
40
- - 连带修正:`smoke-test-m3b2-pre.mjs` 的 D7 断言按 PR #50 语义更新(tmp 保留为恢复快照而非清理);
41
- `smoke-test-p4-l0-response-pre.mjs` 的 import 正则放宽(允许同源附加导入)。
42
-
43
- ### 变异演示总账(全部真失败,非假绿)
44
-
45
- | 套件 | 变异 | 结果 |
46
- |---|---|---|
47
- | issue#54 | 移除 append 守卫 / 移除 replaceSingle 守卫 | 5 条 / 1 条失败 ✅ |
48
- | issue#48 | 退避重试只试 1 次 | 15 条失败 ✅ |
49
- | issue#40 | 三处 `allowTour` 闸还原 | 5 条失败 ✅ |
50
- | issue#38 | `seqOf` 退回无条件 `'## '+title` | 6 条失败 ✅ |
51
- | issue#30 | 去重回退按 title 匹配 | 4 条失败 ✅ |
52
- | issue#52 | `set()` 退回读闭包快照 | 3 条失败 ✅ |
53
- | 反馈#4 | 排除过滤退化为不过滤 | 3 条失败 ✅ |
54
-
55
- **还原纪律**:每次变异后按 SHA256 逐字节校验还原(`memory-writer-pre.js`、`fs-retry-pre.js`、
56
- `client.js`、`index.js`、`procedure-store-pre.js`、`tier-layer-inject-pre.js` 均已核对一致)。
57
-
58
- ---
59
-
60
- ## 0. 当前基线(压缩前实测,供新窗口复核)
61
-
62
- | 项 | 值 |
63
- |---|---|
64
- | 仓库 | `D:\dsh-auto-memory`(pre 线,**未 commit 未 push**) |
65
- | 工作区改动 | **204 项**(含本文档) |
66
- | 窗口内 git 提交 | **0** |
67
- | 全量回归 | `node tools/run-smoke.mjs` → **PASS 96 / FAIL 0 / TIMEOUT 0(143.3s)** |
68
- | graph 套件 | `tests/smoke/smoke-test-graph-mode-pre.mjs` → **35 断言** |
69
- | 三处工具数硬锁 | legacy=**14**(`smoke-test.mjs:67`、`smoke-test-m3b3-pre.mjs:43`、`smoke-test-context-observer.mjs:107`) |
70
- | 本地 vs 远程 | 分叉:本地 `main` 领先 **122** 提交,`origin/main`(`794717d`) 领先 **60** 提交 |
71
- | 已推送内容 | 仅 3 个文档:`README.md`、`README.zh-CN.md`、`docs/CONTRIBUTORS.html`(提交 `794717d`,零删除) |
72
-
73
- **重要事实**:`CHANGELOG.md` **本地完好**(32KB,git 跟踪中,工作区干净),但**远程线上从来没有过**(分叉点 `89bd636` 与 `origin/main` 均无)。它是提交 `89641dc` 在**本地线**引入的。**文件没丢**,是两条历史线不同步造成的错觉。合并本地线时它会随之上线。
74
-
75
- ---
76
-
77
- ## 1. 群反馈 9 条 · 代码实测现状
78
-
79
- 来源:`docs/internal/TODO-GRAPH.html`(原文卡片 + points 已抽取核对)。
80
- **判定口径**:已在代码中 grep 验证,非采信卡片状态。
81
-
82
- | # | 反馈内容 | 卡片状态 | **代码实测** | 归档 |
83
- |---|---|---|---|---|
84
- | 1 | 接续/强制接续互锁失效;默认**不强制**接续(省成本) | P0-A 封存 3.1 | ✅ **已修(2026-09-14 解耦)** — 见 §5 调研结论 | **无需改**(卡片状态过时) |
85
- | 2 | 设置里 subagent「模型+思考强度」**选不动** | P0-B 封存 3.1 | `subagentModel`/`reasoningEffort` 配置项**都在**;未查到 disabled 保护 | **要改** → 同 issue **#52**(无 PR) |
86
- | 3 | 晋升开关:项目记忆→全局记忆可开可关 | P1-8 | `procedurePromotionEnabled` **存在** ✔ | 已有开关;晋升逻辑本身坏 → 见 #8 |
87
- | 4 | 注入上限 + 可排除来源("避免记忆问题一路走错") | P0-4d **待开工** | 注入上限:`maxInjectChars`/`injectCap`/`snapshotMaxChars` **全 0 命中** ✘;排除来源:仅有 `superseded`,**无用户级排除** | **要改**(确未做) |
88
- | 5 | 晋升物要**可读**("我都不知道是啥技能") | P1-8 | 归入 #8 | 见 #8 |
89
- | 6 | 手机端首次指引**太大且关不掉** | P2-12 远期 | `welcomeTourEnabled` 开关**存在** | **要改** → 同 issue **#40**,有 PR **#46 未合并** |
90
- | 7 | 日历太粗糙,**换开源方案** | P2-11 待调研 | 仍自研 `CALENDAR.md`;`fullcalendar`/`tui-calendar`/`calendar.js` **0 命中** | **本批不改**(新功能,撑大审查面) |
91
- | 8 | 长时攻关也晋升 + skill 互相指路 | P1-8 封存 3.1 | `skillHandoff`/`breakthrough`/`longRunning` **全 0 命中** ✘ | **要改** → 同 issue **#30**,有 PR **#36 未合并** |
92
- | 9 | webhook CI 安全收口(签名/限流/密钥) | P2-9 待确认 | `.github/cloud/qq-webhook/index.zip` **仍入库** | **本批不改**(运维项,与审查面无关) |
93
-
94
- ---
95
-
96
- ## 2. 未关闭 issue / PR 全景(15 条,2026-09-16 快照)
97
-
98
- ### 2.1 有 PR 且未合并(7 组)
99
-
100
- | Issue | PR | 内容 | 本地是否已有修复 | 归档 |
101
- |---|---|---|---|---|
102
- | #38 | **#44** | 笔记容量整理净增长(每轮 +10 字符 → 最终所有写入被永久拒绝) | ❌ 无 | **P0 必合** |
103
- | #40 | **#46** | `welcomeTourEnabled=false` 无效,向导仍自动弹;移动端浮层吞点击 | ❌ 无 | **P0 必合** |
104
- | #45 | **#49** | `memory_recall` 够不到 ~5 天前记录(256 条 L0 预算挤出) | ❌ 无 | **P0 必合** |
105
- | #48 | **#50** | `atomicReplace` 缺 EPERM 退避重试,Windows 并发子代理下硬失败 | ❌ 无(本地 `EPERM` grep **0 命中**) | **P0 必合** |
106
- | #51 | **#53** | `ws-overview-rank` DATE_RE 未锚定,恢复候选误计活跃度 | ❌ 无(本地 `DATE_RE = /\d{4}-\d{2}-\d{2}/` **仍非锚定**) | **P0 必合** |
107
- | #30 | **#36** | **技能固化永远无法晋升**(episode 候选未如实标记) | ❌ 无 | **P0 必合**(对应群反馈 #8) |
108
- | #35 | **#37** | 自动接续 `agree` 路径绕过回合活跃防护,新旧会话并行 | ❌ 无 | **P0 必合** |
109
-
110
- ### 2.2 无 PR(需自修)
111
-
112
- | Issue | 内容 | 归档 |
113
- |---|---|---|
114
- | **#52** | 子代理模型选择被旧 cfg 覆盖:已删除模型无法切换/清空 | **P0 自修**(对应群反馈 #2) |
115
- | **#54** | **[P0] 写入侧缺保留语法过滤:单条含 `MARKER_OPEN` 的正文使整个记忆文件永久拒写** | **P0 自修**(用户新提,见 §3) |
116
-
117
- ### 2.3 已关闭(背景)
118
-
119
- #43(channel test)、#42(gh_api 多 token 验收)——测试条目,忽略。
120
-
121
- ---
122
-
123
- ## 3. issue #54 详析(用户 09-16 15:39 新提)★
124
-
125
- **标题**:`[P0] 写入侧缺少保留语法过滤:单条含 MARKER_OPEN 的正文会使整个记忆文件永久拒写`
126
-
127
- **一句话**:`appendAnchoredRecord()` 只校验**文件已有内容**是否干净,**从不校验本次要写入的正文**。
128
-
129
- **根因(带行号)**:
130
- - `lib/memory-writer-pre.js:95-111` — `appendAnchoredRecord(content, {memoryId, text})`
131
- - `text` 的唯一检查是 `!text.trim()`(第 96 行)
132
- - `parseAnchors(buf)` 解析的是 **`buf`(既有文件)**,不是 `text`
133
- - 末段 `body = toEol(text, ...)` 仅做行尾转换,随后 `'<!-- memory:' + id + ' -->'` **原样拼接落盘**
134
- - `MARKER_OPEN` 常量**只出现在** `lib/memory-anchor-pre.js:177/182`(读取路径),**写入路径零引用**
135
- - `parseAnchors` 判定(`memory-anchor-pre.js:177-186`):`includes(MARKER_OPEN)` → 判 `orphan-content` **fail closed**
136
-
137
- **后果**:一次误写 → 从**下一次写入起**该文件**全部写入被永久拒绝**(`conflict:orphan-content`,size/mtime 不再变化)。不是丢一条,是**该 workspace 项目笔记写入能力整体中断**。
138
-
139
- **为什么"转义"救不了**:`parseAnchors` **无转义机制**(不认反引号/代码块/HTML 实体);反引号包裹不匹配 `MARKER_RE` 但 `.includes()` 照样命中 ⇒ 仍判冲突。
140
-
141
- **用户给的修复建议**:
142
- - **P0** 所有落盘路径(`appendAnchoredRecord()` / `renderReplace()` 等)对入参 `text`/`replacement` 做 `MARKER_OPEN` 检测。二选一,**建议先做 (a)**:
143
- - (a) **拒绝并明确报错** `reason: 'reserved-syntax-in-content'`(与既有 fail-closed 语义一致)
144
- - (b) 提供显式 `sanitizeContent(text)` 辅助,由调用方主动调用
145
- - **禁止静默改写**(会导致落盘内容与用户原文不一致且无感知)
146
- - **P1** 可诊断性:当前错误不带行号/文件路径;而 `parseAnchors` 的 conflict 对象**其实已带 `line`/`byteStart`/`byteEnd`**(`memory-anchor-pre.js:184`),只是被 `memory-writer-pre.js:68/102` 的 `.map(c => c.type)` **丢掉了**。修:错误信息保留行号 + 文件路径。
147
- - **P2**(可选)区分"本次写入引入的冲突"vs"文件本来就有冲突"(当前同一错误,误导调用方)。
148
-
149
- **用户说"一次代码复用就可以做到"** ⇒ 指 **写入侧复用已有的 `MARKER_OPEN` 常量 + 检测**(该常量已在 `memory-anchor-pre.js` 导出/存在,写入路径 import 即可),成本极低。
150
-
151
- **验收方法**:修复后,写入含保留串的正文应当 ① 立即返回明确错误(方案 a)或落盘已安全改写(方案 b);② 后续良性写入不受影响。
152
-
153
- **应急 SOP(若已逃逸)**:备份 `MEMORY.md.bak-<yyyyMMdd-HHmmss>` → Node 脚本定位「含 MARKER_OPEN 但不匹配 MARKER_RE」的行 → **仅改写该行措辞**(逐行核对,行数不变)→ 一次良性写入验证恢复。
154
-
155
- ---
156
-
157
- ## 4. 送审范围裁定(压缩后按此执行)
158
-
159
- ### 4.1 本批必改(P0,共 11 项)
160
-
161
- **A. 合并外部 PR(7 个)**:#44、#46、#49、#50、#53、#36、#37
162
- > 均为 Minervaowl7 提交,其上一批 #31-#34 已合并入 `origin/main`,质量可信。彼此有关联(#44↔#38 同一处容量逻辑),**建议全合而非挑选**。
163
-
164
- **B. 自修(3 项)**:
165
- 1. **issue #54**(写入侧保留语法过滤 + P1 可诊断性)★ 用户明示"一次代码复用"
166
- 2. **issue #52**(子代理模型选择被旧 cfg 覆盖)— 群反馈 #2
167
- 3. **群反馈 #4**(注入上限 + 可排除来源,P0-4d「待开工」确未做)
168
-
169
- **C. 已完成,无需再动(1 项)**:
170
- 4. **群反馈 #1**(接续互锁)— ✅ **已修(2026-09-14 解耦)**,见 §5 调研结论
171
-
172
- ### 4.2 本批**不改**(明确排除)
173
-
174
- | 项 | 理由 |
175
- |---|---|
176
- | 群反馈 #7 日历换开源 | 卡片状态"待调研",属**新功能**,会撑大审查面 |
177
- | 群反馈 #9 webhook CI 收口 | 运维项,与 3.0 审查面无关 |
178
- | **subagent 智能调度**(用户提的"智能判断是否使用子代理施行") | **未实现的新功能**(`shouldSpawn`/`judgeSubagent`/`needSubagent` grep **全 0 命中**)。现有子代理能力是"被动调用"(时段总结/问候/自动沉淀),**不存在调度判断**。塞进本批会让审查面从 3 件事膨胀到 12 件事 ⇒ **单独排一批** |
179
-
180
- > **必须向用户说明的一点**:用户希望"验证重构后长期系统是否做到去除 harness 记忆争议点"(① 重复多次项目如发版能否被识别为模式 ② 重大攻关/有价值套件 skill 化 + 智能调度子代理)。
181
- > **修 issue/PR 不经过"长期记忆系统"这条路,两者没有验证关系**——修 bug 是修 bug。
182
- > 真实验证点应落在:
183
- > - ①/②:`lib/procedure-store-pre.js` 的 `sessionDiversity≥3 && successCount≥2` 晋升门槛 + `observed/candidate/validated` 三级 + `/memory-hub` 审批队列。**但该能力现在是坏的**(issue #30)⇒ 修 #30/#36 后**才具备验证前提**。
184
- > - ③:**根本没实现**,不是"重构后没做好"。
185
-
186
- ---
187
-
188
- ## 5. 群反馈 #1 调研结论(已修,无需再动)★
189
-
190
- **用户裁定**:「我觉得应该是修好了。」→ **调研证实用户判断正确。**
191
-
192
- ### 5.1 一个误导性信号(我上次的取证错误,须记住)
193
-
194
- `git log -S "forceContinue"` **全历史零命中** —— 该字样**从未在代码里存在过**。
195
- "强制接续"是群里描述症状的**口语说法**,不是配置键名。
196
- ⇒ **凭"某字样消失"判定功能被移除是错的。** 判"是否修好"必须找**行为断言**:
197
- 解耦注释 + 判定函数收口 + 回归套件,而不是找字样。
198
-
199
- ### 5.2 三处带日期、带根因的解耦(真修复)
200
-
201
- | # | 位置 | 修的内容 | 注释原文要点 |
202
- |---|---|---|---|
203
- | 1 | `lib/index.js:2562` | **关白板 ⇒ 自动接续被静默关掉** | 旧实现 `if (handoffEnabled === false) return` ⇒ 水位永不测量 ⇒ `waterLevelModelKnown` 永不写入 ⇒ `shouldArmAutoContinuePre` 的 fail-closed 闸永远拒绝 arm ⇒「**关白板会把自动接续一并静默关掉(实证:确认卡永不出现)**」。改为**测量与白板解耦**(测量只读,产物另由 `handoffEnabled` 把关) |
204
- | 2 | `lib/index.js:2740` | **反向耦合**:白板关 + 水位越阈 ⇒ 照样写账本并覆盖快照 | 「测量放行后,这条**产物**写入必须由 `handoffEnabled` 单独把关,否则『白板关 + 水位越阈』会照样写交接账本并覆盖 `latestHandoffText`(反向耦合)」 |
205
- | 3 | `lib/index.js:3189` | **卡片可用性**被白板连累 | 「旧实现的 `&& handoffEnabled !== false` 是**同一处耦合的第二份副本**(白板关 ⇒ 卡片报 disabled)」⇒ 改为只判 `autoContinueEnabled` |
206
- | 4 | `lib/index.js:5218` | 完整复盘(设计说明) | 「**不是记错,是开关耦合的缺陷**:改前 `autoContinueEnabled` 只管接续资格与 GUI 卡片可用性;而水位自动账本写入只判 `handoffEnabled`/`waterLevelAutoHandoff`,**从不看接续开关**。症状即『不跳窗口、却照样写账本并覆盖 `latestHandoffText`』」+ 语义依据:`waterLevelAutoHandoff` 唯一目的是给自动接续备料,接续关了 ⇒ 没人来接 ⇒ 账本无用且污染快照 |
207
-
208
- ### 5.3 当前三开关语义(已解耦)
209
-
210
- ```
211
- handoffEnabled = false # 白板:只管产物(写/读 PLAN + 账本)
212
- autoContinueEnabled = false # 接续:只管资格 + 卡片可用性
213
- waterLevelAutoHandoff = true # 水位账本:受 handoffChainEnabledPre() 统一把关
214
- ```
215
-
216
- 判定**同源**:`handoffChainEnabledPre()`(`lib/index.js:5234`)统一收口,
217
- 注释明写「与置位点、写入点同源,**避免三处条件漂移**」。
218
-
219
- ### 5.4 有回归套件锁住(非口头承诺)
220
-
221
- ```
222
- tests/smoke/smoke-test-switch-decouple-pre.mjs 24.0KB ← 专门锁"开关解耦"
223
- tests/smoke/smoke-test-autocont-host-pre.mjs 35.1KB
224
- tests/smoke/smoke-test-water-hard-trigger-pre.mjs 12.9KB
225
- tests/smoke/smoke-test-water-step-pre.mjs 6.3KB
226
- tests/smoke/smoke-test-water-window-pre.mjs 16.2KB
227
- ```
228
-
229
- **结论**:群反馈 #1 **已修**,`TODO-GRAPH.html` 的 P0-A 卡片状态「封存(3.1)」**已过时**,
230
- 可在下次回写看板时更新为「已解耦(2026-09-14)」。**本批不动此项。**
231
-
232
- ---
233
-
234
- ## 6. 施工顺序(**已于 2026-09-16 执行完毕**)
235
-
236
- ```
237
- 第 1 步 合并远程 60 提交 → 本地(解决 CHANGELOG 缺失 + 拿到已合并的 #31/#32/#33/#34)
238
- ⚠️ 不可逆操作 —— **本轮未执行**(等用户裁定;不阻塞其余施工)
239
- 第 2 步 合并 7 个外部 PR → ✅ 已移植 6 个;#37 因与用户裁定冲突**挂起待裁**
240
- 第 3 步 自修 3 项(#54 ★ / #52 / 群反馈 #4)→ ✅ 全部完成
241
- 第 4 步 群反馈 #1 —— ✅ 已确认为已修(2026-09-14 解耦),跳过(见 §5)
242
- 第 5 步 全量回归 + 定向变异演示 → ✅ **PASS 104 / FAIL 0 / TIMEOUT 0(159.0s)**,7 组变异全部真失败
243
- 第 6 步 → 交 ChatGPT 验收(任务书:docs/internal/GPT-ACCEPTANCE-PROMPT-20260916.md,
244
- 按本批新增内容更新「声称交付」章节)—— **待执行**
245
- 第 7 步 按验收结论修完 → 一起提交推送 —— **待执行(需用户明确同意)**
246
- ```
247
-
248
- **关键经验(写给下一个窗口)**:外部 PR 打的是**发布线布局**(`lib/memory-writer.js` 等裸名),
249
- 而 pre 线运行的是 `-pre.js` 具名模块 ⇒ **`git apply` 必然失败**。正确姿势是:
250
- ① `git fetch origin pull/<n>/head` 取分支实体;② 读 PR 的**意图与根因**;
251
- ③ 在 pre 线**按根因重写**(保留 pre 线已有的加固,如 `isCurrentPre` 状态闸、`compactAnchoredLayer` 重做);
252
- ④ 落 PR 自带测试并把 `import` 路径改到 `-pre` 模块、把发布线命名(`memory_recall`/`idx_`/`proc_`/`hub`)
253
- 改回 pre 线命名(`memory_recall_pre`/`idx_pre_`/`proc_pre_`/`hub-pre`);
254
- ⑤ **不要假设 PR 的测试是充分的** —— #36 的用例没覆盖它自己的根因(同名碰撞链),必须补断言。
255
-
256
- ---
257
-
258
- ## 7. 硬约束(贯穿全程)
259
-
260
- 1. **禁止无差别杀 node 进程**(DSH harness 与插件宿主都在 node 上,2026-09-14 出过事故)。
261
- 2. **`dsh web` 宿主由用户自行重启**,agent 只改文件并说明需重启;严禁 `Stop-Process`/`Start-Process`。
262
- 3. **无 BOM**(任何文件写完须校验前 3 字节 ≠ `EF BB BF`)。
263
- 4. **大文件分块写**,一次工具调用不写超大内容。
264
- 5. **改前备份**(`*.bak-YYYYMMDD-<tag>`);**变异演示基线必须是当前版本备份**(旧备份曾整体回滚改造)。
265
- 6. **代码留在 pre 线**,未经用户明确同意不 commit/push/publish。
266
- 7. 结论必须附代码/日志证据;推断显式标注为推断。
267
- 8. **先核 evidence 再采信**:卡片状态、记忆自述、他人交接声明一律以硬证据为准。
268
-
269
- ---
270
-
271
- ## 8. 关键路径索引
272
-
273
- | 用途 | 路径 |
274
- |---|---|
275
- | 全量回归 | `D:\dsh-auto-memory\tools\run-smoke.mjs` |
276
- | graph 端到端套件 | `D:\dsh-auto-memory\tests\smoke\smoke-test-graph-mode-pre.mjs`(35 断言) |
277
- | issue #54 根因文件 | `D:\dsh-auto-memory\lib\memory-writer-pre.js`(:95-111、:68/:102) |
278
- | issue #54 检测常量 | `D:\dsh-auto-memory\lib\memory-anchor-pre.js`(:27-29 常量、:177-186 判定、:184 带行号) |
279
- | 技能晋升逻辑 | `D:\dsh-auto-memory\lib\procedure-store-pre.js`(:251 `promote()`、:54 门槛) |
280
- | 群反馈原始卡片 | `D:\dsh-auto-memory\docs\internal\TODO-GRAPH.html`(P0-A/P0-B/P0-4d/P1-8/P2-9/P2-11/P2-12) |
281
- | 送审任务书 | `D:\dsh-auto-memory\docs\internal\GPT-ACCEPTANCE-PROMPT-20260916.md` |
282
- | 本次全量粗检审计 | `D:\dsh-auto-memory\docs\internal\AUDIT-WB-GRAPH-FULL-20260916.md` |
283
- | 施工方自审(3 致命+6 高/中危) | `D:\dsh-auto-memory\docs\internal\REVIEW-WB-GRAPH-SELF.md` |
284
- | 3.0 蓝本 | `D:\dsh-auto-memory\docs\internal\MASTER-PLAN-3.0.md` |
285
-
286
- ---
287
-
288
- **归档时间**:2026-09-16 21:20 · **归档人**:施工方(本窗口 agent)
289
- **数据来源**:GitHub API 实时查询(`state=all`,15 条未关闭)+ `TODO-GRAPH.html` 卡片抽取 + 代码 grep 实测