@furongjun1999/dsh-memory 0.5.1 → 0.6.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 (187) hide show
  1. package/README.md +588 -552
  2. package/codebuddy/CODEBUDDY.md +10 -10
  3. package/data/policy.json +27 -0
  4. package/docs/discipline/harnesses.yaml +31 -0
  5. package/docs/discipline/templates/full.md.tmpl +1 -1
  6. package/docs/discipline/templates/rules.mdc.tmpl +1 -1
  7. package/docs/eval/DSH/346/227/245/345/277/227/347/264/242/345/274/225v2_/345/217/202/350/200/203dsh-TUI_v1.0.md +248 -0
  8. package/docs/eval/DSH/346/227/245/345/277/227/347/264/242/345/274/225/346/225/210/346/236/234/351/252/214/350/257/201_v1.0.md +209 -0
  9. package/docs/eval/DSH/347/253/257/347/274/272/351/231/267/344/270/223/351/241/271_v1.0.md +254 -0
  10. package/docs/eval/N225_/347/264/242/345/274/225/346/227/245/345/277/227/351/235/236/345/257/271/350/261/241/350/243/205/350/275/275/351/235/242/347/261/273/345/236/213/351/227/270_v1.0.md +418 -0
  11. package/docs/eval/P1b2_/350/257/273/351/235/242/344/273/243/351/231/205/344/277/256/345/244/215_v1.0.md +124 -0
  12. package/docs/eval/issue43_/351/273/230/350/256/244/347/255/226/347/225/245/344/270/216/351/224/256/347/261/273/345/236/213/351/227/270_v1.1.md +441 -0
  13. package/docs/eval/issue43_/351/273/230/350/256/244/347/255/226/347/225/245/345/212/240/350/275/275/344/270/216/345/207/255/346/215/256/346/230/216/346/226/207/351/230/237/345/210/227_v1.0.md +398 -0
  14. package/docs/eval//344/274/230/345/214/226/347/254/254/344/270/200/346/211/271_/346/216/245/347/272/277/344/270/216/347/255/211/344/273/267/345/217/230/346/215/242_v1.0.md +498 -0
  15. package/docs/eval//344/274/230/345/214/226/347/254/254/344/270/211/346/211/271_/351/227/250/347/246/201/350/275/254/346/255/243/344/270/216/350/260/203/345/272/246/346/255/242/350/241/200/344/270/216/351/227/250/346/216/247/346/224/266/345/217/243_v1.0.md +669 -0
  16. package/docs/eval//344/274/230/345/214/226/347/254/254/344/272/214/346/211/271_/344/276/235/350/265/226/351/200/217/344/274/240/344/270/216/345/257/271/346/213/215/345/217/243/345/276/204/344/270/216/350/264/237/347/274/223/345/255/230_v1.0.md +683 -0
  17. package/docs/eval//345/217/221/345/270/20306_/344/270/200/351/224/256/351/205/215/347/275/256/344/270/216DSH0172_v1.0.md +171 -0
  18. package/docs/eval//345/217/221/345/270/20307_/345/244/226/351/203/250/346/212/245/345/221/212/345/233/233/346/211/271/344/277/256/345/244/215/344/270/216/346/217/222/344/273/266/351/235/242/345/212/240/345/233/272_v1.0.md +205 -0
  19. package/docs/eval//346/200/247/350/203/275/344/270/223/351/241/271_/345/206/267/346/237/245/350/257/242/344/270/216/345/206/205/345/255/230_v1.0.md +218 -0
  20. package/docs/eval//346/225/205/351/232/234/346/263/250/345/205/245/345/256/236/346/265/213_v1.0.md +10 -0
  21. package/docs/eval//347/274/226/347/240/201/351/235/242/345/211/215/347/275/256_/345/205/245/345/217/243/350/207/252/344/277/235/350/257/201UTF8/344/270/216/346/226/207/346/234/254open/345/256/210/345/215/253_v1.0.md +646 -0
  22. package/docs/eval//347/274/272/351/231/267/346/214/226/346/216/230_/350/207/252/344/270/273/350/277/255/344/273/243_v18.md +183 -0
  23. package/docs/eval//347/274/272/351/231/267/346/214/226/346/216/230_/350/207/252/344/270/273/350/277/255/344/273/243_v19.md +207 -0
  24. package/docs/eval//347/274/272/351/231/267/346/214/226/346/216/230_/350/207/252/344/270/273/350/277/255/344/273/243_v20.md +283 -0
  25. package/docs/eval//347/274/272/351/231/267/346/214/226/346/216/230_/350/207/252/344/270/273/350/277/255/344/273/243_v21.md +224 -0
  26. package/docs/eval//347/274/272/351/231/267/346/214/226/346/216/230_/350/207/252/344/270/273/350/277/255/344/273/243_v22.md +223 -0
  27. package/docs/eval//347/274/272/351/231/267/346/214/226/346/216/230_/350/207/252/344/270/273/350/277/255/344/273/243_v23.md +293 -0
  28. package/docs/eval//347/274/272/351/231/267/346/214/226/346/216/230_/350/207/252/344/270/273/350/277/255/344/273/243_v24.md +303 -0
  29. package/docs/eval//347/274/272/351/231/267/346/214/226/346/216/230_/350/207/252/344/270/273/350/277/255/344/273/243_v25.md +230 -0
  30. package/docs/hive//346/243/200/347/264/242/350/267/257/345/276/204/344/270/216/350/256/244/347/237/245/347/273/223/346/236/204/345/245/221/347/272/246_v0.1.md +20 -0
  31. package/docs/hive//350/234/202/345/267/242M6_ingest/345/256/236/346/226/275/350/256/241/345/210/222_v0.1.md +1 -1
  32. package/docs/mdcg/README/350/257/246/347/273/206/347/211/210_v0.4.10.md +12 -0
  33. package/docs/mdcg//345/212/237/350/203/275/350/260/203/347/224/250/346/230/240/345/260/204/350/241/250_v0.1.md +40 -40
  34. package/docs/mdcg//345/217/221/345/270/203/351/227/250/347/246/201/351/223/276_v0.1.md +21 -9
  35. package/docs/mdcg//347/201/265/346/236/242/350/256/260/345/277/206/345/212/250/350/257/215/345/215/217/350/256/256_v1.0-draft.md +7 -2
  36. package/docs/mdcg//350/256/244/347/237/245/345/233/276_/347/264/242/345/274/225/344/270/216/345/267/245/347/250/213/350/247/204/350/214/203/345/214/226_/350/256/241/345/210/222_v0.1.md +39 -3
  37. package/docs/plans//345/205/250/344/270/255/346/226/207/347/274/226/347/240/201/344/270/216/350/234/202/345/267/242/344/273/273/345/212/241/346/240/207/350/257/206/345/245/221/347/272/246_v2.0.md +220 -0
  38. package/docs/plans//347/234/237/346/272/220/347/264/242/345/274/225_/351/200/232/347/224/250/346/234/272/345/210/266_v0.3.md +227 -0
  39. package/docs/plans//350/234/202/345/267/242/346/250/241/345/236/213/345/257/206/351/222/245/351/205/215/347/275/256/351/235/242_v1.0.md +385 -0
  40. package/docs//345/267/245/344/275/234/347/272/252/345/276/213_/350/256/244/347/237/245/345/233/276/346/235/241/347/233/256_v1.1.json +460 -460
  41. package/dsh/cordis-patch-profile-web.example.yml +35 -0
  42. package/lib/bridge.js +24 -2
  43. package/lib/cli.d.ts +3 -0
  44. package/lib/cli.js +66 -0
  45. package/lib/hooks.d.ts +31 -2
  46. package/lib/hooks.js +219 -16
  47. package/lib/init.d.ts +88 -0
  48. package/lib/init.js +302 -0
  49. package/lib/lib/prompt_safety.d.ts +52 -1
  50. package/lib/lib/prompt_safety.js +76 -1
  51. package/md_cg/audit.py +652 -379
  52. package/md_cg/bench6_arms.py +1 -1
  53. package/md_cg/bench_p0.py +1 -1
  54. package/md_cg/branches.py +2 -2
  55. package/md_cg/ccgc.py +1071 -1006
  56. package/md_cg/chain.py +1 -1
  57. package/md_cg/consistency.py +97 -9
  58. package/md_cg/consolidate.py +34 -9
  59. package/md_cg/crypto.py +59 -26
  60. package/md_cg/docindex.py +16 -1
  61. package/md_cg/evidence.py +585 -582
  62. package/md_cg/evolution.py +17 -1
  63. package/md_cg/export.py +1 -1
  64. package/md_cg/forgetting.py +309 -13
  65. package/md_cg/fsutil.py +454 -8
  66. package/md_cg/identity.py +3 -3
  67. package/md_cg/insight.py +24 -3
  68. package/md_cg/linkref.py +1 -1
  69. package/md_cg/logref.py +327 -0
  70. package/md_cg/mcp_server.py +4152 -3818
  71. package/md_cg/mdcg.py +4208 -3462
  72. package/md_cg/mdcos.py +4491 -4137
  73. package/md_cg/mreview/pipeline.py +15 -1
  74. package/md_cg/nodefile.py +639 -575
  75. package/md_cg/protect.py +158 -11
  76. package/md_cg/protocol.py +41 -2
  77. package/md_cg/provenance.py +22 -4
  78. package/md_cg/reach.py +4 -4
  79. package/md_cg/readcache.py +76 -15
  80. package/md_cg/reconcile.py +1 -1
  81. package/md_cg/refindex.py +246 -37
  82. package/md_cg/refine.py +1 -1
  83. package/md_cg/review_cli.py +49 -4
  84. package/md_cg/routing.py +32 -5
  85. package/md_cg/run_tests.py +17 -0
  86. package/md_cg/scrub.py +30 -3
  87. package/md_cg/security.py +47 -1
  88. package/md_cg/self_state.py +5 -5
  89. package/md_cg/sources.py +23 -6
  90. package/md_cg/srcindex.py +352 -0
  91. package/md_cg/stg.py +47 -3
  92. package/md_cg/subgraph.py +2 -2
  93. package/md_cg/sustain.py +1299 -1168
  94. package/md_cg/tasks.py +469 -470
  95. package/md_cg/test_b1_auto_id_multiproc.py +277 -0
  96. package/md_cg/test_b1b2_write_face.py +417 -0
  97. package/md_cg/test_b2_sensitivity_landing.py +223 -0
  98. package/md_cg/test_b3_merge_keeps_content.py +576 -0
  99. package/md_cg/test_b4_shard_dir_selfheal.py +843 -0
  100. package/md_cg/test_b4_shard_dir_selfheal_guard.py +238 -0
  101. package/md_cg/test_c3_transient_read_negative.py +793 -0
  102. package/md_cg/test_c8_search_rrf_gates.py +502 -0
  103. package/md_cg/test_ccg_form_parity.py +188 -0
  104. package/md_cg/test_ccgc.py +28 -3
  105. package/md_cg/test_govern_directread.py +17 -4
  106. package/md_cg/test_h2_session_view_norm.py +233 -0
  107. package/md_cg/test_h4_sustain_snapshot.py +1377 -0
  108. package/md_cg/test_hive_ingest.py +285 -285
  109. package/md_cg/test_index_crossprocess_reload.py +301 -0
  110. package/md_cg/test_issue39_utf8_stdio.py +307 -16
  111. package/md_cg/test_issue43_default_policy.py +865 -0
  112. package/md_cg/test_legacy_p3_node_id_type.py +375 -0
  113. package/md_cg/test_linkref.py +10 -3
  114. package/md_cg/test_lock.py +2 -2
  115. package/md_cg/test_logref.py +1109 -0
  116. package/md_cg/test_m3_h9_bucket_health_protect_mark.py +301 -0
  117. package/md_cg/test_m3_h9_semantic_guard.py +525 -0
  118. package/md_cg/test_mr_m2.py +15 -3
  119. package/md_cg/test_n130_verify_falsified_protect.py +1 -1
  120. package/md_cg/test_n139_dek_provision_failclosed.py +185 -0
  121. package/md_cg/test_n176_link_trust.py +221 -0
  122. package/md_cg/test_n178_units_jobid_gate.py +212 -0
  123. package/md_cg/test_n184_keys_concurrent_provision.py +307 -0
  124. package/md_cg/test_n195_writepath_reload.py +283 -0
  125. package/md_cg/test_n196_stale_gate_skip.py +169 -0
  126. package/md_cg/test_n197_n208_write_face_gates.py +471 -0
  127. package/md_cg/test_n198_tokens_corrupt_failclosed.py +225 -0
  128. package/md_cg/test_n199_tokens_concurrent_write.py +378 -0
  129. package/md_cg/test_n201_proposal_visibility.py +382 -0
  130. package/md_cg/test_n202_session_notes_visibility.py +461 -0
  131. package/md_cg/test_n204_n205_n226_n227_n228_n229_exit_gates.py +542 -0
  132. package/md_cg/test_n206_stdio_jsonrpc_type.py +403 -0
  133. package/md_cg/test_n209_verify_write_face_gates.py +461 -0
  134. package/md_cg/test_n212_n213_n224_generation_gates.py +513 -0
  135. package/md_cg/test_n214_n215_n221_n222_write_face_gates.py +563 -0
  136. package/md_cg/test_n225_nonobject_load.py +1110 -0
  137. package/md_cg/test_n62_tenant_bind_failclosed.py +200 -0
  138. package/md_cg/test_neg_condition_hits.py +333 -0
  139. package/md_cg/test_neg_tail_honesty.py +663 -0
  140. package/md_cg/test_none_id_write_guard.py +166 -0
  141. package/md_cg/test_opt_batch1_md_cg.py +451 -0
  142. package/md_cg/test_p1.py +5 -5
  143. package/md_cg/test_p11_consistency.py +161 -12
  144. package/md_cg/test_p26_refindex.py +2 -2
  145. package/md_cg/test_p27_docindex.py +777 -774
  146. package/md_cg/test_p28_refcheck.py +740 -13
  147. package/md_cg/test_p29_session_ingest_export.py +2 -2
  148. package/md_cg/test_p2_mcp.py +12 -1
  149. package/md_cg/test_p30_maintain.py +33 -2
  150. package/md_cg/test_p31_insight.py +1 -0
  151. package/md_cg/test_p9c_dedup_hints.py +276 -0
  152. package/md_cg/test_policy_required_ccg.py +426 -0
  153. package/md_cg/test_protocol.py +22 -0
  154. package/md_cg/test_rank_parity_score_mode.py +516 -0
  155. package/md_cg/test_read_face_input_gates.py +363 -0
  156. package/md_cg/test_read_face_semantics.py +489 -0
  157. package/md_cg/test_recall_face_guards.py +812 -0
  158. package/md_cg/test_rejected_credential_forms.py +188 -0
  159. package/md_cg/test_rejected_redact.py +146 -0
  160. package/md_cg/test_retr_s1b.py +2 -2
  161. package/md_cg/test_retr_s5.py +20 -7
  162. package/md_cg/test_review_cli_attribution.py +177 -0
  163. package/md_cg/test_review_cli_visibility.py +235 -0
  164. package/md_cg/test_review_conformance.py +21 -3
  165. package/md_cg/test_security_audit_v21.py +2 -2
  166. package/md_cg/test_server_version.py +67 -0
  167. package/md_cg/test_srcindex.py +171 -0
  168. package/md_cg/test_tenant_env_override_warn.py +63 -50
  169. package/md_cg/test_token_lowercase_form.py +315 -0
  170. package/md_cg/test_v21r1_package_version.py +310 -0
  171. package/md_cg/test_writepipe.py +10 -4
  172. package/md_cg/tokens.py +225 -95
  173. package/md_cg/tool_face.py +4 -4
  174. package/md_cg/trust.py +49 -5
  175. package/md_cg/units.py +204 -6
  176. package/md_cg/weights.py +4 -4
  177. package/md_cg/whitebox_kb/wisdom/knowledge_points.py +1 -1
  178. package/md_cg/writelimit.py +42 -8
  179. package/md_cg/writepipe.py +651 -554
  180. package/package.json +8 -2
  181. package/skills/plugin.json +1 -1
  182. package/src/bridge.ts +25 -2
  183. package/src/cli.ts +65 -0
  184. package/src/hooks.ts +229 -16
  185. package/src/init.ts +361 -0
  186. package/src/lib/prompt_safety.ts +88 -1
  187. package/zcode/AGENTS.md +10 -10
@@ -0,0 +1,209 @@
1
+ # DSH 日志索引效果验证报告 v1.0
2
+
3
+ - **日期**:2026-09-27
4
+ - **修订记录**:v1.0(隐私门禁整改重写:期望事实改为 ≤50 字「事实点」并重新措辞、全文去本机盘符路径与编码路径的目录名、不留日志原话式长句)
5
+ - **对象**:`scripts/dsh_log_index.py`(新增,**未 commit**——git status 仅此一个 untracked 文件,编排会话负责提交)及其产出的 `dsh-log-` 检索面
6
+ - **数据来源**:摄取统计、幂等复跑、五案检索、dry-run 快照对照的实测记录由摄取/验证会话提供(本文标注「实测记录」);报告撰写会话独立复核了全部代码引证(逐条读码比对)、git 状态与 CLI 参数面,并实跑两件回归套件(见 §2.4、§七)。凡撰写会话未实跑的检查,均如实标注,不冒充为本会话实跑。
7
+ - **隐私**:本报告不含 DSH 会话日志正文原文;查询词为验证用查询词(纪律允许),日志派生内容一律以 ≤50 字、重新措辞的「事实点」呈现;只含统计与计数;全文不含盘符绝对路径,日志目录一律写「DSH 会话根」,命令中敏感路径用 `<DSH会话根>`、`<活库root>` 占位。
8
+
9
+ ---
10
+
11
+ ## 一、背景
12
+
13
+ DSH 端曾执行「停自动写入」决策:不再把会话过程自动写进记忆库。该决策成立的前置件是——**会话日志作为冷真源必须可被事后检索**:日志若既不自动入库、又检索不到,历史会话的结论就彻底丢失,停自动写入等于信息黑洞。本次工作即偿还这笔 DSH 端欠账:
14
+
15
+ 1. 新增离线摄取工具 `scripts/dsh_log_index.py`:DSH 会话日志(zstd jsonl)→ 转写 md(系统临时目录、路径确定)→ 直调生产同款索引入口,摄取进**私有活库**的灵枢检索面;
16
+ 2. 对目标会话完成摄取并实测幂等;
17
+ 3. 以五个真实信息需求做检索效果验证,逐层实证闭合未命中根因,给出三个 gap、对照发现与使用边界。
18
+
19
+ ---
20
+
21
+ ## 二、工具与摄取统计
22
+
23
+ ### 2.1 工具形态
24
+
25
+ **新增 1 个独立摄取脚本** `scripts/dsh_log_index.py`,仓库无其他改动(git status 仅此一个 untracked 文件,撰写会话已复查确认)。CLI 参数面(撰写会话经 `grep add_argument` 逐项核实):
26
+
27
+ | 参数 | 语义 |
28
+ |---|---|
29
+ | `--sessions-root` | **必选**,DSH 会话根 |
30
+ | `--root` | 灵枢库 root,缺省取 `MDCG_ROOT` 环境变量 |
31
+ | `--session` / `--workspace` | 过滤:只处理指定会话 id / 工作区目录名 |
32
+ | `--dry-run` | 只转写、只统计,不写库 |
33
+ | `--allow-init` | 允许初始化空库 |
34
+ | `--actor` / `--tenant` | 写入身份,缺省 `dsh-memory` / `default` |
35
+ | `--cleanup-transcripts` | 摄取后清理转写暂存(缺省保留在系统临时目录确定路径) |
36
+
37
+ 管线:DSH 会话日志(zstd jsonl)→ 转写 md → 直调**生产同款索引入口**摄取灵枢检索面。
38
+
39
+ ### 2.2 摄取统计(实测记录)
40
+
41
+ - **活库节点数 14140 → 14159(+19)**,全部为 `dsh-log-` 前缀新节点;既有节点零修改零删除(活库只增不删)。
42
+ - 目标会话 `session-927e3b6a-cae2-45b7-b1dc-c650b5fa927e`(位于 DSH 会话根下特定工作区目录;该目录名含本机盘符形态编码,本报告不录,复现时经 `--workspace` 传实际目录名):
43
+ - 1387 行日志 → 转写 **18 条用户轮 + 14 条助手轮(43077 字符)**;
44
+ - 跳过 1162 行其他类型 + 145 行无正文助手消息 + 15 条重复事件 + 0 行 JSON 错误;
45
+ - 章节切分产出 **19 章全部落库**,密级全部 `private`;
46
+ - 归因:session=该会话 / writer=dsh-memory / harness=dsh。
47
+
48
+ ### 2.3 语义裁定(六条,读码定案)
49
+
50
+ ① **摄取路由选定「经 MdCGSecure 直调同款索引入口」而非 `cg index_doc` op**:读码发现 `index_doc` 的节点 id 由 `docindex.node_id` 硬编码为 `doc_` 前缀(`md_cg/docindex.py:284`),无法满足 `dsh-log-` 前缀要求;故章节切分直调与 `index_doc` op **完全同一实现**的 `refindex.index_dir(kind="doc_ref")`(内含 `docindex.extract` 的 level≤3 切分 / 小节合并 / 围栏感知),写入侧逐条对照 `refindex.add_items` 的 doc_ref 分支(`md_cg/refindex.py:378-392`),仅节点 id 改为 `dsh-log-<会话id>-<章节序号>` 且不写 doc_ref 列。*(撰写会话已读码复核上述三处引证。)*
51
+
52
+ ② **不写 doc_ref / 不登记 Ledger 的原因**:转写文件是临时目录暂存物,绑定列会系统性 dangling,且 `op=ref` 回读会开第二个日志原文暴露面;溯源改记 `frontmatter.dsh_log`(session/workspace/source/transcript/heading_path/lineno/end,已实测落盘)。
53
+
54
+ ③ **检索覆盖遵循生产章节切分语义**:直接正文 <200 字的小节并入父节摘要(`docindex` 的 `MIN_BODY=200`,`md_cg/docindex.py:41`),故 33 个转写节中 19 个形成独立节点,其余在父节摘要(生产 `MAX_SUMMARY=200`,`md_cg/docindex.py:42`)与父节区间内。docindex 的设计即「**不存全文,节点正文=CCG 模板+摘要**,正文一律回读」(`md_cg/docindex.py:13-14`;模块头注 `md_cg/docindex.py:2`)。
55
+
56
+ ④ **幂等语义**:节点 id 确定性 + 写入前查索引,已存在即计 `nodes_skipped_existing` 跳过(不覆写既有节点,符合活库只增不删)。
57
+
58
+ ⑤ **private 档按 `_readable` 会话绑定**:仅归属会话的 MCP 面 + 设计者可读;写入身份与在役插件一致(tenant=default / actor=dsh-memory,复用既有 DEK 信封);转写体内的 markdown 标题样行首加反斜杠转义防切分误认(68 处,不改动正文一字)。
59
+
60
+ ⑥ **输出仅统计/计数/node id**,全程未打印日志正文(仅摘录 ≤50 字用于选查询词);转写暂存按确定路径保留在系统临时目录(`--cleanup-transcripts` 可选清理),实验快照临时文件已清理。
61
+
62
+ ### 2.4 检查清单(实测记录;标注撰写会话复跑项)
63
+
64
+ | # | 检查 | 命令 / 方法 | 结果 | 本会话复跑? |
65
+ |---|---|---|---|---|
66
+ | ① | 摄取 | `python scripts/dsh_log_index.py --sessions-root <DSH会话根> --session session-927e3b6a-cae2-45b7-b1dc-c650b5fa927e --root <活库root>` | 输出 `nodes_indexed=19` / sensitivity `{private:19}`;库索引复查 `dsh-log-`=19、总节点 14159 | 否(触活库,实测记录) |
67
+ | ② | 幂等 | 同命令重跑 | `nodes_indexed=0` / `nodes_skipped_existing=19`,库内 `dsh-log-` 仍 19 个(无重复) | 否(触活库,实测记录) |
68
+ | ③ | 检索 | 以会话属主 Principal 开 MdCGSecure 调 `cg.search` | 「现在有你么」→ 命中 `dsh-log-…-0000` score 1.0;「执行通道」→ 命中 `dsh-log-…-0002` score 1.0;附加「zcode汇报」→ 命中 `-0007`/`-0010` 均 1.0(注:泛词「记忆」被 14k 节点全库挤出 top10,非未索引) | 否(触活库,实测记录) |
69
+ | ④ | dry-run | 先拍活库快照(节点 14140 / `_index.json` mtime_ns 与 size / md 文件 14232)→ 跑 `--dry-run` | 四项指标逐项相等,且摄取前库内 `dsh-log-` 节点为 0,断言 PASS | 否(触活库,实测记录) |
70
+ | ⑤ | 回归 | `python -m md_cg.test_p27_docindex`;`python -m md_cg.test_p1x_ref_root`(index_doc 面既有测试 grep 所得两件均跑) | **98 通过 / 0 失败**;**10/10 通过** | **是**——撰写会话实跑复现同结果 |
71
+
72
+ ---
73
+
74
+ ## 三、检索效果验证(逐查询)
75
+
76
+ 五案均为真实信息需求,按三层读者形态实测:①活库副本直调(无 DEK,词法面);②管线重放临时库(自带 KEK 重放摄取,33 节点与在役库逐条同 id)+ **归属会话读者**(唯一合法可读面);③后续新会话读者与 can_admin 设计者读者。实测记录(验证会话),撰写会话未重跑。各案「期望事实」以**事实点**呈现(≤50 字、重新措辞,非日志原文摘录)。
77
+
78
+ ### C1 沙箱启动错误
79
+
80
+ - **查询词**:DSH 里 run_code 一执行就报 worker-exit 退出,沙箱给工作区挂写权限失败,是什么错误?
81
+ - **期望事实**(事实点):
82
+ - 阶段:worker 沙箱启动期失败,run_code 零执行(turn1)
83
+ - 报错 API:SetNamedSecurityInfoW
84
+ - 错误码:Win32 5(ACCESS_DENIED)
85
+ - 对象:给工作区目录挂 grantWrite 授权失败
86
+ - **实测**:
87
+ 1. 在役库临时副本直调(MdCGOS 无 DEK,k=30):top5 全为 `mem_*` 手工归档节点,`dsh-log-` 节点 0 进榜——`dsh-log` 正文是 `mdcg-enc:v1` 密文(sensitivity=private 落盘即加密),明文词法零重叠,以『SetNamedSecurityInfoW grantWrite 沙箱』三个专名组成逐字诊断查询也不现身;`search` 与 `search_rrf` 同。
88
+ 2. 管线重放临时库 + 归属会话读者:含该事实的块 `dsh-log-…-0004` 存在(token 幸存),但全排序仅 **13/19**,top-5 未进。
89
+ 3. 后续新会话读者与 can_admin 设计者读者:scanned=0,全不可见。
90
+ - **命中**:**否**。
91
+
92
+ ### C2 工作区目录与真实仓库位置
93
+
94
+ - **查询词**:当前 DSH 的工作区目录怎么是空的?真正的 dsh-memory 仓库到底在哪里?
95
+ - **期望事实**(事实点):
96
+ - DSH 工作区目录:会话初始化按需创建的空容器(turn2)
97
+ - 实测 entryCount=0(空目录)
98
+ - 真实仓库另有其处:即本报告所在仓库的检出目录
99
+ - **实测**:
100
+ 1. 活库副本直调:top5 无 `dsh-log-`;该事实在活库由 `mem_1790416361175`(交接单,第 5 名)等手工归档节点覆盖。
101
+ 2. 重放库 + 归属会话读者:含该事实的块**不存在**——检索词『dsh-memory-main』在全部 19 块解密内容中零命中——该结论位于 turn2 助手消息深处,被 docindex 摘要截断(每章渲染仅 759–1034 字),根本未入库,检索无从命中。
102
+ 3. 其他读者形态不可见。
103
+ - **命中**:**否**。
104
+
105
+ ### C3 会话日志体积与用户输入占比
106
+
107
+ - **查询词**:那份 DSH 会话日志解压之后有多大?用户真实输入在里面能占多大比例?
108
+ - **期望事实**(事实点):
109
+ - 日志 691 个 zstd 帧;解压约 4.04 MB;1323 个事件(turn14)
110
+ - user/message 仅 17 条,占比约 0.08%
111
+ - assistant/message 占比约 55.4%
112
+ - **实测**:
113
+ 1. 活库副本直调:无 `dsh-log-` 进榜。
114
+ 2. 重放库 + 归属会话读者:**命中排名 1/19**★——`dsh-log-…-0017` 含『4.04』『691』(该节开头部分幸存截断);但 0.08%/1323/55.4% 等表格数据在 turn 深处被截掉,节点只含部分事实。
115
+ 3. 后续会话/设计者读者:不可见。
116
+ - **命中**:**是(部分事实)**。
117
+
118
+ ### C4 dsh web 重启不生效与后台编排
119
+
120
+ - **查询词**:为什么在会话里直接发起 dsh web 重启总是不生效?后台编排进程为什么没跑起来?
121
+ - **期望事实**(事实点):
122
+ - 会话内 pwsh 解释器不存在,仅有 Windows PowerShell(turn9-10)
123
+ - DETACHED_PROCESS 编排器随 run_code worker 退出被宿主连带回收
124
+ - 该编排器未活过 15 秒延迟启动窗
125
+ - 结论:dsh web 重启必须走宿主侧
126
+ - **实测**:
127
+ 1. 活库副本直调:无 `dsh-log-` 进榜。
128
+ 2. 重放库 + 归属会话读者:完整事实块不存在——检索词『detached_process』在 19 块中零命中(turn10 深处被截断);仅含『pwsh』的 `dsh-log-…-0013` 排第 4/19,top-5 有部分证据但不含宿主回收因果链,按全事实判据不命中。
129
+ 3. 其他读者形态不可见。
130
+ - **命中**:**否**。
131
+
132
+ ### C5 落盘成功但在役 MCP read 返回 null
133
+
134
+ - **查询词**:review_cli 落盘成功、磁盘索引里也能看到新节点,为什么在役 MCP 服务 read 还是返回 null?
135
+ - **期望事实**(事实点):
136
+ - 在役进程仅在启动时装载索引快照(turn12)
137
+ - 快照时点 22:13:16,约 14135 节点
138
+ - 其后不复查磁盘索引变化 → 跨进程写入不可见
139
+ - 对应缺陷线:P1b-2 读面缓存代际
140
+ - 探针节点 dsh_restart_recheck_20260926 为留存活体用例
141
+ - **实测**:
142
+ 1. 活库副本直调:top5 无 `dsh-log-`;该结论由手工归档面覆盖(`mem_1790416403598` 交接增补第 1 名、探针节点 `dsh_restart_recheck_20260926` 第 5 名)。
143
+ 2. 重放库 + 归属会话读者:检索词『dsh_restart_recheck_20260926』『14135』在 19 块解密内容中零命中——turn12 的时间戳证据链全部落在截断线之后,事实块未入库;返回的 4 条相关块均不含该事实。
144
+ 3. 其他读者形态不可见。
145
+ - **命中**:**否**。
146
+
147
+ ---
148
+
149
+ ## 四、效果总评
150
+
151
+ **总评**:`dsh-log-` 检索面在『唯一合法可读面』(重放库+归属会话读者)上 top-5 全事实命中率 **1/5**(且为部分事实),在现实使用面(后续新会话『后来想知道』)**0/5**——后者不可见是**设计行为**(private 会话绑定,`md_cg/mdcos.py:3948-3956`,issue #35 使用者拍板)。未命中根因链已逐层实证闭合,三个 gap:
152
+
153
+ **① 摄取覆盖率 gap(最重)**:docindex 设计为『不存全文,节点正文=CCG 模板+摘要』(`md_cg/docindex.py:13-14`、`md_cg/docindex.py:42` 行 `MAX_SUMMARY=200`),全文依赖 ref 回读,而 `scripts/dsh_log_index.py:50-54` **有意不写 doc_ref 绑定**(转写是临时暂存物)——实测转写 md 43,878 字符仅 14,805 字符入库(**覆盖率 33.7%**),66.3% 正文永久缺席,turn 深处的结论(C2/C4/C5 三案)物理不存在,任何检索器都无法命中。
154
+
155
+ **② 可见性 gap**:节点 frontmatter.session 绑死摄取时的会话 id,会话一换(重启/新会话即换 id)即永久不可见;设计者 can_admin 能过会话闸但过不了密钥闸——DEK 按 (tenant, actor) 签发(`md_cg/crypto.py:290-314`),封/开 AAD 均绑写入者 actor(`md_cg/mdcos.py:3764`/`md_cg/mdcos.py:3784`),跨 actor 永远解不开密——模块自述目标『使历史会话正文可被 cg search 检索面召回』(`scripts/dsh_log_index.py:7` 头注)在除『复用原会话 id』外的任何读者形态下均不成立。
156
+
157
+ **③ 排名 gap**:幸存块中数字/专名类事实(4.04MB)排第 1,共享词表高的叙事类事实(沙箱错误)仅排 13/19——19 块共享纪律尾注词表,判别弱。
158
+
159
+ **已验证的机制面**:同身份往返实验(自带 KEK、全新临时库)命中排名 1、异身份不可见;三会话重放 2+19+12=33 节点与在役库逐条同 id,分块确定性无漂移——**管线机制本身无缺陷,问题在截断与可见性策略**。
160
+
161
+ **对照发现**:在活库中 C2/C5 的信息需求实际由 internal 密级手工归档节点(`mem_*`)满足并进 top-5,『手动写记忆』面当前是可检索主力,`dsh-log` 面贡献 ≈0。
162
+
163
+ **边界与未测项**:按隐私纪律未触真实令牌库(~/.mdcg)与在役 serve 进程,持真实 DEK 的在役服务实测表现未测,此为本验证的残余盲区;在役库全程只读(实验全在临时副本/重放库),验证期间在役库簿记文件有一次 00:09:48 的写入系在役 serve 自身 sustain 周期心跳(已排除本验证责任:`refindex.index_dir` 仅在显式传 ledger 时才写,`md_cg/refindex.py:302`/`md_cg/refindex.py:323`,本验证未传);全部临时实验产物已清理,实现员的转写暂存目录非本验证创建,保留未动。
164
+
165
+ ---
166
+
167
+ ## 五、使用指引(命令 / 参数 / 幂等)
168
+
169
+ 环境:`set PYTHONUTF8=1`(第 15 条:argv 列表 + 显式 UTF-8,不经 Windows shell)。依赖:`zstandard`(pip);`md_cg` 包(脚本自注仓库根进 sys.path)。
170
+
171
+ ```text
172
+ # ① 先看会碰到什么:不写库,只转写 + 统计
173
+ python scripts/dsh_log_index.py --sessions-root <DSH会话根> --dry-run
174
+
175
+ # ② 按会话摄取进活库(--root 缺省取 MDCG_ROOT)
176
+ python scripts/dsh_log_index.py --sessions-root <DSH会话根> --root <灵枢库root> --session <session-id>
177
+
178
+ # ③ 按工作区过滤 / 指定写入身份
179
+ python scripts/dsh_log_index.py --sessions-root <DSH会话根> --workspace <工作区目录名> --actor dsh-memory --tenant default
180
+ ```
181
+
182
+ - **空库首摄**须显式 `--allow-init`;对已有库不加该参数即拒绝初始化(防误指 root)。
183
+ - **幂等**:节点 id 由 (session-id, 章节序号) 决定 → 确定性;转写路径确定(临时根 + 工作区 + 会话 id),重跑生成逐字节相同的转写;写入前查活库索引,已存在即计 `nodes_skipped_existing` 跳过,**不覆写**(活库只增不删)。已实测:重跑 `nodes_indexed=0` / `nodes_skipped_existing=19`,库内无重复。
184
+ - **回收钩子**:节点 id 前缀 `dsh-log-` 专用于识别与将来回收;当前无删除路径,回收须待活库 deletion 策略裁决。
185
+ - **转写暂存**:默认保留在系统临时目录的确定路径(溯源见节点 frontmatter.dsh_log 的 transcript 字段);要即清即加 `--cleanup-transcripts`。
186
+ - **读取边界(重要)**:摄取出的 private 节点仅**归属会话**(principal.session 绑定)与设计者可读;换会话后即不可见(见 §四 gap ②)——不要预期新会话能检索到旧会话的 `dsh-log-` 节点。
187
+
188
+ ---
189
+
190
+ ## 六、遗留与建议
191
+
192
+ 按影响排序(均为建议,未实施;在役库只增不删,任何方案须带 `dsh-log-` 前缀回收钩子):
193
+
194
+ 1. **覆盖率(最重)**:66.3% 正文缺席使该面在『turn 深处结论』类问题上结构性失明。可选方向:(a) 把转写从「临时暂存」升级为「库侧受控持久化」,恢复 doc_ref 绑定与 `op=ref` 回读面——需先裁决日志原文第二暴露面的隐私代价;(b) 保持不存全文,但对该面提高摘要密度(多级切分 / 放宽 `MAX_SUMMARY`)——治标,深处结论仍会漏。
195
+ 2. **可见性**:会话绑定 + DEK 按 (tenant, actor) 的双重闸,使该面只服务『复用原会话 id』单一读者形态。若目标是跨会话召回,须走策略裁决(如读面代理身份 / 密钥迁移),**不要**试图绕过密钥闸;短期现实做法是:重要结论仍走『手动写记忆』面落 internal 节点(现状已证明其是可检索主力)。
196
+ 3. **排名**:19 块共享纪律尾注词表压低判别力;若保留该面,可在转写时剥离/压缩共享尾注,让块间词表拉开区分度。
197
+ 4. **定位声明**:三 gap 修复前,`dsh-log-` 摄取面**不宜**当作常规检索依赖;其当前价值在机制验证(分块确定性、幂等、加密落盘)与审计溯源(frontmatter.dsh_log)。
198
+ 5. **残余盲区**:持真实 DEK 的在役 serve 表现未测(隐私纪律禁触);若需要在役面验证,须由在役侧授权的专用探针会话执行。
199
+ 6. **工程收尾**:`scripts/dsh_log_index.py` 为 untracked,待编排会话评审后 commit。
200
+
201
+ ---
202
+
203
+ ## 七、纪律合规声明
204
+
205
+ - **隐私(工程纪律第 9 条)**:DSH 会话日志为私有侧数据,摄取目标仅为私有活库 root,未触公开库;本报告与工具输出均不打印日志正文原文——查询词为纪律允许的验证用查询词,日志派生内容一律以 ≤50 字、重新措辞的事实点呈现(v1.0 整改项:期望事实事实点化、去本机盘符路径与编码路径目录名、去日志原话式长句);命令与说明中日志目录一律写「DSH 会话根」占位。
206
+ - **活库保护**:在役库只增不删——+19 全为 `dsh-log-` 前缀新节点,既有节点零修改零删除(摄取 ①/幂等 ② 双实测佐证);实验全在临时副本/重放库进行,在役库全程只读(验证期间唯一一次簿记写入系在役 serve 自身 sustain 心跳,已排除本验证责任,证据见 §四边界项)。
207
+ - **临时产物**:验证会话全部临时实验产物已清理;实现员的转写暂存目录非本验证创建,保留未动。
208
+ - **撰写会话自查范围(诚实边界)**:撰写会话实跑项 = ①`git status --porcelain`(确认仅 `?? scripts/dsh_log_index.py`);②全部代码引证逐条读码比对(`scripts/dsh_log_index.py:2-67` 头注/用法、`md_cg/docindex.py:2/13-14/41/42/284`、`md_cg/refindex.py:302/323/378-392`、`md_cg/mdcos.py:3948-3956/3764/3784`、`md_cg/crypto.py:290-314`);③CLI 参数面 `grep add_argument` 核对(九个参数与 §2.1 表逐项一致);④`python -m md_cg.test_p27_docindex` → 通过 98 / 失败 0;⑤`python -m md_cg.test_p1x_ref_root` → 10/10 通过;⑥隐私预扫描(见下)。摄取统计、幂等复跑、五案检索、dry-run 快照对照为验证会话实测记录,撰写会话未重跑(触活库/私有会话根,按隐私纪律不重复触达)——文中已逐处标注,未将记录冒充为本会话实跑。
209
+ - **隐私预扫描(撰写会话实跑,成稿后对文件全文执行)**:①盘符路径扫描(逐字符查「字母+冒号+斜杠」形态)→ 0 条;②门禁提示中的命中形态字面串(「命中」+全角冒号)→ 0 条;③已删的两处日志原话短语复查(不在此复述其字面)→ 0 条;④「期望事实」事实点逐条长度实测 → 19 条全部 ≤50 字(实测最长 47 字)。扫描以单条 `python -c` 串实现(unicode 转义定位模式,避开 shell 转义链路),计数输出:`drive_paths: 0 / hit_colon_lit: 0 / removed_phrases: 0 / fact_bullets: 19 max_len: 47 over50: []`。
@@ -0,0 +1,254 @@
1
+ # DSH 端缺陷专项修复报告 v1.0
2
+
3
+ - **日期**:2026-09-26
4
+ - **范围**:DSH 端(插件另一端)在役实测报告四组缺陷的修复落地。定性由编排会话读码完成,本轮为修复与验证的如实汇编;修复落点全部在本仓 `md_cg/`(记忆引擎/工具面)与 `scripts/`(工具孪生件),不改 DSH 侧代码。
5
+ - **基线**:工作区 HEAD `2ae15a63`(main)之上的未提交改动——`git status --short` 实测:修改 7 件(`md_cg/evidence.py`、`md_cg/mdcg.py`、`md_cg/mdcos.py`、`md_cg/review_cli.py`、`scripts/linkref_backfill.py`、`scripts/migrate_restricted.py`、`scripts/review_cli.py`),新增守卫 3 件(`md_cg/test_review_cli_visibility.py` 235 行、`md_cg/test_review_cli_attribution.py` 177 行、`md_cg/test_none_id_write_guard.py` 165 行)。未 git commit(编排会话负责)。
6
+ - **材料来源**:第二节逐项修复的 target/前后对比/语义变化/验证主体来自编排会话交付的三份修复材料(修复轮实跑记录);本报告撰写会话对全部关键引证做了逐条读码复核,**材料行号与当前工作区实测有漂移处已按实测修正**(校勘明细见附录清单二末尾),三个守卫套件在本会话重跑全绿(实测输出见第三节、第四节)。
7
+
8
+ ---
9
+
10
+ ## 一、总览
11
+
12
+ DSH 端在役实测报告四组缺陷,经编排会话读码定性后,处置矩阵如下:
13
+
14
+ | 组 | 标签 | 缺陷一句话定性 | 处置 | 结果 |
15
+ |---|---|---|---|---|
16
+ | 可见性 | **P1b** | review_cli 裁决落盘节点在 MCP 读面不可见——autoflush 兜底的第二落点遗漏(server 级 2026-09-16 已修,工具面四处构造漏补) | 代码修复(4 处构造补 `autoflush=1` + 红守卫) | 已修;守卫 10/0(本会话重跑 EXIT=0) |
17
+ | 归因 | **P1** | review_cli 随机会话 + accept 落盘 writer 被 designer-cli 覆盖,原始写入者不可追溯 | 代码修复(`--session` + 归因保留 + 红守卫) | 已修;守卫 10/0(本会话重跑 EXIT=0) |
18
+ | 归因(环境侧) | **P1-1** | DSH 会话目录若不在 `_normalize_session` 校验面内(`MDCG_DSH_SESSIONS_ROOT` / `~/.dsh/sessions`),该会话在 MCP 写入面降级 anonymous,CLI 与 MCP 两侧归因对不上 | 环境侧回告(按要求非代码修) | 回告,复验清单见第五节 |
19
+ | 脏节点 | **P3** | `knowledge/orphan/None.md` 脏节点写入源头——node_id 字符串化污染形态(`"None"`/`"null"`)在写入边界放行 | 代码修复(写入边界整串精确等值闸 + 红守卫)+ 存量清理建议回告 | 已修;守卫 17/0(本会话重跑 EXIT=0) |
20
+ | 待排期 | **P4 / P5** | 本轮材料未含其定性细节(如实注明,不入虚构内容) | 入缺陷池 | 不入本轮,见第六节 |
21
+
22
+ 四组归并:①可见性组(P1b)②归因组(P1 + 其环境侧面 P1-1)③脏节点组(P3)④其余(P4/P5 入池)。三项代码修复共用同一条工程链路:读码定性 → 修复落点 → 红守卫先红后绿 → 定向回归 → 组全量/门禁。
23
+
24
+ ---
25
+
26
+ ## 二、逐项修复
27
+
28
+ ### 2.1 P1b——review_cli 裁决落盘节点在 MCP 读面不可见(autoflush 兜底第二落点遗漏)
29
+
30
+ **target**:短命裁决/工具进程被 kill 时,索引增量停留在内存 `_dirty`、分片日志 `_index_log/` 从未落盘,其它进程读面不可见(DSH 在役实测 read null)。server 级同款兜底 2026-09-16 已修(`md_cg/mcp_server.py:3695-3702`,`autoflush=1`),本项补齐**工具面第二落点**。
31
+
32
+ **落点**(全部本会话读码复核在位):
33
+ - `md_cg/review_cli.py:96-106`——`_cg` 返回 `MdCGSecure(..., autoflush=1)`(`autoflush=1` 在 :106),注释写明根因与 mcp_server 对照;
34
+ - `md_cg/evidence.py:509-512`——`_open_cg` 同款补参(`autoflush=1` 在 :512);
35
+ - `scripts/linkref_backfill.py:195-198`——构造补 `autoflush=1` + 注释;
36
+ - `scripts/migrate_restricted.py:41-46`——构造补 `autoflush=1` + 注释;
37
+ - `md_cg/test_review_cli_visibility.py`——新增红守卫(235 行)。
38
+ - `scripts/_mdcg_reindex_code.py:62` 经读码判定**不改**:批式重索引工具(逐文件 add 可达数千条),:128 有显式 `cg.close()` 作为确定性提交边界(flush+compact 落快照),收尾语义与「写完即退的短命工具」不同——per-write `autoflush=1` 只会增加数千次逐条日志 append 的开销而无可见性收益,维持 `autoflush=64`(本会话实测 :62 为 `autoflush=64`、:128 为 `cg.close()`,在位)。
39
+
40
+ **前后对比**:
41
+ - 修复前:`python -X utf8 -m md_cg.test_review_cli_visibility` → PASS=5 FAIL=5。红项:③落账契约「进程 A'(经生产构造 `_cg` 调库裸 add 2 条 → `os._exit(0)` 模拟被杀,close/atexit 均不执行)退出后盘面 `_index_log/` 已含全部写入记录」实测 `log_ids=[]`(autoflush=64 未达阈值,分片日志从未落);④四处构造 autoflush 回显均为 64/缺参。
42
+ - 修复后:同命令 → PASS=10 FAIL=0(③ `log_ids=['vis-node-1','vis-node-2']`;④ review_cli `_cg` 与 evidence `_open_cg` 行为断言 `autoflush==1`,两个 scripts 源级断言命中)。
43
+ - 读面断言①②(进程 A subprocess 跑 review_cli accept/调库落盘 → 进程 B 全新子进程 `_load_index`+read 断言业务节点与审计记录节点可见)修复前后均绿——如实说明:本仓 HEAD 上正常路径已由 09-16 的 review_decide 显式 flush(`md_cg/mdcos.py` 实测三处 `self.flush()` 在 :2258/:2309/:2330)+ review_cli finally `cg.close()`(`md_cg/review_cli.py:204-211`)+ 库层 atexit(`md_cg/mdcg.py:104-118`,`atexit.register` 在 :117,仅覆盖正常退出)覆盖;kill 形态的重开读面已由批次 39(9102df88,2026-09-25)`_load_index` 指纹失配→全扫自愈(`md_cg/mdcg.py:959-970`:指纹不符或旧快照无 `_fingerprint` 键即 `idx=None` 回退 `_scan_nodes` 全扫)兜住,该自愈晚于 09-16 的 autoflush=1 修复(17699ec5)落地——DSH 在役实测的 read null 对应**旧读面**(0.4.x 副本 `_load_index` 盲信既有快照无指纹校验)+ **旧写入面**(无显式 flush/autoflush)的叠加形态,本次补齐的正是写入面兜底在短命工具侧的第二落点(与 server 同款);①②保留为回归钉,防上述两层兜底未来被移除时旧症复发。
44
+
45
+ **语义变化**:`autoflush=1` 仅改变索引增量的落账时机:写入经 `_stage` 后立即 flush() 落分片日志 `_index_log/`(`md_cg/mdcg.py:2079-2087` 阈值判定 `len(self._dirty) >= self.autoflush` 在 :2086-2087,1 条即落),任意退出形态(含被 kill)下写入对其它进程立即可见;flush 幂等(`_dirty` 空即 no-op,`md_cg/mdcg.py:1080-1081`),节点文件/索引条目内容、读面结果、权限闸均零变化。四处均为构造参数增补,无 API/文件格式变更。`_mdcg_reindex_code.py` 维持 autoflush=64 是读码判定后的刻意不动(见落点末段理由),非遗漏。
46
+
47
+ **验证**:
48
+ 1. 守卫红→绿:`python -X utf8 -m md_cg.test_review_cli_visibility`,修复前 PASS=5 FAIL=5(③ `log_ids=[]`、④ autoflush=64×2 + 源级断言×2 未命中),修复后 PASS=10 FAIL=0。**本报告撰写会话重跑:PASS=10 FAIL=0,EXIT=0**(③ `log_ids=['vis-node-1','vis-node-2']`、④ `autoflush==1`×2 + 源级断言×2,实测输出见第三节)。
49
+ 2. 回归(修复轮实跑):`test_review_cli_attribution` 10/0;`test_review_conformance` 38/0;`test_review_onepass` 10/0;`test_p24_evidence` 29 passed(evidence.py 改动的直接回归)。
50
+ 3. `python -X utf8 -m py_compile` 五个改动文件 → COMPILE_OK;`scripts/migrate_restricted.py --root <临时库>` dry-run 冒烟 exit=0、`scripts/linkref_backfill.py --root <临时库>` 扫描冒烟 exit=0(修复轮实跑)。本会话另对 11 个改动面+新守卫+reindex 工具整体 py_compile → **COMPILE_OK**。
51
+ 4. 全量测试由编排会话跑(修复轮未跑,本报告会话亦未跑——见第四节门禁与第六节申报)。
52
+ 5. 实验与测试全程临时目录 + 哑主密钥(`MDCG_MASTER_KEY=ab*32`),实验目录(系统临时目录下 `mdcg_p1b_exp` 及 `clivis_*` 等临时残留)已清理(余量 0)。
53
+ 6. 读码依据(行号为本会话实测):`mdcg.py:922`(autoflush 缺省 64)、`mdcg.py:104-118`(`_atexit_flush_all`,atexit 仅正常退出)、`mdcg.py:2079-2087`(`_stage` 阈值落账)、`mdcg.py:1079-1098`(flush 落分片日志)、`mdcg.py:948-975`(`_load_index`=快照+日志重放,:959-970 指纹失配全扫自愈)、`mdcos.py:2258/2309/2330`(review_decide 显式 flush)、`mcp_server.py:3695-3702`(server 级 autoflush=1 对照)、git 时间线 17699ec5(09-16 autoflush)vs 9102df88(批次 39 指纹自愈,09-25)。未触真实令牌库/真实 serve/在役数据目录。
54
+
55
+ ### 2.2 P1——裁决面身份归因退化:review_cli 随机会话 + accept 落盘 writer 被 designer-cli 覆盖(原始写入者不可追溯)
56
+
57
+ **target**:同一批裁决落盘节点会话 id 各自随机(DSH 实录 5 节点 5 个 `sess_*`),且 accept/edit 落盘节点 `frontmatter.writer` 被裁决者 designer-cli 覆盖,提案原始写入者(如 dsh-memory)不可追溯。
58
+
59
+ **落点**(本会话读码复核在位):
60
+ 1. `md_cg/review_cli.py`——模块 docstring :31-44(`--session` 用法 + 落盘归因回告,含 `_normalize_session` 的 DSH 前置条件注记);:75-80 新增 `_session_of`(`--session` > 环境变量 `MDCG_SESSION` > None);:83-106 `_cg` 改造(None 时 stderr 告警一行后维持随机会话);:175-178 argparse common 新增 `--session`,所有子命令通用(`parents=[common]` 挂全部 8 个子命令)。
61
+ 2. `md_cg/mdcos.py:2240-2249`——review_decide accept/edit 分支:提案记录的原始 actor(propose rec 的 `"actor"`,propose 时库端快照,`md_cg/mdcos.py:1770`)经 `extra.setdefault` 记为落盘节点 `frontmatter.writer`,裁决者 `self.actor` 记入 `frontmatter.reviewer`。
62
+ 3. `scripts/review_cli.py`——孪生件同款同步(`_session_of` :66、`--session` argparse :153、docstring :11/:26);本会话实测两文件同步点在位。
63
+ 4. `md_cg/test_review_cli_attribution.py`——新增红守卫(①~⑥ 共 10 断言,177 行)。
64
+
65
+ 注:git status 中 `md_cg/mdcg.py` 的改动与 `md_cg/test_none_id_write_guard.py` 为并行修复员的 P3(None.md)改动,非本目标所改,未触碰。
66
+
67
+ **前后对比**:
68
+ - 修复前(红守卫实测,`python -m md_cg.test_review_cli_attribution`):PASS=2 FAIL=8——`accept --session` 报 argparse "unrecognized arguments" 退出码 2;提案人以 actor=dsh-memory propose、designer-cli accept 后节点 `frontmatter.writer="designer-cli"`(原始写入者被覆盖,DSH 缺陷直接复现);设 `MDCG_SESSION` 亦被无视(落 `sess_41d73208c113` 随机值);无告警。
69
+ - 修复后:同一守卫 PASS=10 FAIL=0——`accept --session sess_decide_01` → `frontmatter.session=="sess_decide_01"`、`writer=="dsh-memory"`(原始写入者在位)、`reviewer=="designer-cli"`(裁决者换字段保留);同一 `--session` 两次裁决两节点归属一致;仅设 `MDCG_SESSION` 时兜底生效(sess_env_03);两者皆缺省时 stderr 恰一行随机会话告警且退出码 0、仍落 `sess_*` 随机值(现状兼容)、writer 归因同样在位。
70
+ - 孪生件 `scripts/review_cli.py` 端到端(修复轮,临时库+哑密钥):rc=0,`session='sess_twin_01'`、`writer='dsh-memory'`、`reviewer='designer-cli'`;`_session_of`/`_cg` 两文件逐字一致已 diff 验证(修复轮实跑;本会话复核同步点在位,未重跑孪生端到端——见第六节申报)。
71
+
72
+ **语义变化**(向后兼容):
73
+ 1. `frontmatter.writer` 含义变化——accept/edit 落盘节点从「最后落盘者=裁决者(designer-cli)」变为「保留提案原始写入者」(propose 时库端快照的 actor,非裁决期客户端输入,不可伪造面);裁决者身份不丢失,移入 `frontmatter` 新增字段 `reviewer`。该实现落在引擎层 `mdcos.review_decide`,故 MCP 面 op=review 的 accept/edit 走同一代码路径同样受益。兼容性:提案 extra 里已带 writer 的存量提案不覆盖(`setdefault`,保留既有「库层调用方可显式传值覆盖」通道,`_attribution` 语义不变);旧格式提案无 actor 时 writer 仍回落裁决者(现状不变);merge/reject/noop 路径不动。
74
+ 2. review_cli 全部子命令新增 `--session`:缺省取环境变量 `MDCG_SESSION`,仍无则维持旧随机会话行为、仅多一行 stderr 告警(不拒绝、不阻断);现有调用形态(不传 `--session`)全部照旧。
75
+ 3. `frontmatter.session` 语义本身不变(写入时会话归属),变化仅是取值来源受控——DSH 端同一批裁决传同一 `--session` 即得同一落盘归属。
76
+ 4. **DSH 前置条件回告(P1-1,按要求为回告非代码修)**:MCP 写入面对 DSH 形态会话 id(`session-<8>-<4>-<4>-<4>-<12>`)有 `_normalize_session` 防编造校验(`md_cg/mcp_server.py:3381-3405`,目录根可用 `MDCG_DSH_SESSIONS_ROOT` 覆盖、缺省 `~/.dsh/sessions`,:3397)——会话目录须真存在于其下,否则该会话在 MCP 面降级 anonymous;review_cli 直构 Principal 不经该校验。此注记已写入两份 review_cli 模块 docstring(`md_cg/review_cli.py:39-44`),DSH 端环境侧需自行核对目录在位,否则 CLI 与 MCP 两侧归因对不上。
77
+ 5. 未做 git commit(按纪律,编排会话负责)。
78
+
79
+ **验证**(修复轮全部实跑):
80
+ - 修复前红:`python -m md_cg.test_review_cli_attribution` → PASS=2 FAIL=8(关键红:`--session` 未识别退出码 2;writer=designer-cli;`MDCG_SESSION` 被无视落随机值;无告警)。
81
+ - 修复后绿:同命令 → PASS=10 FAIL=0。**本报告撰写会话重跑:PASS=10 FAIL=0,EXIT=0**(session/writer/reviewer 三归因逐项断言 + 稳定性 + `MDCG_SESSION` 兜底 + 告警一行 + 随机兼容,实测输出见第四节抽验)。
82
+ - 孪生件端到端(修复轮,子进程,临时库 + `MDCG_MASTER_KEY=ab*32` 哑密钥):`scripts/review_cli.py accept --session sess_twin_01` → rc=0,frontmatter 三归因在位。
83
+ - 定向回归全绿(修复轮实跑):test_review_conformance 38/0、test_index_durability 16/0、test_identity_attribution 19/0、test_propose_tail_index 8/0、test_review_onepass 10/0、test_merge_upsert 11/0、test_n131_merge_gate 17/0、test_p2_mcp 64/0、test_p21_tokens 38/0、test_p2 37/0、test_action_derive 46/0、test_mr_m4 88/0。
84
+ - 组全量:`python scripts/run_tests.py md_cg --jobs 4` → 159/159 通过、3 跳过(白箱语料依赖,既有跳过)、exit 0,清单含 PASS `md_cg.test_review_cli_attribution`。
85
+ - `python -m md_cg.review_cli accept --help` → `--session` 在列;`python scripts/run_tests.py --list` → 新守卫已入发现面。
86
+
87
+ ### 2.3 P3——knowledge/orphan/None.md 脏节点写入源头(md_cg 写入边界 node_id 污染形态放行)
88
+
89
+ **target**:DSH 在役库出现 `knowledge/orphan/None.md` 并进入检索与 route 候选(route op 即 `cg.search`,`md_cg/mcp_server.py:2117-2119`,本会话实测)。定性:`str(None)`(Python)/`String(null)`(TS)字符串化污染形态在写入边界放行。
90
+
91
+ **落点**(本会话读码复核在位):
92
+ - `md_cg/mdcg.py:909-916`——新增模块级 `_NODE_ID_FORBIDDEN = frozenset({"None", "null"})` 及成因注释,紧邻 `_NODE_ID_RE`(:907);
93
+ - `md_cg/mdcg.py:1316-1321`——add 既有白名单闸(None 本体/空串/`..` 穿越/形状)位置;
94
+ - `md_cg/mdcg.py:1322-1326`——add() 写入边界新增整串精确等值闸:`nid_s in _NODE_ID_FORBIDDEN` → 结构化 ValueError(消息点名 P3 缺陷与改法);
95
+ - `md_cg/test_none_id_write_guard.py:1-165`——新红守卫,套件自动发现。
96
+
97
+ **前后对比**:
98
+ - 修前(修复轮,临时库实弹复现):`MdCGOS.add("None", …)` 返回 `'None'` 并落盘 `knowledge/orphan/None.md`;`add("null")` 同(白名单 `_NODE_ID_RE` 形状合法放行——str(None)/String(null) 字符串化污染形态);该文件经 `_scan_nodes` 收录为 id="None",search_rrf 实测命中 `('None', 0.016)`,与 DSH 在役『None.md 出现在检索与 route 候选』病理吻合。
99
+ - 修后:add 在唯一写入边界拒 `"None"`/`"null"`(ValueError),盘面无 None.md、索引无该条目;防误杀与既有语义不回退(`'NoneBot_1'`/`'nullify_test'` 子串 id 正常写入;`add(None)`/`''`/`0` 仍 P0-1 ValueError)。
100
+ - 红→绿:守卫修前 9 通过/7 失败,修后 17 通过/0 失败。**本报告撰写会话重跑:17 通过/0 失败,EXIT=0**([1] 字符串 "None" 拒写 4 断言、[2] "null" 拒写、[3] 防误杀、[4] 既有语义不回退、[5] writepipe 链不落盘、[6] 存量脏数据收录取证与清理路径实证,实测输出见第四节抽验)。
101
+
102
+ **语义变化**:
103
+ 1. 行为变化仅一处:node_id 与 `"None"`/`"null"` **整串精确等值**(大小写敏感、不扩子串)的写入由『成功落盘』变『ValueError 拒绝』。全部写入链(writepipe 执行器、review accept、identity、consolidate、branches)最终经 add 单点落盘,行为同步收敛;已持有存量 id="None" 节点的库再覆写该 id 将被拒——预期 fail-closed。
104
+ 2. 定性(取证结论):None.md 出自两段叠加——①批次 24(2a57c2a2,2026-09-24)之前 add 无任何校验、`f"{node_id}.md"` 直拼,`add(None)` 直落 None.md(修复轮 `git show 2a57c2a2^:md_cg/mdcg.py` 实证:旧 add 无校验、path 直拼,DSH 在役库的存量 None.md 属该历史脏数据);②现行代码 `add(None)` 本体已拒,但字符串形态 `add("None")` 仍可造出 None.md——这是现行残留洞而非纯历史问题,故本次修复成立,非『修不存在的缺陷』。
105
+ 3. 存量清理建议(未代执,不触真实库):删除 `<root>/knowledge/orphan/None.md` 后 `rebuild_index()` 即从索引与检索/route 候选消失(守卫 [6] 三断言实证该路径有效);勿用 `add("None")` 覆写清理(修后被拒)。
106
+ 4. 相邻发现(如实报告,未修,超本目标):①`add(123)` 等非字符串真值 id 以原值入索引键,flush 落快照后重开 `_load_index` 的 `sorted(nodes)` 混型键 TypeError 整库打不开(修复轮探针实测);②`propose(None)` 抛裸 TypeError 非 ValueError(`md_cg/mdcos.py:1770` 附近,不产生 None.md,未动)。建议入池,见第六节。
107
+ 5. 工作区内 mdcos.py/review_cli.py 等另有并行改动(P1/P1b 修复员所为),未触碰;未 git commit(编排会话负责)。
108
+
109
+ **验证**(修复轮实跑):
110
+ 1. 红态:`python -X utf8 -m md_cg.test_none_id_write_guard` → 9 通过/7 失败 exit 1([1][2][5] 污染形态红,[3][4][6] 防误杀/既有语义/取证面绿)。
111
+ 2. 绿态:同命令 → 17 通过/0 失败 exit 0。本会话重跑一致(EXIT=0)。
112
+ 3. 回归:`test_security_audit` 13/0;`test_security_audit_v21` 49/0;`test_session_isolation` 19/0。
113
+ 4. 全量:`python scripts/run_tests.py --jobs 4` → 「SUMMARY 213/213 通过,5 跳过(依赖缺失/平台不符)」exit 0,且 `_discover()` 列表(218 件)含 `md_cg.test_none_id_write_guard`。
114
+ 5. 取证:grep 写入路径构造点(`_node_disk_path`、add path 派生、`_scan_nodes`、writepipe execute/executor)+ `git show 2a57c2a2^:md_cg/mdcg.py` + 临时库探针(add 13 种 None-ish 调用形态枚举,仅 `add("None")` 复现 None.md);探针与守卫临时目录均已删除,未触真实令牌库/真实在役数据。
115
+
116
+ ---
117
+
118
+ ## 三、跨进程可见性红转绿证据(P1b)
119
+
120
+ **红态**(修复前,`python -X utf8 -m md_cg.test_review_cli_visibility`):PASS=5 FAIL=5。
121
+
122
+ 关键红项③的契约:进程 A' 经生产构造 `_cg` 调库裸 add 2 条后 `os._exit(0)`(模拟被杀,close/atexit 均不执行),退出后盘面 `_index_log/` 必须已含全部写入记录。修复前 `log_ids=[]`——缺省 `autoflush=64`(`md_cg/mdcg.py:922`)未达阈值,分片日志从未落;此时另一进程 B 重开读面(`_load_index`=快照+日志重放,`md_cg/mdcg.py:948-975`)自然读不到这两条,即 DSH 在役 read null 的机理。
123
+
124
+ **绿态**(修复后):PASS=10 FAIL=0。本报告撰写会话重跑实测输出(节选):
125
+
126
+ ```
127
+ 【①③】… 进程 B 读回业务节点 vis-acc-node 可见 · READ 1
128
+ 进程 B 侧审计记录节点可见(review_records 命中 1 条)
129
+ 【②③】进程 A' 调库落 2 条即 os._exit(模拟被杀)→ 落账契约 + 进程 B 读
130
+ [PASS] 进程 A' 经生产构造 _cg(autoflush=1 回显) · staged=0 autoflush=1
131
+ [PASS] ③ 落账契约:A' 被杀退出后 _index_log 已含全部 2 条写入记录
132
+ · log_ids=['vis-node-1', 'vis-node-2']
133
+ [PASS] ② 进程 B 读回 kill 形态的两条节点均可见 · READ 1 1
134
+ 【④】同病工具面 autoflush=1
135
+ [PASS] review_cli._cg 构造 autoflush==1 · 1
136
+ [PASS] evidence._open_cg 构造 autoflush==1 · 1
137
+ [PASS] scripts/linkref_backfill.py 构造语句带 autoflush=1(源级断言)
138
+ [PASS] scripts/migrate_restricted.py 构造语句带 autoflush=1(源级断言)
139
+ ================================================================
140
+ PASS=10 FAIL=0 EXIT=0
141
+ ```
142
+
143
+ **证据链要点**:
144
+ - 红转绿的唯一变量是四处构造的 `autoflush=1`(写入侧落账时机),读面 `_load_index` 重放逻辑一行未改——同一读面在红态读不到、绿态读到,证明缺陷在写入面,与定性一致。
145
+ - ①②读面断言修复前后均绿:正常退出路径在本仓 HEAD 已有三层既有兜底(mdcos review_decide 显式 flush :2258/:2309/:2330;review_cli finally `cg.close()` :204-211;库层 atexit `mdcg.py:104-118`);kill 形态重开读面另有批次 39 指纹失配→全扫自愈(`mdcg.py:959-970`)。DSH 在役实测命中的是**旧读面(0.4.x 无指纹校验)×旧写入面(无 autoflush)**叠加,两层兜底均晚于其在役版本。①②保留为回归钉。
146
+ - 时间线佐证:17699ec5(2026-09-16,server 级 autoflush=1)早于 9102df88(批次 39,2026-09-25,指纹自愈),故在役 0.4.x 两侧皆旧。
147
+
148
+ ---
149
+
150
+ ## 四、门禁
151
+
152
+ 编排会话门禁执行记录(本报告撰写会话**未重跑门禁全套**,如实注明):
153
+
154
+ | 门禁项 | 结果 |
155
+ |---|---|
156
+ | python 全量测试 | 通过(退出码 0) |
157
+ | 注入套件 | 18/18,与登记一致(EXIT=0) |
158
+ | gate | 1 |
159
+
160
+ **本报告撰写会话抽验(本会话实跑,均 EXIT=0)**:
161
+
162
+ | 命令 | 结果 |
163
+ |---|---|
164
+ | `python -X utf8 -m md_cg.test_review_cli_visibility` | PASS=10 FAIL=0 |
165
+ | `python -X utf8 -m md_cg.test_review_cli_attribution` | PASS=10 FAIL=0 |
166
+ | `python -X utf8 -m md_cg.test_none_id_write_guard` | 17 通过 / 0 失败 |
167
+ | `python -X utf8 -m py_compile`(11 件:7 改动面 + 3 新守卫 + `scripts/_mdcg_reindex_code.py`) | COMPILE_OK |
168
+
169
+ ---
170
+
171
+ ## 五、回告 DSH 端复验清单(复现步骤+预期)
172
+
173
+ **通用前置**:拉取含本轮修复的 md_cg 构建(三项修复均在本仓未提交工作区,随编排会话提交/发布后生效;在役 0.4.x 副本不含 09-16 autoflush 与批次 39 指纹自愈,须升级方可复验);复验一律临时库 + 哑密钥,勿触在役数据。
174
+
175
+ **P1b(跨进程可见性)**
176
+ - 步骤 A(守卫):`python -X utf8 -m md_cg.test_review_cli_visibility`。
177
+ 预期:PASS=10 FAIL=0,退出码 0;③项 `log_ids=['vis-node-1','vis-node-2']`。
178
+ - 步骤 B(手工复现):进程 A 以生产构造(review_cli accept 或 `_cg` 裸 add)写入 2 条后立即 `os._exit(0)` 模拟被杀;随后检查 `<root>/_index_log/`。
179
+ 预期:A' 退出后分片日志立即含全部 2 条写入记录;进程 B 全新进程 `_load_index`+read 可见业务节点与审计记录节点。
180
+
181
+ **P1(裁决归因)**
182
+ - 步骤 A(守卫):`python -X utf8 -m md_cg.test_review_cli_attribution`。
183
+ 预期:PASS=10 FAIL=0,退出码 0。
184
+ - 步骤 B(端到端):以身份 X(如 dsh-memory)propose 一条 → `python -m md_cg.review_cli accept <pid> --session <同一会话id> --reason "…"`(裁决者 designer-cli)。
185
+ 预期:退出码 0;落盘节点 `frontmatter.session==<传入值>`、`writer==X`(原始写入者在位)、`reviewer=="designer-cli"`;同一 `--session` 再裁一条,两节点 session 一致。
186
+ - 步骤 C(兼容性):不传 `--session` 亦不设 `MDCG_SESSION` 裁决一条。
187
+ 预期:stderr 恰一行随机会话告警、退出码 0、落 `sess_*` 随机值、writer 归因同样在位(不阻断)。
188
+ - **P1-1 环境侧核对(回告项)**:核对 DSH 会话目录真实存在于 `MDCG_DSH_SESSIONS_ROOT` 或 `~/.dsh/sessions` 之下。预期:目录在位后,MCP 写入面 `_normalize_session`(`md_cg/mcp_server.py:3381-3405`)不再将该会话降级 anonymous,MCP 面与 CLI 面归因一致;目录不在位时 MCP 面降级 anonymous 属既有防编造设计,CLI 侧(直构 Principal 不经该校验)不受影响,但两侧归因会对不上——需环境侧保证目录在位。
189
+
190
+ **P3(None.md 脏节点)**
191
+ - 步骤 A(守卫):`python -X utf8 -m md_cg.test_none_id_write_guard`。
192
+ 预期:17 通过 / 0 失败,退出码 0。
193
+ - 步骤 B(写入拒绝):修复版库 `add("None", …)` / `add("null", …)`。
194
+ 预期:ValueError(消息点名字符串化污染形态与 P3),盘面无 None.md/null.md,索引无该条目;`add("NoneBot_1")`/`add("nullify_test")` 等子串 id 不受影响。
195
+ - 步骤 C(存量清理,DSH 端自执,本轮未代执):核对 `<root>/knowledge/orphan/None.md` 是否存在;存在则删除该文件后 `rebuild_index()`。
196
+ 预期:id="None" 从索引、检索结果与 route 候选消失(守卫 [6] 实证该路径)。**勿用 `add("None")` 覆写清理(修后被拒)。**
197
+
198
+ ---
199
+
200
+ ## 六、遗留
201
+
202
+ 1. **读路径自愈长效兜底与升级要求**:批次 39(9102df88,2026-09-25)`_load_index` 指纹失配→全扫自愈(`md_cg/mdcg.py:959-970`)已在库层兜住 kill 形态重开读面;但 0.4.x 旧副本读面盲信快照无指纹校验——DSH 侧**必须升级构建**才能同时获得旧读面自愈与本轮写入面兜底,升级列为第五节复验前置。
203
+ 2. **P1b 读面断言①②为回归钉**:正常路径与 kill 重开路径的既有兜底(显式 flush / close / atexit / 指纹自愈)若未来被移除,守卫即红。
204
+ 3. **P3 相邻发现未修**(如实,建议入池):`add(123)` 等非字符串真值 id 混型索引键可致重开 `_load_index` 的 `sorted(nodes)` TypeError 整库打不开(修复轮探针实测);`propose(None)` 抛裸 TypeError 非 ValueError(`md_cg/mdcos.py:1770` 附近,无脏文件产生)。
205
+ 4. **P4/P5 入池**:编排决策不入本轮;定性细节本轮材料未含,本报告不作描述(不虚构)。
206
+ 5. **存量 None.md 清理在 DSH 真实库的执行**由 DSH 端自执(本轮未代执、未触真实库),路径见第五节 P3 步骤 C。
207
+ 6. **批式工具 autoflush 取舍**:`scripts/_mdcg_reindex_code.py` 维持 `autoflush=64`(:62)+ 显式 `cg.close()`(:128)——读码判定后的刻意不动(批式数千条逐条落日志无收益,:128 close 即确定性提交边界),非遗漏。
208
+ 7. **本报告会话未重跑项**:门禁全套(python 全量/注入套件/gate,编排会话执行记录见第四节)、组全量与定向回归套件(修复轮实跑记录见第二节各验证栏)、孪生件端到端(修复轮实跑,本会话仅复核同步点源码在位)。以上均为如实申报,未以本会话名义重报为已跑。
209
+
210
+ ---
211
+
212
+ ## 七、纪律合规声明
213
+
214
+ 1. **实验环境**:全程系统临时目录 + 哑主密钥(`MDCG_MASTER_KEY=ab*32`);未触真实令牌库、真实 serve、真实在役数据目录。
215
+ 2. **清理**:修复轮实验残留(`mdcg_p1b_exp`、`clivis_*`、`cliattrib_*`、`twin_attr_*`、`mdcg_conf_*` 及 P3 探针/守卫临时目录)均已清理,复查余量 0。
216
+ 3. **提交纪律**:未 git commit(编排会话负责);工作区未提交改动即本轮修复落点(7 修改 + 3 新守卫,见前言基线)。
217
+ 4. **引证纪律**:结论均带 `path:line`;验证结果区分「修复轮实跑(材料记录)」与「本报告会话实跑(第四节抽验)」;未跑项如实标注(第六节第 7 条),无以未跑充已跑之处。
218
+ 5. **路径表述**:本报告不写本机绝对路径,实验目录一律以「系统临时目录下 …」表述。
219
+ 6. **无法满足项如实列出**:P4/P5 定性细节本轮材料未提供,总览矩阵与遗留仅记「入池」,不作内容描述;材料个别行号与当前工作区实测有漂移(如 review_decide 显式 flush 实测在 `mdcos.py:2258/2309/2330` 而非材料所记 2248/2299/2320),报告已全部按本会话实测修正,未沿用漂移值。
220
+
221
+ ---
222
+
223
+ ### 附:自查双清单
224
+
225
+ **清单一:结论引证自查(关键结论 → 引证 → 验证方式)**
226
+
227
+ | 结论 | 引证 | 验证方式 |
228
+ |---|---|---|
229
+ | P1b 四处落点 `autoflush=1` | `md_cg/review_cli.py:106`、`md_cg/evidence.py:512`、`scripts/linkref_backfill.py:198`、`scripts/migrate_restricted.py:46` | 本会话逐处读码在位 |
230
+ | 缺省 autoflush=64、atexit 仅正常退出 | `md_cg/mdcg.py:922`、`mdcg.py:104-118` | 本会话读码 |
231
+ | `_stage` 阈值落账 / flush 幂等落分片日志 | `md_cg/mdcg.py:2079-2087`、`mdcg.py:1079-1098` | 本会话读码 |
232
+ | `_load_index` 快照+重放、指纹失配全扫自愈 | `md_cg/mdcg.py:948-975`(:959-970) | 本会话读码 |
233
+ | P1 三归因改造点 | `md_cg/review_cli.py:31-44/75-80/83-106/175-178`、`md_cg/mdcos.py:2240-2249`、propose actor 快照 `md_cg/mdcos.py:1770` | 本会话读码 |
234
+ | P1-1 校验面 | `md_cg/mcp_server.py:3381-3405`(:3397 目录根) | 本会话读码 |
235
+ | P3 写入边界闸 | `md_cg/mdcg.py:909-916`、`mdcg.py:1322-1326` | 本会话读码 |
236
+ | route op 即 cg.search | `md_cg/mcp_server.py:2117-2119` | 本会话读码 |
237
+ | reindex 工具刻意不动 | `scripts/_mdcg_reindex_code.py:62/:128` | 本会话读码 |
238
+ | 孪生件同步 | `scripts/review_cli.py:66/:153` 等 | 本会话读码 |
239
+ | 三守卫全绿 | 第四节抽验表 | 本会话实跑(EXIT=0) |
240
+ | 11 件 py_compile | 第四节抽验表 | 本会话实跑(COMPILE_OK) |
241
+ | 门禁三项、组全量、定向回归、孪生端到端、红态 5/5 与 9/7 | 第二节各「验证」栏、第四节门禁表 | 修复轮/编排实跑记录(材料),本会话未重跑 |
242
+
243
+ **清单二:未实跑/未尽事项申报**
244
+
245
+ - 门禁全套(python 全量、注入套件 18/18、gate=1):编排会话执行,本会话未重跑——按记录转述,未冒充本会话结果。
246
+ - 全量 213/213、组全量 159/159、定向回归 12 套、孪生件端到端、红态(PASS=5 FAIL=5 / PASS=2 FAIL=8 / 9 通过 7 失败):修复轮实跑(材料记录),本会话未重跑红态(绿态三守卫已重跑)。
247
+ - 存量 None.md 真实库清理:未代执(DSH 端自执)。
248
+ - P4/P5:无定性材料,未描述。
249
+ - P3 相邻两项(混型索引键 TypeError、propose(None) 裸 TypeError):未修,已申报入池建议。
250
+ - 材料行号校勘:`_stage` 2066-2073→实测 2079-2087;flush 1070-1089→实测 1079-1098;`_load_index`/指纹自愈 939-973/958-961→实测 948-975/959-970;autoflush 缺省 913→实测 922;atexit 104-119→实测 104-118;review_decide 显式 flush 2248/2299/2320→实测 2258/2309/2330;review_cli finally close「196 区」→实测 204-211;argparse --session 165-168→实测 175-178。其余引证与实测一致。
251
+
252
+ ---
253
+
254
+ *报告撰写会话(报告员)2026-09-26 · 全部抽验命令与输出见第四节;材料与实跑来源已在正文逐处标注。*