@furongjun1999/dsh-memory 0.6.0 → 0.7.0

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 (202) hide show
  1. package/README.md +618 -572
  2. package/codebuddy/CODEBUDDY.md +10 -10
  3. package/data/policy.json +27 -0
  4. package/docs/README.md +1 -0
  5. package/docs/discipline/harnesses.yaml +31 -0
  6. package/docs/discipline/templates/full.md.tmpl +1 -1
  7. package/docs/discipline/templates/rules.mdc.tmpl +1 -1
  8. 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
  9. 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
  10. 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
  11. 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
  12. 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
  13. 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
  14. package/docs/eval//345/207/272/350/264/247/351/235/242/345/206/222/347/203/237_/350/277/233/350/264/247/351/227/250/347/246/201_v1.0.md +460 -0
  15. 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
  16. package/docs/eval//345/217/221/345/270/20308_/350/207/252/350/277/255/344/273/243/344/270/216/347/235/241/347/234/240_/345/233/276/346/243/200/347/264/242/350/267/257/344/270/216/346/235/203/351/207/215_v1.0.md +97 -0
  17. package/docs/eval//345/275/222/344/270/200/345/261/202/347/274/272/347/234/201/347/277/273/345/205/263_/344/277/256/345/244/215/350/256/260/345/275/225_v1.0.md +458 -0
  18. 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
  19. 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
  20. 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
  21. 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
  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_v21.md +224 -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_v22.md +223 -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_v23.md +293 -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_v24.md +303 -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_v25.md +230 -0
  27. package/docs/hive//346/243/200/347/264/242/347/256/227/346/263/225/345/217/243/345/276/204/345/257/271/347/205/247_v0.1.md +136 -11
  28. 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 +52 -2
  29. 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
  30. package/docs/mdcg/README/350/257/246/347/273/206/347/211/210_v0.4.10.md +100 -0
  31. 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
  32. package/docs/mdcg//345/217/221/345/270/203/351/227/250/347/246/201/351/223/276_v0.1.md +57 -9
  33. 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
  34. package/docs/mdcg//347/235/241/347/234/240/345/221/250/346/234/237_/350/277/220/347/273/264/345/211/215/346/217/220/344/270/216/347/273/264/346/212/244/346/214/207/345/215/227_v1.0.md +183 -0
  35. 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
  36. 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
  37. 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
  38. package/docs/plans//347/235/241/347/234/240/344/270/216/350/207/252/350/277/255/344/273/243_/345/212/237/350/203/275/344/274/230/345/214/226/350/256/276/350/256/241_v0.4.md +547 -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/lib/bridge.js +24 -2
  42. package/lib/hooks.d.ts +31 -2
  43. package/lib/hooks.js +219 -16
  44. package/lib/init.js +16 -1
  45. package/lib/lib/prompt_safety.d.ts +52 -1
  46. package/lib/lib/prompt_safety.js +76 -1
  47. package/md_cg/audit.py +652 -379
  48. package/md_cg/bench6_arms.py +1 -1
  49. package/md_cg/bench_e2e_locomo_qa.py +11 -4
  50. package/md_cg/bench_p0.py +1 -1
  51. package/md_cg/branches.py +2 -2
  52. package/md_cg/ccgc.py +1071 -1006
  53. package/md_cg/chain.py +48 -1
  54. package/md_cg/consistency.py +97 -9
  55. package/md_cg/consolidate.py +34 -9
  56. package/md_cg/crypto.py +59 -26
  57. package/md_cg/docindex.py +16 -1
  58. package/md_cg/evolution.py +17 -1
  59. package/md_cg/export.py +1 -1
  60. package/md_cg/forgetting.py +309 -13
  61. package/md_cg/freshness.py +511 -0
  62. package/md_cg/fsutil.py +454 -8
  63. package/md_cg/generation.py +409 -0
  64. package/md_cg/hotcache.py +4 -1
  65. package/md_cg/identity.py +3 -3
  66. package/md_cg/insight.py +24 -3
  67. package/md_cg/linkref.py +1 -1
  68. package/md_cg/logref.py +327 -0
  69. package/md_cg/mcp_server.py +4261 -3818
  70. package/md_cg/mdcg.py +4695 -3547
  71. package/md_cg/mdcos.py +4672 -4159
  72. package/md_cg/mreview/pipeline.py +15 -1
  73. package/md_cg/nodefile.py +713 -576
  74. package/md_cg/protect.py +158 -11
  75. package/md_cg/protocol.py +41 -2
  76. package/md_cg/provenance.py +22 -4
  77. package/md_cg/reach.py +4 -4
  78. package/md_cg/readcache.py +76 -15
  79. package/md_cg/reconcile.py +1 -1
  80. package/md_cg/refindex.py +246 -37
  81. package/md_cg/refine.py +1 -1
  82. package/md_cg/routing.py +32 -5
  83. package/md_cg/run_tests.py +17 -0
  84. package/md_cg/scrub.py +30 -3
  85. package/md_cg/security.py +47 -1
  86. package/md_cg/self_state.py +5 -5
  87. package/md_cg/semantic/canonical.py +22 -0
  88. package/md_cg/semantic/unify.py +73 -22
  89. package/md_cg/semantic/unify_fixture.json +25 -0
  90. package/md_cg/sleep.py +1297 -0
  91. package/md_cg/sources.py +23 -6
  92. package/md_cg/srcindex.py +352 -0
  93. package/md_cg/stg.py +47 -3
  94. package/md_cg/subgraph.py +2 -2
  95. package/md_cg/sustain.py +1436 -1168
  96. package/md_cg/tasks.py +469 -470
  97. package/md_cg/test_auto_defaults.py +424 -0
  98. package/md_cg/test_b1_auto_id_multiproc.py +277 -0
  99. package/md_cg/test_b1b2_write_face.py +417 -0
  100. package/md_cg/test_b2_sensitivity_landing.py +223 -0
  101. package/md_cg/test_b3_merge_keeps_content.py +576 -0
  102. package/md_cg/test_b4_shard_dir_selfheal.py +843 -0
  103. package/md_cg/test_b4_shard_dir_selfheal_guard.py +238 -0
  104. package/md_cg/test_boundary_hit.py +410 -0
  105. package/md_cg/test_c3_transient_read_negative.py +793 -0
  106. package/md_cg/test_c8_search_rrf_gates.py +502 -0
  107. package/md_cg/test_ccg_form_parity.py +188 -0
  108. package/md_cg/test_ccgc.py +28 -3
  109. package/md_cg/test_en_pipeline.py +22 -13
  110. package/md_cg/test_generation_guard.py +352 -0
  111. package/md_cg/test_govern_directread.py +17 -4
  112. package/md_cg/test_h2_session_view_norm.py +233 -0
  113. package/md_cg/test_h4_sustain_snapshot.py +1387 -0
  114. package/md_cg/test_hive_ingest.py +285 -285
  115. package/md_cg/test_issue39_utf8_stdio.py +307 -16
  116. package/md_cg/test_issue43_default_policy.py +865 -0
  117. package/md_cg/test_legacy_p3_node_id_type.py +375 -0
  118. package/md_cg/test_linkref.py +10 -3
  119. package/md_cg/test_lock.py +2 -2
  120. package/md_cg/test_logref.py +1109 -0
  121. package/md_cg/test_m3_h9_bucket_health_protect_mark.py +301 -0
  122. package/md_cg/test_m3_h9_semantic_guard.py +525 -0
  123. package/md_cg/test_mr_m2.py +15 -3
  124. package/md_cg/test_n130_verify_falsified_protect.py +1 -1
  125. package/md_cg/test_n139_dek_provision_failclosed.py +185 -0
  126. package/md_cg/test_n176_link_trust.py +221 -0
  127. package/md_cg/test_n178_units_jobid_gate.py +212 -0
  128. package/md_cg/test_n184_keys_concurrent_provision.py +307 -0
  129. package/md_cg/test_n195_writepath_reload.py +283 -0
  130. package/md_cg/test_n196_stale_gate_skip.py +169 -0
  131. package/md_cg/test_n197_n208_write_face_gates.py +471 -0
  132. package/md_cg/test_n198_tokens_corrupt_failclosed.py +225 -0
  133. package/md_cg/test_n199_tokens_concurrent_write.py +378 -0
  134. package/md_cg/test_n201_proposal_visibility.py +382 -0
  135. package/md_cg/test_n202_session_notes_visibility.py +461 -0
  136. package/md_cg/test_n204_n205_n226_n227_n228_n229_exit_gates.py +542 -0
  137. package/md_cg/test_n206_stdio_jsonrpc_type.py +403 -0
  138. package/md_cg/test_n209_verify_write_face_gates.py +461 -0
  139. package/md_cg/test_n212_n213_n224_generation_gates.py +519 -0
  140. package/md_cg/test_n214_n215_n221_n222_write_face_gates.py +563 -0
  141. package/md_cg/test_n225_nonobject_load.py +1110 -0
  142. package/md_cg/test_n230_dirty_replay.py +375 -0
  143. package/md_cg/test_n62_tenant_bind_failclosed.py +200 -0
  144. package/md_cg/test_neg_condition_hits.py +333 -0
  145. package/md_cg/test_neg_tail_honesty.py +663 -0
  146. package/md_cg/test_none_id_write_guard.py +4 -3
  147. package/md_cg/test_opt_batch1_md_cg.py +451 -0
  148. package/md_cg/test_p1.py +5 -5
  149. package/md_cg/test_p11_consistency.py +161 -12
  150. package/md_cg/test_p26_refindex.py +2 -2
  151. package/md_cg/test_p27_docindex.py +777 -774
  152. package/md_cg/test_p28_refcheck.py +740 -13
  153. package/md_cg/test_p29_session_ingest_export.py +2 -2
  154. package/md_cg/test_p2_mcp.py +12 -1
  155. package/md_cg/test_p2_six_elements.py +463 -0
  156. package/md_cg/test_p30_maintain.py +33 -2
  157. package/md_cg/test_p31_insight.py +1 -0
  158. package/md_cg/test_p3_legacy_closure.py +433 -0
  159. package/md_cg/test_p4_freshness.py +680 -0
  160. package/md_cg/test_p8_subgraph_chain.py +14 -1
  161. package/md_cg/test_p9c_dedup_hints.py +276 -0
  162. package/md_cg/test_policy_required_ccg.py +426 -0
  163. package/md_cg/test_protocol.py +22 -0
  164. package/md_cg/test_rank_parity_score_mode.py +522 -0
  165. package/md_cg/test_read_face_input_gates.py +363 -0
  166. package/md_cg/test_read_face_semantics.py +489 -0
  167. package/md_cg/test_recall_face_guards.py +812 -0
  168. package/md_cg/test_rejected_credential_forms.py +188 -0
  169. package/md_cg/test_rejected_redact.py +146 -0
  170. package/md_cg/test_retr_s1b.py +2 -2
  171. package/md_cg/test_retr_s5.py +20 -7
  172. package/md_cg/test_review_conformance.py +21 -3
  173. package/md_cg/test_security_audit_v21.py +2 -2
  174. package/md_cg/test_semantic_canonical.py +5 -3
  175. package/md_cg/test_server_version.py +67 -0
  176. package/md_cg/test_sleep.py +611 -0
  177. package/md_cg/test_sleep_p1.py +784 -0
  178. package/md_cg/test_srcindex.py +171 -0
  179. package/md_cg/test_tenant_env_override_warn.py +63 -50
  180. package/md_cg/test_time_core_lint.py +968 -0
  181. package/md_cg/test_token_lowercase_form.py +315 -0
  182. package/md_cg/test_unify_default_off.py +701 -0
  183. package/md_cg/test_unify_scope.py +182 -0
  184. package/md_cg/test_v21r1_package_version.py +310 -0
  185. package/md_cg/test_writepipe.py +10 -4
  186. package/md_cg/tokens.py +225 -95
  187. package/md_cg/tool_face.py +4 -4
  188. package/md_cg/trust.py +49 -5
  189. package/md_cg/units.py +204 -6
  190. package/md_cg/weights.py +4 -4
  191. package/md_cg/whitebox_kb/aeis_core/time_core.py +8 -0
  192. package/md_cg/whitebox_kb/wisdom/knowledge_points.py +1 -1
  193. package/md_cg/writelimit.py +42 -8
  194. package/md_cg/writepipe.py +651 -554
  195. package/package.json +4 -2
  196. package/skills/plugin.json +1 -1
  197. package/src/bridge.ts +25 -2
  198. package/src/hooks.ts +229 -16
  199. package/src/init.ts +15 -1
  200. package/src/lib/prompt_safety.ts +88 -1
  201. package/utf8_boot.py +237 -0
  202. package/zcode/AGENTS.md +10 -10
@@ -0,0 +1,498 @@
1
+ # 优化第一批(接线与等价变换)—— 修复工程报告 v1.0
2
+
3
+ - 日期:2026-09-29
4
+ - **修订:v1.0-r1**(按读者反馈逐条处置:符号图例与计数口径新增于 §0.1;`_dirty` 机制改写于 §3.1;R-2 数字口径与第一手复测新增于 §4.1、§6.3;`git diff --numstat` 与「零写入」措辞更正在 §6.4、§7;读者 21 条问题的逐条处置见 §8)
5
+ - 仓库:`D:/program/dsh-memory-main`(下称 `<repo>`)
6
+ - 批次标识:opt-batch1(外部双路调研确认的改进批次)。**计数口径**:**6 项缺陷**(C-1 一项含 3 处写点、C-7、R-1、R-2、R-3、R-6)/**8 条缺陷取证腿**(§2 的 C-1a/b/c、C-7、R-1a、R-2、R-3、R-6)/**10 条复现记录**(上列 8 条 + 登记态复测腿 C-1d + **非缺陷**基线腿 R-1b,见 §2 的计数表)
7
+ - 变更面(本报告实跑 `git status --porcelain` 所见):
8
+ - Python:`M md_cg/forgetting.py`、`M md_cg/insight.py`、`M md_cg/scrub.py`、`M md_cg/consolidate.py`、`M md_cg/test_p30_maintain.py`、`M md_cg/test_p31_insight.py`、`M md_cg/test_govern_directread.py`、`?? md_cg/test_opt_batch1_md_cg.py`(新增守卫)
9
+ - Rust:`M rust/Cargo.toml`、`M rust/src/atoms.rs`、`M rust/src/engine.rs`、`M rust/src/main.rs`、`M rust/src/retrieval.rs`、`M rust/src/store.rs`、`M rust/tests/i29_probe.rs`
10
+ - 用例登记:`M test/chaos_injection/registry.py`、`M test/chaos_injection/test_fi_m03_reinforce_stale_read.py`
11
+ - 另有 `M package-lock.json`(与本次修复无因果关系,本报告不主张其归属,仅记录现场)、`?? .zcode/`(宿主工作区件,非本批产物;**未被 `.gitignore` 忽略**——本报告实跑 `git check-ignore -v .zcode` → 无输出、rc=1)
12
+ - 未 `git add` / 未 `commit` / 未 `push`
13
+ - 本报告只落盘一行产物(本文件);未改任何源码或其它文件
14
+
15
+ ## 行号口径声明
16
+
17
+ 本文行号分两套,逐处标注:
18
+
19
+ - **HEAD 口径**=`git show HEAD:<path>`(HEAD = `f75a343e`)的**修前**文本。本文全部「缺陷站点」用此口径。
20
+ - **工作区口径**=本报告读码当时的磁盘文本,即**修后**文本。本文全部「落点」用此口径。
21
+
22
+ 两者不一致处(因修复插入注释/docstring 造成位移)在 §1 表中并列给出,位移量逐处可核。
23
+
24
+ ---
25
+
26
+ ## 0. 结论速览
27
+
28
+ | 项 | 结论 | 证据 |
29
+ |---|---|---|
30
+ | D1–D3 · C-1(三处同族写点) | `forgetting.reinforce` / `insight.verify` / `scrub._apply_offset` 三处 `cg._write_node` 写盘后**不标 `_dirty`**(scrub 连内存条目都不改;HEAD 口径下三个文件 `_dirty` 出现次数均为 **0**)⇒ 读缓存默认开时同进程「写后读」永久拿到旧 frontmatter,**零异常零告警**(静默陈旧读) | §1 D1–D3、§2 L-a/L-b/L-c |
31
+ | D4 · C-7(升格门槛) | `consolidate.py` 自带**第二份**要素常量(4 元素),与真源 `nodefile.CCG_REQUIRED`(6 元素)不一致 ⇒ 缺「验证方式」的弱证据节点可被 `promote_memories` 升格进 knowledge 层;`predict._is_settled` 转发同一常量判终点,缺口在两个消费面同时放大 | §1 D4、§2 L-e |
32
+ | D5 · R-1(评测 CLI 漏接归一层 + 双实现) | 评测 CLI 的 `main.rs::search`(HEAD 口径 `:271-321`)是**编排的第二份实现**且不做 `atoms.unify(query)` ⇒ 同 query 同语料与库/serve 路 top-1 不同(10 条 query 中 3 条劈叉),违反 `engine.rs` 自书的「与评测 CLI 一致」 | §1 D5、§2 L-f |
33
+ | D6 · R-2(热路径重复小写化) | `retrieval::like` 每查询每文档两次整串 `to_lowercase()`,是 `lexical` 热路径的主导项 | §1 D6、§2 L-h、**§4.1 第 9 行(本报告第一手复测)** |
34
+ | D7 · R-3(graph 种子口径) | 种子取「候选枚举序前 5」而非相关度前 5 ⇒ 唯一满分节点被漏掉,graph 路整条为空 | §1 D7、§2 L-i |
35
+ | D8 · R-6(未声明 feature) | `src/atoms.rs` 引用 `no-probe` 而 `Cargo.toml` 无 `[features]` ⇒ 每次构建 2 条 `unexpected_cfgs` 告警,且该 cfg 分支恒为死代码 | §1 D8、§2 L-j(本报告已独立复现修前告警) |
36
+ | 修法性质 | **接线**(C-1 三处补标脏、C-7 改转发真源、R-1 收成单编排点、R-3 换 `sort_path` 三键)+**等价变换**(R-2 把求值时机从每查询前移到建库)+**声明**(R-6 注册 cfg 名,不删分支) | §3 |
37
+ | 本报告实跑验证 | 守卫 `22 通过 / 0 失败` rc=0;变异自证红项 `2/2/2/3` 恰命中预期、rc=0;`run_tests.py md_cg` `192/192`、rc=0;`cargo test`(缺省与 `--features no-probe` 两态各 `26 passed / 0 failed`、零告警)rc=0;FI-M03 单格 `verdict=pass consistent=true` rc=0;chaos `-k M` 十格全「一致」rc=0;HEAD 源码树 `cargo check --all-targets` 复现 **恰好 2 条** `unexpected cfg` 告警;R-2 独立探针(release,20000×700 字符语料)测得现行 `lexical` **8.96 ms** / 两次小写化 **30.06 ms** | §4.1 |
38
+ | 未由本报告复跑的验证 | 修前取证腿、独立复核各探针、python 全量、容器两栈、`rank_parity` 对拍、采集侧的 R-2 性能探针 | §4.2、§6.5 |
39
+ | 独立复核 | 判定 **ACCEPT**;列出的 uncovered 见 §5.2 | §5 |
40
+ | 边界与未覆盖 | predict 文案漂移、R-2 三组读数互不可印证(未查明)、C-1 穷尽性只有文件级扫描、未修的留池面 | §6 |
41
+
42
+ ### 0.1 符号图例与计数口径(v1.0-r1 新增,回应读者「同一批符号三处三义」)
43
+
44
+ 本文用**互不重叠的前缀**区分三类实体;读者若见到裸的 ①②③,一律是**被引物自身的标签**,不是本文的编号。
45
+
46
+ | 前缀 | 指什么 | 出现处 | 定义处 |
47
+ |---|---|---|---|
48
+ | **D1–D8** | 本文对**缺陷行**的编号(1 项缺陷可含多行) | §1 表首列 | §1 |
49
+ | **L-a … L-j** | 本文对**复现腿/记录**的编号(10 条) | §2 各小节标题 | §2 计数表 |
50
+ | **V1–V11** | 本文对**独立复核条目**的编号,另给「采集段标」列(该条在原采集材料里带的 ①/②/③/④/旁证 标记) | §5.1 表首列 | §5.1 |
51
+ | **「绿场①/②/③」** | **FI-M03 用例自身打印**的三个标签(修复点 / 端到端 / 物证),本文引用时保留其符号并注明出自用例 | §3.7 | 用例输出原文,见 §4.1 |
52
+ | **「四可」** | **FI-M03 用例自身打印**的四项判据:**可发现 / 可隔离 / 可恢复 / 可追溯**(每项取值「是/否」) | §3.7 | 用例输出原文,见 §4.1 |
53
+ | **①–④(裸)** | **仅**出现在「采集段标」列里,指原采集材料自带的段落标记,与上文各前缀无关 | §5.1 | 本表 |
54
+
55
+ **计数口径**(同一组对象在全文只用一个数):**6 项缺陷** / **8 条缺陷取证腿** / **10 条复现记录**(含 1 条登记态复测腿 C-1d、1 条非缺陷基线腿 R-1b)/ **53 个 `_write_node` 调用点**(18 个非测试 md_cg 模块,**文件级**扫描,见 §6.6)。
56
+
57
+ **总口径(v1.0-r1 收紧,回应读者「总口径对六条腿不成全覆盖」)**:本批 6 项缺陷里,**4 项**(C-1、C-7、R-1、R-3)属「**判据面/写面与真源脱钩,且失败静默**」家族;另 **2 项不属该家族**——D6(R-2)是**性能项**(无正确性错误,修法为逐位等价变换),D8(R-6)是**构建面卫生项**(带编译器可见信号的告警 + 死 cfg 分支)。本批把二者一并纳入的理由是「可机械判定、低风险、无行为变更」,**不是**因为它们属于同一缺陷家族。
58
+
59
+ ---
60
+
61
+ ## 1. 缺陷定义与真实站点
62
+
63
+ 下表「缺陷站点」列一律为 **HEAD 口径**(本报告用 `git show HEAD:<path>` 读到的修前文本);「落点」列为**工作区口径**。
64
+
65
+ | # | 缺陷组 | 缺陷站点(HEAD 口径,本报告实读) | 修前文本的后果 | 落点(工作区口径) |
66
+ |---|---|---|---|---|
67
+ | **D1** | C-1a | `md_cg/forgetting.py:290`:`cg._write_node(node_id, os.path.join(cg.root, node["path"]), fm, node.get("content") or "")`;紧随 `:292` 取 `e`、`:293-299` 只改内存 entry 的 importance/state/protected——**全文件 `_dirty` 出现 0 次**(实跑 `git show HEAD:md_cg/forgetting.py \| grep -c "_dirty"` → `0`) | 写盘成功、盘面已新值,但标脏簿记不推进 ⇒ 读缓存仍判写盘前旧 fm 新鲜 ⇒ 同进程其后所有读永远旧值 | `md_cg/forgetting.py:295-296`(写盘)、`:297`(取条目)、`:314-316`(标脏) |
68
+ | **D2** | C-1b | `md_cg/insight.py:306`:`cg._write_node(node_id, os.path.join(cg.root, node["path"]), fm, node.get("content") or "")`;**全文件 `_dirty` 出现 0 次**(同上 grep → `0`) | 同 D1,且陈旧面更宽:`insight_state`/`tags`/`importance` 三字段同批拿旧值 | `md_cg/insight.py:309-310`(写盘)、`:311`(取条目 `ent`)、`:322-324`(标脏) |
69
+ | **D3** | C-1c | `md_cg/scrub.py:761`:`cg._write_node(nid, os.path.join(cg.root, e["path"]), fm, node.get("content") or "")`;**全文件 `_dirty` 出现 0 次**(同上 grep → `0`) | 本处比 D1/D2 更差:写盘后**连内存条目都不碰**(条目字段集不含 confidence),缓存自然冻结旧 `confidence`;`_apply_offset` 是 `calibrate(apply=True)` 的唯一落库动作 | `md_cg/scrub.py:761-762`(写盘)、`:772-774`(标脏)、`:775`(`adjusted` 计数) |
70
+ | **D4** | C-7 | `md_cg/consolidate.py:867`:`CCG_REQUIRED = ("生效条件", "子功能", "执行", "不适用条件")`(**本地副本,4 元素**);`:917`:`complete = all(_has_ccg_line(content, f) for f in CCG_REQUIRED)` | 与真源 `nodefile.CCG_REQUIRED`(6 元素:多「功能名」「验证方式」)不同 ⇒ 缺「验证方式」的弱证据节点判 `complete=True` ⇒ 可被升格进 knowledge 层 | `md_cg/consolidate.py:876`(`CCG_REQUIRED = nodefile.CCG_REQUIRED` 转发)、`:931`(同一判据,常量已换源) |
71
+ | **D5** | R-1 | `rust/src/engine.rs:140` 起 `SearchEngine::search` 内有 `:148` `query_owned = a.unify(query)`(**库/serve 路过归一层**),且 `:142` docstring 自书「(编排与评测 CLI 一致)」;而 `rust/src/main.rs:271-321`(`fn search` 的完整体,`:321` 为收尾 `}`)是**编排的第二份实现**(lexical/bucket/entity/graph → `fuse` → `round(s,6)`),**全文 `unify` 命中 0 次、`atoms` 命中 0 次**(实跑 `git show HEAD:rust/src/main.rs \| grep -n "unify\|atoms"` → 无这两词的命中) | 同一 query 同语料,评测 CLI 与库/serve 两条路 top-1 不同;自书的「一致」承诺无实现保证,且**没有机械面能发现两面劈叉** | `rust/src/engine.rs:212-217`(`prepare_query` 单点)、`:227-281`(`search_ranked` 唯一编排)、`:151-186`(`SearchEngine::search` 改为调它);`rust/src/main.rs:289-311`(`fn search` 只搬参数) |
72
+ | **D6** | R-2 | `rust/src/retrieval.rs:34-35`(HEAD):`let body = doc.like_body().to_lowercase();` / `let tags = doc.tags_joined.to_lowercase();`——位于 `fn like`(`:31`)内,而 `like` 是 `lexical` 的**每查询 × 每候选**最内层判定 | 每查询每文档两次整串新分配;文档内容建库后不变,属可前移的派生物(**性能项;无正确性错误**) | `rust/src/retrieval.rs:39-40`(引用预存串);`rust/src/store.rs:59-74`(`Doc` 新增 `like_body_lower`(`:65`)/`tags_joined_lower`(`:67`))、`:351-352`(建库时算一次)、`:359-360`(构造) |
73
+ | **D7** | R-3 | `rust/src/engine.rs:42`(HEAD):`graph_seeds_sorted: false`(缺省);`:170` 起的 seeds 支路只按 `score` 单键排序(HEAD `main.rs:302-312` 为同款副本) | 种子退化为**候选枚举序前 5**(目录序,与相关性脱钩)⇒ 相关节点可能根本进不了种子集,graph 路整条为空 | `rust/src/engine.rs:53`(缺省改 `true`)、`:266-269`(改用 `retrieval::sort_path` 三键);`rust/src/main.rs:103`(缺省 `true`)、`:158-160`(`--graph-seeds raw` 反转为排查阀) |
74
+ | **D8** | R-6 | `rust/src/atoms.rs:80`:`#[cfg(not(feature = "no-probe"))]`;`:86`:`#[cfg(feature = "no-probe")]`;`rust/Cargo.toml`(HEAD)**无 `[features]` 段**(实跑 `git show HEAD:rust/Cargo.toml \| grep -n features` → 空输出) | 每次构建 2 条 `unexpected cfg condition value: no-probe` 告警;且 `feature="no-probe"` 分支**恒不可达**(死代码) | `rust/Cargo.toml:10-20`(`[features]` + `no-probe = []`)、`rust/src/atoms.rs:83-88`(docstring)、`:94`/`:100`(两处 cfg,因补 docstring 位移);`:218`/`:228` 为两条 `#[test]` 的 cfg |
75
+
76
+ ---
77
+
78
+ ## 2. 修前现场(改动前取证,由本工作流「缺陷复现员」取得)
79
+
80
+ **来源与边界**:本节逐条引用本工作流**缺陷复现环节**采集的实测记录(原始字段 `reproduced=true` 共 10 条)。本报告**未复跑**这些腿(§6.5);§4.1 另有本报告实跑的独立证据。所有腿都在系统临时目录合成库上跑。
81
+
82
+ ### 2.0 计数表(v1.0-r1 新增,回应读者「取证覆盖面没有可核的计数口径」)
83
+
84
+ | 腿号 | 缺陷组 | 类别 | 是否计入「缺陷取证腿」 |
85
+ |---|---|---|---|
86
+ | L-a | C-1a | 缺陷现场 | ✔ |
87
+ | L-b | C-1b | 缺陷现场 | ✔ |
88
+ | L-c | C-1c | 缺陷现场 | ✔ |
89
+ | L-d | C-1d | **登记态复测**(既有 chaos 用例 FI-M03 的改动前登记) | ✘(不是新取证;是对既有用例的复测) |
90
+ | L-e | C-7 | 缺陷现场 | ✔ |
91
+ | L-f | R-1a | 缺陷现场 | ✔ |
92
+ | L-g | R-1b | **非缺陷基线**(`rank_parity` 对拍基线,采集原文自标「基线度量,非缺陷腿」) | ✘ |
93
+ | L-h | R-2 | 缺陷现场(性能) | ✔ |
94
+ | L-i | R-3 | 缺陷现场 | ✔ |
95
+ | L-j | R-6 | 缺陷现场(构建面) | ✔ |
96
+
97
+ ⇒ **10 条记录 = 8 条缺陷取证腿 + 1 条登记态复测 + 1 条非缺陷基线**。(C-1 一项占 3 条缺陷腿因其为**同族三处写点**,见 §3.1。)
98
+
99
+ ### L-a · C-1a:`forgetting.reinforce` 写盘后同进程读缓存陈旧
100
+
101
+ - **payload**:临时根 + `MdCGSecure(principal=designer, clearance=secret)` → `add('n_fi', importance=0.5)` → `flush` → `readcache` 默认装配(未设 `MDCG_READ_CACHE`)→ `search('optb1reinforce 香蕉')` 装填缓存 → `forgetting.reinforce(cg,'n_fi',delta=0.3)`
102
+ - **observed**:**无异常抛出(静默陈旧读,零告警)**。`reinforce` 返回值 `importance=0.8`;盘上 `nodefile.loads` 得 `fm.importance=0.8`;同进程 `cg._read(entry)`(被 readcache 包装)与 `cg.search` **仍返回 0.5**。缓存条目冻结写盘前旧 fm。
103
+ - **站点**:`md_cg/forgetting.py:290`(HEAD 口径;本报告逐行核对一致)
104
+
105
+ ### L-b · C-1b:`insight.verify` 写盘后同进程读缓存陈旧
106
+
107
+ - **payload**:临时根 + `MdCGSecure` → `insight.record(statement='optb1insight 香蕉 洞见事件正文', importance=0.5)` → `flush` → 装填缓存(`search`)→ `insight.verify(cg, nid, verdict='verified', evidence=['optb1 外部确证'])`
108
+ - **observed**:**无异常抛出**。`verify` 返回 `state=verified` / `importance=0.9`;盘上 `fm.insight_state=verified`、`importance=0.9`;缓存读与 `search` 仍为 `insight_state=pending`、`importance=0.5`。
109
+ - **站点**:`md_cg/insight.py:306`(HEAD 口径;核对一致)
110
+
111
+ ### L-c · C-1c:`scrub._apply_offset` 写盘后同进程读缓存陈旧
112
+
113
+ - **payload**:临时根 + `MdCGSecure` → `add('n_cal', layer='knowledge', confidence=0.5)` → `flush` → 装填缓存 → `scrub._apply_offset(cg, 0.3, min_evidence=0)`
114
+ - **observed**:**无异常抛出**。返回 `adjusted=1 / skipped=0`;盘上 `fm.confidence=0.8`(含 `fm.calibration`);缓存读仍为 `0.5`。
115
+ - **站点**:`md_cg/scrub.py:761`(HEAD 口径;核对一致)
116
+
117
+ ### L-d · C-1d:既有 chaos 用例 FI-M03 在改动前的登记态
118
+
119
+ - **命令**:`python test/chaos_injection/test_fi_m03_reinforce_stale_read.py`(用例自身用 `tempfile.mkdtemp` + 哑 `MDCG_*` env)
120
+ - **observed**:8 项 check 全 OK;`CASE_RESULT {"case_id":"FI-M03","verdict":"gap","expected":"gap","consistent":true,"fails":[]}`,退出码 0——缺陷当时以 **EXPECTED_GAP 登记在案**(红场①②③均成立:`search=0.5` / 盘面与 `get=0.8` / 缓存冻结 0.5),修复后应转 pass。
121
+ - **站点**:`test/chaos_injection/test_fi_m03_reinforce_stale_read.py`(判据面 `md_cg/forgetting.py:290`)
122
+
123
+ ### L-e · C-7:consolidate 本地四要素清单放行缺「验证方式」节点升格
124
+
125
+ - **payload**:临时根 + `MdCGOS(ROOT)`;三个 `layer='contextual'`、`merge_count=3`、`importance=0.9` 节点:`n_weak` 独缺「# 验证方式」(其余五行齐)、`n_ctrl` 缺「# 执行」、`n_full` 六要素齐;`consolidate.promote_memories(ROOT, apply=True)`
126
+ - **observed**:**无异常抛出(静默升格)**。`consolidate.CCG_REQUIRED=('生效条件','子功能','执行','不适用条件')` 判 `n_weak complete=True` → `promoted=['n_full','n_weak']`,`n_weak` 落盘 `knowledge/orphan/n_weak.md`;真源 `nodefile.CCG_REQUIRED`(6 元素)判 `n_weak complete=False`(应当拒)。
127
+ - **判据非空转的对照**:`n_ctrl` 两份清单同步判 `False`、`skipped_incomplete=1` 未升格——即该判据本身有判别力,缺口只在**要素集不全**这一处。
128
+ - **站点**:`md_cg/consolidate.py:867`(本地 CCG_REQUIRED)/ `md_cg/consolidate.py:917`(complete 判据)(均 HEAD 口径;核对一致)
129
+
130
+ ### L-f · R-1a:评测 CLI 与库层 SearchEngine 同 query 同语料 top-1 不同
131
+
132
+ - **payload**:一个临时库(30 节点 zh+en,语料/建库同 `scripts/rank_parity.py` 的 `build_cogmap`)。A 路 = `mdcg-eval --root T --lib T/graph --qfile q.jsonl --dump D --out T/out`(`main.rs::search`,原始 query);B 路 = `mdcg-eval --root T/graph --serve`(`engine.rs` `SearchEngine::search`,`atoms.unify(query)`);C 对照 = Python `MdCGSecure.search_rrf`。10 条 query。
133
+ - **observed**:**无异常抛出:3/10 条 cli≠serve**——
134
+ - `'The compiler wrote tests'`:cli=`parity_en_08` vs serve=`parity_en_00`
135
+ - `'agent review verdict'`:cli=`parity_en_09` vs serve=`parity_zh_02`
136
+ - `'memory recall pipeline'`:cli=`parity_en_08` vs serve=`parity_en_00`
137
+
138
+ 三条**全部**满足 `serve==python` 且 `cli!=python`(即评测 CLI 是唯一漏接归一层的路)。
139
+ - **站点**:`rust/src/main.rs:271-321`(HEAD 口径 `fn search` 完整体;全文 `unify` 命中 0 次、`atoms` 命中 0 次)vs `rust/src/engine.rs:148`(HEAD 口径 `query_owned = a.unify(query)`,本报告逐行核对)
140
+
141
+ ### L-g · R-1b:对拍入口 `rank_parity` 的改动前基线(**基线度量,非缺陷腿**)
142
+
143
+ - **payload**:`python scripts/rank_parity.py --exe <用 CARGO_TARGET_DIR 指向临时目录构建的 mdcg-eval.exe>`;以及加 `--dataset scripts/retrieval_dataset.json`
144
+ - **observed**:基线(改动前实测):内建合成语料 → 逐位一致 **7/10** · 集合一致 **10/10** · top-1 一致 **7/10**,exit 1;共享数据集 → 逐位一致 **8/10** · 集合一致 **8/10** · top-1 一致 **9/10**,exit 1。差异全部落在 **Python 侧 vs Rust `--serve`**(该路两侧 `unify` 都开),与 L-f 的 CLI/serve 劈叉**不是同一条腿**。
145
+ - **采集原文的如实标注**:「改动后分数变化:未测得(树未改动,无法观测改动后值)——按修法(评测路径接入/复用 SearchEngine 编排)推断 serve 路不受影响、rank_parity 数字应保持;**此推断未经执行验证**」。该推断后在实施/验证环节被实测**证实**(§4.2 第 ⑥ 项:改前改后完全相同)。
146
+ - **站点**:`scripts/rank_parity.py:102-140`(`rust_topk` 只起 `--serve`)
147
+
148
+ ### L-h · R-2:lexical 热路径每查询每文档两次整串小写化
149
+
150
+ - **payload**:临时语料 20000 文档(body≈700 字符,含大段英文原文);`store::load_docs` 后 5 次 `retrieval::lexical(&docs,&cand,'optb1q 检索语料 alpha',1e9,true)`,另在同规模上单独计时 `like()` 的 `doc.like_body().to_lowercase() + doc.tags_joined.to_lowercase()`
151
+ - **observed**:**无异常抛出(性能)**。`lexical` **30.59 ms/查询**,其中两次 `to_lowercase` **27.12 ms = 88.7%**;每次查询累计产出 **54,333,350 字节**小写串。短正文变体(body≈200 字符)为 10.30 ms / 7.70 ms = 74.8%。
152
+ - **量级口径声明(采集原文照录)**:绝对毫秒随语料长度/机器变化,**比例(热路径占比)与「每查询每文档两次分配」成立**。
153
+ - **站点**:`rust/src/retrieval.rs:34-35`(HEAD 口径 `like()` 内两次 `to_lowercase`);`Doc` 无小写预存——`rust/src/store.rs:49-60` 已有 `stripped`/`db_len`/`tags_joined` 预存先例
154
+ - **⚠ 与验证段旁证腿的读数冲突**:验证环节另有一条同探针复测腿(见 §4.2 第 ⑦ 项)报 HEAD **8.62 ms** → 工作区 **1.97 ms**。两条腿**同一口径名(20000 文档)却相差约 3.5×**;本报告另做了第一手复测(§4.1 第 9 行)并给出对账(§6.3),**结论是:方向一致、绝对值互不可印证、成因未查明**。
155
+
156
+ ### L-i · R-3:graph 路种子取候选枚举序前 5 而非相关度前 5
157
+
158
+ - **payload**:临时语料:`n00..n04`(含查询词弱命中 `score=0.5`、无 edges)、`n08`(正文不含查询词,是扩展目标)、`n09`(正文最短 `score=1.0`、`edges=['n08']`,文件名字典序在 `n00..n04` 之后);`query='optb1q'`。对比默认口径(`lex_raw` 原序 take 5)与 `retrieval::sort_path`(三键)后 take 5,再各跑 `retrieval::graph` 与 `retrieval::fuse`。端到端另用 `mdcg-eval --serve`(默认)vs `--serve --graph-seeds sorted`。
159
+ - **observed**:**无异常抛出(静默错取种子)**。默认种子=`['n00','n01','n02','n03','n04']`(唯一满分节点 `n09` 被漏掉)→ graph 路 = `[]`;`sort_path` 种子=`['n09','n00','n01','n02','n03']` → graph = `[('n08',0.5)]`。融合 top-5:默认无 `n08`;`sort_path` 下 `n08` 居首。端到端 serve:默认 top-5=`['n09','n00','n01','n02','n03']`(无 `n08`),`--graph-seeds sorted` 时 `n08` 出现在第 2 位。
160
+ - **采集原文注**:现有 `sorted` 支路只按 `score` 单键排序(HEAD `engine.rs:171-177`),未走 `retrieval::sort_path` 三键——本批在 §3.4 一并收口。
161
+ - **站点**:`rust/src/engine.rs:42`(`graph_seeds_sorted` 默认 `false`,HEAD 口径核对一致)/ `rust/src/engine.rs:170-180`(seeds 支路);同款副本 `rust/src/main.rs:302-312`(HEAD 口径)
162
+
163
+ ### L-j · R-6:`no-probe` feature 未声明(构建期告警 + 死分支)
164
+
165
+ - **payload**:`cd rust && CARGO_TARGET_DIR=<临时目录> cargo check --all-targets`(仓库零写入);另 `CARGO_TARGET_DIR=<临时目录> cargo check --features no-probe`
166
+ - **observed**:cargo 告警(编译器消息原文):`warning: unexpected \`cfg\` condition value: \`no-probe\``,位置 `src\atoms.rs:80:23` 与 `src\atoms.rs:86:19`,共 **2 条**;`note: no expected values for \`feature\``;`help: consider adding \`no-probe\` as a feature in \`Cargo.toml\``。另 `cargo check --features no-probe` **直接失败**:`error: the package 'mdcg-eval' does not contain this feature: no-probe` ⇒ `cfg(feature="no-probe")` 恒假、`atoms.rs:86` 的 `None` 分支恒为死代码。
167
+ - **本报告已把「修前态」独立复现**:`git archive HEAD rust/ | tar -x -C /tmp/…` 后在 HEAD 源码树上 `cargo check --all-targets`,输出**恰好 2 条**同款告警,位置 `80` / `86`(§4.1 末行)。
168
+ - **采集原文的补充如实观察**:全仓 grep `no-probe` 只命中 `rust/src/atoms.rs:80/86` 两行,`hive/` 下零引用、`hive/Cargo.toml` 亦无 `[features]`——本条**实际只涉及 `rust/Cargo.toml`**。
169
+ - **站点**:`rust/src/atoms.rs:80` / `rust/src/atoms.rs:86` + `rust/Cargo.toml`(HEAD 缺少 `[features]` 段)
170
+
171
+ ---
172
+
173
+ ## 3. 修法契约与落点
174
+
175
+ 修法口径有界,按性质分三类:**接线**(把已有机制接上)、**等价变换**(只前移求值时机)、**声明**(注册 cfg 名)。**未新增任何第二套判据**。
176
+
177
+ ### 3.1 C-1:三处写点补标脏(接线)——机制、三处原文、守卫形态
178
+
179
+ **机制(v1.0-r1 重写,回应读者「标脏机制写不圆、`_dirty` 究竟靠什么让缓存失效」)**。三处事实全部出自本报告读码,逐条给行号:
180
+
181
+ 1. `_dirty` 是 **`_DirtyDict`** —— 一个 **`dict` 的子类**(`md_cg/mdcg.py:882` `class _DirtyDict(dict):`),由 `MdCG.__init__` 恒以 `self._dirty = _DirtyDict()` 建立(`md_cg/mdcg.py:1018`)。它**以 node_id 为键**,同时**自带代际字段** `write_gen`(单调自增,`:916`)与 `path_gen`(`path → 最近一次标脏时的 write_gen`,`:917`)。⇒ 读者看到的两种说法**都对,且不矛盾**:`_dirty` 是「以 node_id 为键的 dict」,并**同时**带 `path_gen` 属性。
182
+ 2. **代际是被「赋值动作」推进的,不是被条目内容替换推进的**:`_DirtyDict.__setitem__`(`md_cg/mdcg.py:931-934`)先 `self._bump()`(`write_gen += 1`,`:920-921`)再 `self._note(v)`(`:923-929`:值带 `path` 时记 `path_gen[path] = write_gen`,否则退化为 `broad_gen`),最后才落到父类 dict。**子类钩子就在赋值上**,故一行 `_dirty[node_id] = e` 同时完成「登记脏集」与「推进代际」两件事。
183
+ 3. **读缓存的失效判据**:`readcache._fresh`(`md_cg/readcache.py:80-104`)对 `_DirtyDict` 走精确口径 `pg.get(path, 0) <= hit[0] and dirty.broad_gen <= hit[0]`(`hit[0]` = 该条目入缓存时的 `write_gen`)——即「该 path 最近标脏代际 ≤ 缓存代际」判新鲜;对**非 `_DirtyDict`** 形态回落 `hit[0] == getattr(dirty, "write_gen", len(dirty))`(整代际粗粒度,`:88`、`:104`)。
184
+
185
+ ⇒ 「修前不标脏」为何导致永久陈旧:**不赋值 ⇒ `write_gen` 不动、`path_gen[path]` 不生成 ⇒ 旧条目永远满足 `pg.get(path,0)=0 <= hit[0]`**。修后赋值 ⇒ `path_gen[path]` 抬到新代际 ⇒ 旧条目失效。这也解释了 §1 D1 行的措辞「`_dirty.path_gen` 不推进」是**属性访问**——`_dirty` 上确有 `path_gen` 这个属性(一个 dict),不是 `_dirty` 自身的名字。
186
+
187
+ **三处落点原文(工作区口径,本报告逐行实读;v1.0-r1 补全——三处形态完全一致,读者看到的「scrub 直接写 `_dirty[nid] = e`」是 v1.0 表格里的缩写,不是代码差异)**:
188
+
189
+ ```
190
+ md_cg/forgetting.py:314-316 md_cg/insight.py:322-324 md_cg/scrub.py:772-774
191
+ _dirty = getattr(cg, "_dirty", None) _dirty = getattr(cg, "_dirty", None) _dirty = getattr(cg, "_dirty", None)
192
+ if isinstance(_dirty, dict): if isinstance(_dirty, dict): if isinstance(_dirty, dict):
193
+ _dirty[node_id] = e _dirty[node_id] = ent _dirty[nid] = e
194
+ ```
195
+
196
+ 三处**同形**:先 `getattr(cg, "_dirty", None)`(缺该属性得 `None`),再 `isinstance(..., dict)` 类型闸,最后赋值。差别只有键名与值名(`node_id`/`nid`,`e`/`ent`)。对照先例=`md_cg/mdcg.py` 的 `update_tags` / verify 直写分支 `self._dirty[node_id] = e`。
197
+
198
+ **该形态是否为 fail-open(读者问:无 `_dirty` 的 cg 会怎样)**:见 §8.3 第 3 项的完整处置(结论:**「装了读缓存但 cg 无 `_dirty`」的形态不是静默陈旧而是立崩**——`readcache._fresh` 读 `cg._dirty` **无守卫**(`md_cg/readcache.py:82`、`:104`),第一次读即抛 `AttributeError`;`getattr` 守卫针对的是**未装读缓存的裸对象/测试替身**形态,那种形态下缓存不存在、陈旧读无从发生)。
199
+
200
+ **为什么不把标脏下沉进 `_write_node`**(三处注释同款,如 `forgetting.py:310-313`、`insight.py:320-321`、`scrub.py:769-771`):`_write_node` 另有「只对账索引、不落盘」的调用方(backfill 对账支路等),下沉会让它们凭空产生一次写入代际与自重载。
201
+
202
+ ### 3.2 C-7:升格门槛改转发真源(接线)
203
+
204
+ - `md_cg/consolidate.py:876`:`CCG_REQUIRED = nodefile.CCG_REQUIRED`——**对象同一**(守卫断言 G4a 用 `is` 判),不再复制元素元组。
205
+ - 判据本体(`:931` `complete = all(_has_ccg_line(content, f) for f in CCG_REQUIRED)`)**一行未改**,只换常量来源;`require_conditions and not complete` 分支(`:932-934`)计入 `skipped_incomplete` 不升格。
206
+ - 同步文案:`:863-865`(升格场景注释由「四要素」改六要素并写明 C-7 前只查四要素)、`:898`(生效条件)、`:904-906`(`promote_memories` docstring)、`:869-875`(常量处注释:判据单点在 `nodefile`,本处只转发不复制,并引 N208 同型教训)、`:937`(`skipped_not_hot` 邻域注释)。
207
+ - **未改项(刻意)**:`consolidate.py` 里 `:2/:10/:17/:94/:163/:182/:541/:587` 的「LLM 固化**四要素**」文案**一字未动**——那是**抽取字段**口径(确为 4),与**要素门槛**无关。
208
+
209
+ ### 3.3 R-1:编排收成单点 + 评测链路接入归一层(接线)
210
+
211
+ - `rust/src/engine.rs:212-217`:新增 `prepare_query(atoms, query)` 归一层单点——`Some(a) => a.unify(query)`、`None => query.to_string()`(与改动前无归一口径逐位一致)。
212
+ - `rust/src/engine.rs:227-281`:新增 `search_ranked(...)`(配 `:196-207` 的 `SearchParams`),四路 RRF 编排的**唯一实现**(路插入序 lexical → bucket → entity → graph、`cap=1e9`、融合后 `round(s, 6)`)。
213
+ - `rust/src/engine.rs:151-186`:`SearchEngine::search` 改为只构造参数并调 `search_ranked`——**消除双实现**。
214
+ - `rust/src/main.rs:289-311`:评测链路 `fn search` 改为只搬参数(`:296-310`),不再自带判据;`:31` 引入 `search_ranked`/`SearchParams`;`:58` 新增 `graph_seeds_sorted` 字段、`:63` 新增 `atoms` 字段、`:105` `atoms: mdcg_eval::atoms::Atoms::from_env()`(一次性载入)。
215
+
216
+ ### 3.4 R-3:种子改走 `retrieval::sort_path` 三键(接线)
217
+
218
+ - `rust/src/engine.rs:266-269`:`graph_seeds_sorted` 为真时先 `retrieval::sort_path(&mut v, docs)`(三键 −score/−importance/id)再取前 5。
219
+ - **「与 Python 同一把尺子」的证据(v1.0-r1 补,回应读者「报告未给任何证据把三键对齐到 Python」)**:
220
+ - Python 侧:`md_cg/mdcos.py:987-989`(本报告实读)——`_lexical` 的返回排序键为 `(-x[1], -float(x[0]["frontmatter"].get("importance") or 0), str(x[0].get("id") or ""))`,即 **(-score, -importance, id)**;同函数 docstring `:961-963` 自述「返回序**恒为相关度降序**」(原实现仅在超 cap 时排序)。
221
+ - Rust 侧:`rust/src/retrieval.rs:201-220`(本报告实读)——`sort_path` 的 doc 注释逐字为「对齐 `sorted(scored, key=lambda x: (-score, -importance, str(id)))`(`mdcos._lexical` 三键排序;issue #29:第三键 id 缺失会让分数并列时路内顺序漂移 → RRF 名次连锁偏移)」,实现为 `score` 降序 → `importance` 降序 → `id` 升序(`:205-219`)。
222
+ - ⇒ 「三键同一」有**两侧源码的直接对照**(键位与方向逐项相同),**不是**仅凭注释声称。
223
+ - **仍未有的证据(如实标注)**:L-i 那条腿的 payload/observed 里 Python 侧**没有进入对照**——它只比了 Rust 默认 vs `sort_path`。⇒ 「Rust 的 `sort_path` 与 Python `_lexical` 在真实语料上产出同序」**未经**那条腿实测;本报告只给出**键定义一致**这一级证据(另有采集侧 `rvprobe` 的 R3-2:「现行显式 `false` == HEAD 缺省」,同样不涉及 Python)。
224
+ - `rust/src/engine.rs:53`:`EngineConfig::default().graph_seeds_sorted` 由 `false` 改 **`true`**(`:41-48` 注释:原缺省是旧口径残留移植,`false` 保留为隔离「种子口径」与「边结构质量」的排查阀)。
225
+ - `rust/src/main.rs:103`(缺省 `true`)、`:158-160`(`--graph-seeds raw` 反转为排查阀)。
226
+
227
+ ### 3.5 R-2:小写形态预存(等价变换)
228
+
229
+ - `rust/src/store.rs:59-74`:`Doc` 新增 `like_body_lower`(`:65`) / `tags_joined_lower`(`:67`),注释(`:50-58`)写明「同一实现、同一输入,只把求值时机从每查询前移到建库」。
230
+ - `rust/src/store.rs:351-352`:建库时算一次(排在 `lit` 定形之后,故 `lit` 分支语义随之一致),`:359-360` 进构造。
231
+ - `rust/src/retrieval.rs:39-40`:`like()` 直接引用预存串;表达式逐字不变(`:43` 的 `body.contains(...) || (!tags.is_empty() && tags.contains(...))` 未动)。
232
+ - **等价性由三条 crate 内单测钉住(v1.0-r1 更正:v1.0 写「两条」却列了三个名字,数目与清单不符)**:`store::opt_batch1_tests::r2_like_lower_is_precomputed_equivalent`(预存 == 旧表达式逐文档)、`r2_like_case_insensitive_recall`、`r2_like_lower_follows_lit_branch`(`lit` 分支)。三条在 §4.1 的 `cargo test` 中**均被执行并 `ok`**(测试名由实跑 `cargo test --offline -- --list` 得到)。
233
+ - 连带:`rust/tests/i29_probe.rs:10-20` 手工构造 `Doc` 的探针补两个新字段。
234
+
235
+ ### 3.6 R-6:声明 `[features]`(选「声明」而非「删分支」)
236
+
237
+ - `rust/Cargo.toml:10-20`:新增 `[features] no-probe = []`(空特征:不引依赖、不加代码路径,仅注册 cfg 名)。理由写在文件内注释:缺省路径探测读 `CARGO_MANIFEST_DIR` 相对路径,在**只打包二进制、不携带仓库词表**的部署里不成立,env `MDCG_EN_ZH_MAP` 显式指路仍可用;删分支即永久失去「无探测构建」形态。
238
+ - `rust/src/atoms.rs:83-88`:`from_env` docstring 补齐两分支语义与 R-6 说明;`:94`/`:100` 两处 `#[cfg]`(HEAD 口径 `:80`/`:86`)。
239
+ - 两条 `#[test]`(`atoms.rs` 内,各带 cfg):`r6_probe_branch_is_active_by_default`(缺省构建跑)、`r6_no_probe_branch_is_active_under_feature`(`--features no-probe` 构建跑)——证明**该 cfg 名已被 Cargo 认知**。
240
+ - **`hive/Cargo.toml` 未改**:`git grep -n feature hive/src` 零命中,hive 无该 cfg,不需要声明(采集原文照录)。
241
+
242
+ ### 3.7 用例登记与夹具连带
243
+
244
+ - `test/chaos_injection/test_fi_m03_reinforce_stale_read.py:1` 起:由 gap 用例改写为 **pass 用例**。该用例自身打印的判据面(本报告实跑所见,§4.1)为:**绿场①(修复点)/绿场②(端到端)/绿场③(物证)**=标脏在位 / 同 query 读到 0.8 / 盘面·`get`·读缓存三者同值;外加**对照面**(`readcache.clear` 后同为 0.8,证明修复不是靠清缓存掩盖)与**四可**(该用例自报的四项:**可发现=是**(标脏即索引增量日志与读缓存代际双可见)/ **可隔离=是**(失效粒度按 `path`,只失效被写节点)/ **可恢复=是**(`clear`/重启)/ **可追溯=是**(`_dirty→flush→_index_log` 重放,跨进程可对账))。
245
+ - `test/chaos_injection/registry.py:74`:`FI-M03` 由 `expected_verdict="gap"`、`gap_tag="N133"` 改为 `"pass"` / `None`(缺口结案留痕)。
246
+ - `md_cg/test_p30_maintain.py:40-46,247`:`PROMO_HOT`/`PROMO_COLD` 夹具补「# 验证方式」行(六要素齐全),check 文案「剔除四要素不全」→「剔除六要素不全」。
247
+ - `md_cg/test_govern_directread.py:321`:G8/G9 的 `gd_pro` 夹具补「# 验证方式」行。
248
+ - `md_cg/test_p31_insight.py:81`:`LEARN_KB` 夹具补「# 验证方式」(`predict._is_settled` 亦转发该常量,缺它则知识节点不算可判定终点)。
249
+ - **性质声明**:三处夹具改动均为**加要素**,未削弱任何断言。
250
+
251
+ ---
252
+
253
+ ## 4. 验证数字
254
+
255
+ ### 4.1 本报告实跑(2026-09-29,工作目录 `<repo>`,`python -X utf8`;cargo 一律走临时 `CARGO_TARGET_DIR`)
256
+
257
+ | # | 命令(原样) | 尾部数字 | 退出码 |
258
+ |---|---|---|---|
259
+ | 1 | `python -X utf8 -m md_cg.test_opt_batch1_md_cg` | `opt-batch1 守卫(md_cg 侧):22 通过,0 失败` | `0` |
260
+ | 2 | `python -X utf8 -m md_cg.test_opt_batch1_md_cg --mutate` | 未变异基线`失败=0`;四处红项 **2**(G1c+G1d) / **2**(G2c+G2d) / **2**(G3c+G3d) / **3**(G4a+G4b+G4c),**逐处 `预期=2/2/2/3` 相等**;`定点变异自证:PASS` | `0` |
261
+ | 3 | `python -X utf8 scripts/run_tests.py md_cg` | `===== SUMMARY 192/192 通过,3 跳过(依赖缺失/平台不符) =====` | `0` |
262
+ | 4 | `python -X utf8 test/chaos_injection/test_fi_m03_reinforce_stale_read.py` | 9 项 check 全 OK;`CASE_RESULT {"case_id":"FI-M03","verdict":"pass","expected":"pass","consistent":true,"fails":[]}` | `0` |
263
+ | 5 | `python -X utf8 test/chaos_injection/run_all.py -k M` | 汇总 10 格全 `[一致]`,其中 `FI-M03 观测=pass 登记=pass`;`ALL CONSISTENT: 全部用例观测状态与登记一致` | `0` |
264
+ | 6 | `CARGO_TARGET_DIR=/tmp/… cargo test --offline`(在 `rust/`) | `22 passed`(lib)+`2 passed`(bin:`opt_batch1_tests::r1_eval_path_applies_query_unifier`、`r1_graph_seeds_default_is_sorted`)+`1 passed`(`i29_probe`)+`1 passed`(`i29_store_probe`)=**26 passed / 0 failed**,**零 `warning:` 行** | `0` |
265
+ | 7 | `CARGO_TARGET_DIR=/tmp/… cargo test --offline --features no-probe`(在 `rust/`) | 同为 **26 passed / 0 failed**(`r6` 两条 cfg 分支各被编进并执行),零告警 | `0` |
266
+ | 8 | `git archive HEAD rust/ \| tar -x -C /tmp/… && cargo check --all-targets`(HEAD 源码树,仓库零写入) | 恰好 **2 条** `warning: unexpected \`cfg\` condition value: \`no-probe\``,位置 `80 \| #[cfg(not(feature = "no-probe"))]`、`86 \| #[cfg(feature = "no-probe")]`(=R-6 修前态**我复现到位**) | `0` |
267
+ | 9 | **v1.0-r1 新增:R-2 独立探针** —— 临时 crate `/tmp/optb1_r2probe`(`Cargo.toml` 挂本地库 `mdcg_eval = { package = "mdcg-eval", path = "D:/program/dsh-memory-main/rust" }`)→ `CARGO_TARGET_DIR=/tmp/optb1_r2probe_target cargo run --release --offline` | 语料 20000 文档(body **700 字符 / 890 字节**,中英混排;`tags_joined="alpha beta"`);**现行(预存)`lexical` 中位 8.96 ms**;**两次 `to_lowercase` 合计中位 30.06 ms**;每次查询小写化产出 **18,000,000 字节**(20000 文档 × 900 B = body 890 + tags 10)。按采集腿口径(旧 `lexical` ≈ 现行 + 两次小写化)**推算占比 30.06/(8.96+30.06) = 77.0%** | `0` |
268
+
269
+ - **第 9 行的读数怎么用**:它**支持**「两次小写化是 `lexical` 热路径的主导项」这一**方向**(30.06 ms 相对现行整条 `lexical` 的 8.96 ms),但**不给出**采集腿的 88.7%;两者口径与语料不同,不能互相替代(对账见 §6.3)。探针源码与构建产物全部在**系统临时目录**,仓库零写入。
270
+ - 第 6 行的测试名清单由实跑 `CARGO_TARGET_DIR=/tmp/… cargo test --offline -- --list` 得到(含 `store::opt_batch1_tests::r2_like_lower_is_precomputed_equivalent` / `r2_like_lower_follows_lit_branch` / `r2_like_case_insensitive_recall`、`engine::tests::r1_*` ×2 / `r3_*` ×2、`atoms::tests::r6_probe_branch_is_active_by_default` 等)。
271
+ - **守卫 22 条断言的构成(实跑尾行与读码一致)**:G0 隔离与前置自证 **3**(含「读缓存默认开」这一 C-1 成立前提、「令牌库落在守卫临时目录」、「变异基线源=当前工作区源码」)· G1 C-1a **4** · G2 C-1b **4** · G3 C-1c **4** · G4 C-7 **4** · G5 单点结构 **3**(转发形态在场 / 无本地 4 元素副本 / 对照先例在位)⇒ **22**。
272
+ - **变异自证读数(实测逐条,含红项明细)**:C-1a 删标脏 → `G1c … ← dirty=[]`、`G1d … ← cached=0.5 direct=0.8`;C-1b → `G2c ← dirty=[]`、`G2d ← cached=pending direct=verified`;C-1c → `G3c ← dirty=[]`、`G3d ← cached=0.6 direct=0.8`;C-7 恢复本地 4 元素副本 → `G4a ← consolidate=('生效条件','子功能','执行','不适用条件') nodefile=(六要素)`、`G4b ← (4 元素)`、`G4c ← targeted=2 skipped_incomplete=0 samples=['cand_strong','cand_weak']`。
273
+ - **基线纪律(读码,`test_opt_batch1_md_cg.py:37-41` 自书)**:本守卫**不以 git HEAD 为基线源**——「修复前」形态由「在当前工作区源码上做定点文本变异」(`_MUTATIONS`)得到,基线随代码走、不随提交漂移。变异表每条记 `expect_red`,实际红数不等即判失败(同时钉「有判别力」与「无过度杀伤」)。fail-closed 三档退出码:`0` 全绿 / `1` 有失败或红数不符 / `2` **ANCHOR-MISS**(变异锚点找不到 ⇒ 实现改了没同步本表,硬失败不静默跳过)。
274
+
275
+ ### 4.2 由本工作流采集、**未由本报告复跑**的数字
276
+
277
+ 采集项与结果(原文照录):
278
+
279
+ | 采集项 | 结果 | 本报告是否执行 |
280
+ |---|---|---|
281
+ | 修前取证腿(§2 全部 10 条 `reproduced=true` 记录) | 见 §2 | **未复跑**(引用采集) |
282
+ | 定点变异自证(采集侧读数) | 未变异基线 `失败=0`;红项 **2/2/2/3 == 预期 2/2/2/3**;`--mutate` 退出码 `0`;ANCHOR-MISS 面:把变异表换成不存在锚点后 `--mutate` **退出码 2** 并打印 `ANCHOR-MISS`(fail-closed 实测) | 前两项**已由本报告复跑并逐位一致**(§4.1 第 1–2 行);ANCHOR-MISS 面**未复跑**(§5 引复核探针 `probe_anchor_miss.py`) |
283
+ | 定向套件 ① `python -X utf8 scripts/run_tests.py md_cg` | `192/192 通过、3 跳过`,退出码 `0`(首轮 189/192 的 3 处红为 C-7 语义收紧所致,已按新口径修夹具:`test_p30_maintain 55/0`、`test_govern_directread 40/0`、`test_p31_insight 70/0`) | **已复跑并一致**(总数 192/192 rc=0);三模块逐一数字未复跑 |
284
+ | 定向套件 ② `python -X utf8 test/chaos_injection/run_all.py -k M` | 10 格全「一致」,FI-M03 观测=`pass` 登记=`pass`,`EXIT 0` | **已复跑并一致**(§4.1 第 5 行) |
285
+ | 定向套件 ③ `cargo test --offline --manifest-path rust/Cargo.toml` | `22+2+1+1=26 通过 0 失败`;`--features no-probe` 同 26 通过 | **已复跑并一致**(§4.1 第 6–7 行) |
286
+ | 定向套件 ④ `cargo test --manifest-path hive/Cargo.toml` | `41+9+8=58 通过 0 失败`(hive 源码未改;其 `tests/judgment_surface.rs` 2 条 `unused_variables` 告警为既有、非本次引入) | **未复跑** |
287
+ | 定向套件 ⑤ R-6 构建告警 A/B | 去掉 `[features]` 段后 `cargo build --release` 输出恰好 **2 条** `unexpected cfg condition value: no-probe`;加回后 **0 告警**(两特征态 release 构建均 `rc=0`、零告警) | A 面**已由本报告以 HEAD 源码树独立复现**(§4.1 第 8 行,`cargo check --all-targets`,同样恰好 2 条);「加回后 0 告警」由本报告第 6–7 行的 `cargo test` 零 `warning:` 行侧面支持 |
288
+ | 定向套件 ⑥ `python scripts/rank_parity.py --exe <HEAD构建>\|--exe rust/target/release/mdcg-eval.exe --root <同一合成库>` | 改前与改后**完全相同**:逐位一致 `7/10` · 集合一致 `10/10` · top-1 一致 `7/10`,两次 `rc` 均为 `1`(3 条 `[DIFF]` 为既有残留,本批未改好也未改坏;rank_parity 走 `--serve`,R-1 修的评测 CLI 不在其径路,R-3 的 graph 腿在该口径 A 语料下 edges 恒空,R-2 为逐位等价变换 ⇒ **分数不变即预期**) | **未复跑**(本机未构建 HEAD 二进制;只构建了 HEAD 源码树做 `cargo check`) |
289
+ | 定向套件 ⑦ R-2 同探针复测 | 同一份探针码、同一 20000 文档合成库、release、15 次取中位:**HEAD 构建 8.62 ms → 工作区 1.97 ms(≈4.4×)**,仅 `retrieval::lexical` 热路径。探针文件为临时件,已从 `rust/tests/` 删除 | **未复跑**;本报告另做了第 9 行的独立探针(口径不同,见 §6.3) |
290
+ | python 全量 | `===== SUMMARY 259/259 通过,5 跳过(依赖缺失/平台不符) =====`,退出码 `0`(含 `PASS hive.test_exec_tools`) | **未复跑**(本报告只跑 `md_cg` 面 192/192) |
291
+ | 容器栈一 | 退出码 `0`;尾行片段:`结果: 21 pass / 0 fail`、`[PASS] smoke_test (linux)`、`=== 汇总: 38 pass / 0 fail ===` | **未执行**(本机 win32;硬边界禁止改工作区,容器命令在挂载点内跑构建) |
292
+ | 容器栈二 | 退出码 `0`;尾行片段:`# cancelled 0`、`# skipped 3`、`# todo 0`、`# duration_ms 5472.469516`。**采集片段未含 `# pass` / `# fail` 计数行** —— 本报告照录,不代补 | **未执行**(同上) |
293
+ | 实施段自报的**未跑项** | 「**未跑**(按要求留给脚本):全量 python 套件、容器双栈、`scripts`/`compiler`/`swarm`/`hive` 四个 python 组、`.github` 门禁」 | 同上,本报告未补跑 |
294
+ | 实施段自报的**未做核实** | 「Codex 报的「152ms 在 `to_lowercase`」量级**未复现**(自有语料实测 8.62ms),**原因未查明**,只报我实测到的数字」 | 本报告同样**未查明**(§6.3 三组读数并列) |
295
+
296
+ **v1.0-r1 更正一处指路错误**:v1.0 §5.2 写「python 全量与容器两栈……随后由本工作流脚本执行并回报了数字(§4.2 末三行)」——**该指路不成立**(表尾两行是「实施段自报的未跑项 / 未做核实」)。本表按**行名**指路:`python 全量`、`容器栈一`、`容器栈二` 三行。
297
+
298
+ ---
299
+
300
+ ## 5. 独立复核的判定与它列出的 uncovered
301
+
302
+ ### 5.1 判定
303
+
304
+ **判定:`ACCEPT`。** 依据(采集原文照录):「全部命令由我在**系统临时目录**独立重跑(argv + 显式 UTF-8,cargo 走临时 `CARGO_TARGET_DIR`;**未改工作区任何文件**,收尾 `git status --porcelain` 与开工快照逐条相同)」。
305
+
306
+ **编号说明(v1.0-r1)**:首列 `V1–V11` 是**本报告**为便于指路加的序号;「采集段标」列是复核材料**原本**带的段落标记(①/②/③/④/旁证),与 §1 的 D 编号、§2 的 L 编号无任何对应关系。
307
+
308
+ | # | 采集段标 | 复核项 | 它的结论 |
309
+ |---|---|---|---|
310
+ | V1 | ① | **C-1 三处写点的退化路径真的发生**(`oracle_c1.py`):用自己的裸文件正则解析 + 另起空缓存 `MdCGSecure` 扫同一 root(**不是**靠「没抛异常」判断) | 修后三条腿 `cached == disk == 独立实例` 且 `nid ∈ cg._dirty`;**修前**(在源码文本上删掉三行标脏块后内存 exec)`cached=0.5/0.6/pending ≠ disk=0.8/0.8/verified` 且 `dirty=False`——陈旧读**可判定地发生** |
311
+ | V2 | ① | `oracle_c1_equiv.py` | 三条腿**动作返回值逐字相同、落盘 frontmatter 逐字相同**(仅抹掉每次运行必异的时间戳/会话号) |
312
+ | V3 | ② | **C-7 升格门槛**(`oracle_c7.py`) | A2 `consolidate.CCG_REQUIRED is nodefile.CCG_REQUIRED`(**对象同一**);B 用自己的正则判同一弱夹具 → 4 元素口径 `complete=True` / 6 元素口径 `False`;C(`apply=True` 真落盘)修后弱节点留在 contextual、计入 `skipped_incomplete`、不在 `promoted`,**修前(常量换回 4 元素副本)弱节点确实被迁到 `knowledge/orphan/`**;六要素齐全者两口径都升格(正对照);D 第二消费面 `predict._is_settled` 同步收紧(**修前 `True`→修后 `False`**) |
313
+ | V4 | ① | **rust 腿** | `cargo test --offline` → `26 tests 0 failed` rc=0,`unexpected_cfgs` 告警 **0 行**;`cargo test --offline --features no-probe` → 缺省跑 `r6_probe_branch_is_active_by_default`、带特征跑 `r6_no_probe_branch_is_active_under_feature`(两条 cfg 分支**各被编进并执行**)。R-6 因果另证:`git archive HEAD rust/` 取改动前整棵 crate 编译 → **复现 `atoms.rs:80/:86` 两条告警**。`rvprobe`(三副本:现行/仅撤 R-2/HEAD):R2-1/R2-2 预存字段逐文档 == 改前形态 `like_body().to_lowercase()`;R2-5 12 query×jaccard 两档 **lexical 命中集与分数逐位(`to_bits`)一致**;R3-2 现行显式 `false` == HEAD 缺省;R1-1 同口径现行 vs HEAD 逐位一致;R1-2/R1-3 库路径归一层两版一致 |
314
+ | V5 | ① | **R-1 端到端**(`oracle_cli.py`,跑**真实评测二进制**) | 英文 query `«I eat beef yesterday»` → **评测 CLI top1=beef**(归一层已在评测链路生效),`MDCG_UNIFY_QUERY=0` 时 top1=tall(对照);**评测 CLI 的 top5+分数与库路径 `SearchEngine::search` 逐位一致**(单实现,跨两个入口);`--graph-seeds raw` 反向解析生效(dump 由 `a6,t2,…` 变为 `a6,t1,…`) |
315
+ | V6 | ③ | **守卫本体** | `python -X utf8 -m md_cg.test_opt_batch1_md_cg` → **22 通过 / 0 失败**,rc=0(G0:3 + G1..G4:4×4 + G5:3=22);`--mutate` → 未变异基线 `失败=0`;红项 `2/2/2/3` 恰好命中预期 `2/2/2/3`,rc=0;红项明细含 `G1d『cached=0.5 direct=0.8』`、`G2d『cached=pending direct=verified』`、`G3d『cached=0.6 direct=0.8』` |
316
+ | V7 | ③ | **删断言探针**(`probe_delete_assert.py`,内存改组表**不改文件**) | P1 删 G1 组 → `MISMATCH C-1a 红项=0 预期=2 仍全绿=该判据空转`,rc=1;P2 删 G4 组 → `MISMATCH C-7 红项=0 预期=3`,rc=1;P3 把 `ok()` 换恒真 → 四处全 `MISMATCH`,rc=1 ⇒ **预期红数是钉死的、自证非空转** |
317
+ | V8 | ④ | **不得静默可观测面** | `probe_anchor_miss.py`(内存塞幽灵锚点+真锚点混跑)→ 打印 `ANCHOR-MISS` 且**真实进程退出码 2**(有红项也不吞);`probe_positive_fail.py` → 正向模式失败退出码 `1`。docstring 声明的 1/2 两档 fail-closed **均实测可观测** |
318
+ | V9 | 旁证 | chaos 与三模块 | `test_fi_m03_reinforce_stale_read.py` → `verdict=pass consistent=true` rc=0;被改的三个 md_cg 测试模块 `40/0`、`55/0`、`70/0`(**夹具补「验证方式」是加要素,未削弱断言**) |
319
+ | V10 | — | **复核自身的工作区纪律** | 未写工作区(开工与收尾 `git status --porcelain` 逐条相同);未 `git add`/`commit`/`push`;全部实验体在系统临时目录 |
320
+ | V11 | — | **复核未跑面(自报)** | 「未按 ask 跑脚本后续的全量与容器门禁」——见 §5.2 |
321
+
322
+ ### 5.2 它列出的 uncovered(照录,不代为消除)
323
+
324
+ - **它明确未跑**(采集原文):「**未按 ask 跑脚本后续的全量与容器门禁**」——即 python 全量、容器两栈。这两项**随后由本工作流脚本执行并回报了数字**(§4.2 的 `python 全量` / `容器栈一` / `容器栈二` 三行),但**不是该复核环节的执行结果**。
325
+ - **它明确未做的核实**:「Codex 报的「152ms 在 `to_lowercase`」量级未复现(自有语料实测 8.62ms),**原因未查明**,只报我实测到的数字」。**该分歧在本报告中仍未查明**(§6.3,现为**三组**读数并列)。
326
+ - **不在其复跑面内**:L-g 的 `rank_parity` 对拍(§4.2 ⑥)、采集侧 R-2 性能探针复测(§4.2 ⑦)——复核列出的是 `oracle_cli` 的端到端面与 `rvprobe` 的逐位等价面,**不含** `rank_parity` 的分数表。
327
+
328
+ > 与本报告的关系:本报告在守卫正向、变异自证、`md_cg` 套件、chaos `-k M`、rust 两态 `cargo test`、HEAD 源码树告警复现、R-2 独立探针七个面上做了**独立于上述复核**的实跑(§4.1),读数与其一致(R-2 面为**新增**、口径不同);§2 与 §4.2 的表内项目**本报告未复跑**。
329
+
330
+ ---
331
+
332
+ ## 6. 边界与未覆盖
333
+
334
+ ### 6.1 本轮明确**不修**、留池的面(采集原文显式声明)
335
+
336
+ | # | 留池项 | 依据(采集原文 / 本报告读码) |
337
+ |---|---|---|
338
+ | 1 | `consolidate.py` 中「LLM 固化**四要素**」文案(`:2/:10/:17/:94/:163/:182/:541/:587`) | 那是**抽取字段**口径(确为 4),与**要素门槛**无关 ⇒ 刻意不改(§3.2) |
339
+ | 2 | `hive/Cargo.toml` | `git grep -n feature hive/src` 零命中,hive 无 `no-probe` cfg ⇒ 不需要声明(§3.6) |
340
+ | 3 | `--graph-seeds raw` 支路 | 由「缺省值」反转为**排查阀**(隔离种子口径与边结构质量),非缺陷面 ⇒ 保留(§3.4) |
341
+ | 4 | `rank_parity` 的 3 条既有 `[DIFF]` | 「**既有残留,本批未改好也未改坏**」;差异落在 Python 侧 vs Rust `--serve`(两侧 `unify` 都开),与 L-f 的 CLI/serve 劈叉不是同一条腿(§2 L-g、§4.2 ⑥) |
342
+ | 5 | 采集侧的四类未跑门禁 | `scripts`/`compiler`/`swarm`/`hive` 四个 python 组、`.github` 门禁,按要求留给脚本(§4.2) |
343
+
344
+ ### 6.2 本报告读码新见、但**不在本批改动面**的一处文案漂移
345
+
346
+ - `md_cg/predict.py:832` 的 docstring 写「终点是否已达「可判定」态:知识层 ∧ CCG **五要素**齐全」,而其实现(`:845-846`)消费的是**转发来的六要素**常量 `consolidate.CCG_REQUIRED`。同文件 `:830` 的生效条件注释措辞正确(「含常量 `consolidate.CCG_REQUIRED` 全部要素行」)。`md_cg/predict.py` **不在本次 `git status --porcelain` 的变更面内** ⇒ 这是**既有**的注释—实现文案漂移。**该文件的「是否算本批改动面」的处置见 §8.3 第 5 项**(本报告只判事实:**文件未改、行为随转发常量变了**)。
347
+
348
+ ### 6.3 R-2 的三组读数:并列、对账、成因未查明(v1.0-r1 重写)
349
+
350
+ 读者指出的「同一口径相差约 3.5×」成立,且实际是**三组**读数。本报告把它们并列如下,并给出**可算的**推算,但不给未经执行的解释:
351
+
352
+ | 组 | 来源 | 语料/构建 | 读数 |
353
+ |---|---|---|---|
354
+ | A | 采集(§2 L-h,缺陷腿) | 20000 文档,body≈700 字符 | `lexical` **30.59 ms**;其中两次 `to_lowercase` **27.12 ms = 88.7%**;每查询产出 **54,333,350 字节** |
355
+ | B | 采集(§4.2 ⑦,验证段) | 「同一 20000 文档合成库」、release、15 次取中位 | HEAD **8.62 ms** → 工作区 **1.97 ms(≈4.4×)** |
356
+ | C | **本报告第一手(§4.1 第 9 行)** | 20000 文档,body 700 字符 /**890 字节**、release、5 次取中位 | 现行 `lexical` **8.96 ms**;两次 `to_lowercase` **30.06 ms**;每查询 **18,000,000 字节** |
357
+
358
+ **可算的对账**:
359
+
360
+ 1. **A 与 B 的冲突**:若 B 的 8.62 ms 是**含**两次小写化的「改前 `lexical`」,则它与 A 的 30.59 ms 差 **3.5×**;若 8.62 ms 是**不含**的读数,则它与 C 的 8.96 ms 同量级(差 4%)。**两种读法本报告都无法判定**——采集材料没有留下 B 的探针源码,也未记是否预热/候选集口径。
361
+ 2. **88.7% 与 77.0%**:A 的 88.7% = 27.12/30.59(分母是**改前的整条** `lexical`);C 的 77.0% = 30.06/(8.96+30.06)(分母是**推算的改前** `lexical` = 现行 + 两次小写化)。**两者同义、不同语料不同机器**,差值落到「除小写化以外的其余开销」项:A 隐含其余 **3.47 ms**,C 隐含其余 **8.96 ms**(2.6×)。⇒ 88.7% 这个数**没有被本报告复现**,但它与 C 属同一方向、同一量级。
362
+ 3. **54,333,350 字节与我的 18,000,000 字节**:A 的每查询小写化产出 ÷ (2 串 × 20000 文档) = **1358.3 字节/串**;C 的 = **900 字节/串**(body 890 + tags 10)。两者都自洽——差异来自语料的中英比例(700 **字符**在中文占比高时可达 2 KB 级)。⇒ 该数字**不构成 A 失真的证据**(采集原文未给字节数,无法进一步核)。
363
+
364
+ **结论(本节口径)**:三组读数共同支持的只有**方向**——「两次 `to_lowercase` 是 `lexical` 热路径的主导项」。**绝对值与占比两两之间不可互相印证**;成因**未查明**;本报告只报自己的读数(C)与所依据的语料/命令,**不据 A 或 B 下结论**。
365
+
366
+ ### 6.4 变更面现场(本报告实跑;v1.0-r1 更正 numstat 措辞)
367
+
368
+ `git status --porcelain` 见文件头。**我实跑的命令与输出归属(回应读者「`git diff --numstat` 的输出本身不含 `warning:` 行」)**:
369
+
370
+ | 命令(原样) | stdout | stderr |
371
+ |---|---|---|
372
+ | `git diff --numstat` | **16 行**文件行(无 `warning:` 行) | `warning: in the working copy of '<file>', LF will be replaced by CRLF the next time Git touches it`(本报告实跑 `git diff --numstat 2>&1 >/dev/null \| head -3` 直接看到该提示的前 3 行;`git diff --numstat 2>/dev/null \| wc -l` → `16` 证明 stdout 干净) |
373
+
374
+ ⇒ v1.0 写的「去掉 `warning:` 行后」措辞**不准确**:`warning:` 行是 **git 自身写到 stderr 的换行提示**,不是被过滤掉的 stdout 内容;下表数字是 **stdout 全量**,未做任何过滤,也未受该提示影响:
375
+
376
+ ```
377
+ 19 5 md_cg/consolidate.py 18 1 md_cg/forgetting.py
378
+ 13 1 md_cg/insight.py 13 1 md_cg/scrub.py
379
+ 2 1 md_cg/test_govern_directread.py 4 2 md_cg/test_p30_maintain.py
380
+ 1 0 md_cg/test_p31_insight.py 12 0 rust/Cargo.toml
381
+ 39 0 rust/src/atoms.rs 341 58 rust/src/engine.rs
382
+ 181 54 rust/src/main.rs 8 3 rust/src/retrieval.rs
383
+ 112 0 rust/src/store.rs 6 0 rust/tests/i29_probe.rs
384
+ 7 3 test/chaos_injection/registry.py
385
+ 36 23 test/chaos_injection/test_fi_m03_reinforce_stale_read.py
386
+ ```
387
+
388
+ 新增未追踪件:`?? md_cg/test_opt_batch1_md_cg.py`(守卫)、`?? .zcode/`(**未被 `.gitignore` 忽略**,本报告实跑 `git check-ignore -v .zcode` → 无输出、rc=1)。`package-lock.json` 与本次修复无因果关系,本报告不主张其归属。
389
+
390
+ **一处必须点明的量**:`rust/src/engine.rs` 的 `341 / 58` 行变更**远大于**本批契约所要求的编排收口——其中包含多条新增 `#[test]`(`r1_*`/`r3_*`)、`SearchParams` 结构、以及大段注释;`rust/src/main.rs` 的 `181 / 54`、`rust/src/store.rs` 的 `112 / 0` 同理(含 `r2_*` 三条单测与注释)。**行数不等于缺陷修法规模**,此处仅记录现场供读者核。
391
+
392
+ ### 6.5 未由本报告执行的验证(完整清单)
393
+
394
+ 修前取证腿(§2 全部)· 独立复核各探针(§5)· python 全量 `259/259` · 容器栈一 / 栈二 · `rank_parity` 对拍 · 采集侧 R-2 性能探针(`8.62ms → 1.97ms`)· `hive` 的 `cargo test`(`58 通过`)· `scripts`/`compiler`/`swarm`/`hive` 四个 python 组 · `.github` 门禁 · `linux_verify.sh`。
395
+
396
+ ### 6.6 C-1 的穷尽性:只有**文件级**机械扫描(v1.0-r1 新增,回应读者「怎么确认三处同族写点穷尽」)
397
+
398
+ **本报告实跑的扫描**(读码,仓库只读):
399
+
400
+ ```
401
+ 扫描口径:md_cg/ 下非 test_*.py 模块,统计 `._write_node(` 出现次数与同文件 `_dirty` 出现次数(文件级,非调用点级)
402
+ 汇总:TOTAL calls=53 files=18 with_dirty=9 without_dirty=9
403
+ ```
404
+
405
+ | 有 `_dirty` 的模块 | 调用点 | 无 `_dirty` 的模块 | 调用点 |
406
+ |---|---|---|---|
407
+ | `md_cg/mdcg.py` | 15 | `md_cg/backfill.py` | 8 |
408
+ | `md_cg/writelimit.py` | 3 | `md_cg/consolidate.py` | 5 |
409
+ | `md_cg/lifecycle.py` / `protect.py` / `trust.py` / `vision_evidence.py` / `weights.py` / `mdcos.py` / `forgetting.py` / `insight.py` / `scrub.py` / `mreview/govern.py` | 各 1–2 | `md_cg/ccgc.py` / `crosscheck.py` / `subgraph.py` / `evolution.py` | 各 1–2 |
410
+
411
+ **能据它下的结论(有界)**:
412
+
413
+ 1. **它不是穷尽性证明**:文件级扫描判不出「该文件里的**哪一处**调用属于『写盘+只改内存条目』且仍在读缓存径路上」。C-1 的界定是**语义面**(写盘后内存条目陈旧却被缓存判新鲜),不是行数面。
414
+ 2. **它给出一个可核的规模**:53 个调用点中,「无 `_dirty`」的 9 个模块里有 **3 个是仓库文档化的已知形态**——`_DirtyDict` docstring(`md_cg/mdcg.py:908-911`)明载:「rebuild 以盘面扫描为准,**ccgc/crosscheck/backfill 等「直写文件 + rebuild 收尾」的写方不经 `_dirty` 标脏**,其文件改写对读缓存的可见性靠这一兜底(`clear(broad=True)` 推进 `broad_gen`)」。⇒ 这三个模块的「不标脏」是**设计内的兜底口径**,不是本批 C-1 的同族遗漏。
415
+ 3. **未逐点判定的面(如实标注)**:其余无 `_dirty` 的模块——`consolidate.py`、`subgraph.py`、`evolution.py`、`vision_evidence.py`、`weights.py`、`mreview/govern.py`——本报告**未判定**其每个调用点是否构成「写后读」陈旧风险(需要逐点读调用方与读路径)。**这是本批的覆盖边界,不是「已确认无风险」**。
416
+
417
+ ---
418
+
419
+ ## 7. 诚实留痕
420
+
421
+ 1. **本报告未复跑修前取证腿(§2)与 §4.2 表中的采集项** —— 本节引用本工作流采集的原始记录;本报告在 §4.1 列出的九条命令上做了独立实跑。
422
+ 2. **容器两栈未执行** —— 本机 win32;且栈内命令在挂载点内跑 `npm install`/`cargo build`/`linux_verify.sh full`,与「不得改工作区」的硬边界冲突。两栈**只记录采集退出码 `0`,不写成实测**。容器栈二的采集片段**未含 `# pass`/`# fail` 计数**,本报告**不代补**。
423
+ 3. **python 全量 `259/259` 未由本报告复跑** —— 本报告实跑的是 `scripts/run_tests.py md_cg`(`192/192`、rc=0)。
424
+ 4. **`rank_parity` 与采集侧 R-2 探针未由本报告复跑** —— 前者需构建 HEAD 二进制(本报告只构建了 HEAD 源码树做 `cargo check`),后者探针为临时件已删除;本报告另做了口径不同的 R-2 独立探针(§4.1 第 9 行)。
425
+ 5. **R-2 的三组读数互不可印证,成因未查明** —— 只并列与对账,**不解释**(§6.3)。
426
+ 6. **C-1 的穷尽性只有文件级扫描** —— 53 个 `_write_node` 调用点中 9 个模块无 `_dirty`,其中 3 个属仓库文档化的兜底形态;其余 6 个模块**未逐点判定**(§6.6)。
427
+ 7. **`predict.py:832` 的「五要素」文案漂移为既有、本批未改** —— 本报告读码所见,仅记录事实;其归属处置见 §8.3 第 5 项(裁定项)。
428
+ 8. **「零写入」的准确口径(v1.0-r1 更正)**:v1.0 写「未改任何源码或其它文件」「唯一写操作即本文件(仓库零写入)」——**对本报告(含本轮修订)成立**,但**不覆盖其它环节**:采集/验证段确有临时探针文件落过 `rust/tests/`,采集原文自述「已从 `rust/tests/` 删除,仓内不留」。本报告实跑核实现状:`rust/tests/` 下**只有**两个受追踪文件(`i29_probe.rs`、`i29_store_probe.rs`),`git status --porcelain` 未见任何未追踪的探针件 ⇒ **当前工作区无该残留**。本报告**未**去核证「历史上是否曾写、写了几次、是否全部清理」(本报告无从核)。本轮修订自身的构建/探针一律落在系统临时目录(`CARGO_TARGET_DIR=/tmp/…`、临时 crate `/tmp/optb1_r2probe`)。
429
+ 9. **未 `git add` / `commit` / `push`** —— 唯一写操作即本文件。
430
+
431
+ ---
432
+
433
+ ## 8. 读者反馈的逐条处置(v1.0-r1)
434
+
435
+ 处置原则:**能补证据的补证据(标注实测/读码);能说清的改措辞;确认是误报的说明为什么不改**。凡涉及「改不改代码 / 何时做 / 谁来裁定」的,本报告只给事实与依据,**裁定权归使用者**(本文件硬边界:不得动源码)。
436
+
437
+ ### 8.1 `unclear`(6 条)
438
+
439
+ | # | 读者问题 | 处置 | 落点 |
440
+ |---|---|---|---|
441
+ | 1 | §5.1 的 ①–④ 无图例、且与 §3.7「绿场①②③」、§1 表前导符号三处三义 | **已改措辞 + 新增图例**:§0.1 新增「符号图例」表,明确 **D1–D8**=缺陷行、**L-a…L-j**=复现腿、**V1–V11**=复核条目(另给「采集段标」列=材料原带的 ①–④)、**裸 ①②③** 仅指被引物自身标签;§1 表首列由符号改为 **D 编号**并入「缺陷组」列;§5.1 表首列改 **V 编号**;§3.7 的「绿场①②③」「四可」注明**出自用例自身输出**并在 §3.7 就地定义 | §0.1、§1、§3.7、§5.1 |
442
+ | 2 | 标脏机制「两说」:`_dirty.path_gen` 不推进 vs 写盘后标脏使代际推进;`_dirty` 是 dict 还是带 `path_gen` 的对象 | **已改措辞 + 补机制三条事实**:`_dirty` 是 **`_DirtyDict(dict)`**(`md_cg/mdcg.py:882`,`__init__` 于 `:1018`),既**以 node_id 为键**又**自带 `write_gen`(`:916`)/`path_gen`(`:917`)**;代际由**赋值动作**推进——`__setitem__`(`:931-934`)先 `_bump()` 再 `_note()`;失效判据在 `readcache._fresh`(`md_cg/readcache.py:80-104`)。⇒ 两说**都对且互补**,非矛盾 | §3.1 机制段 |
443
+ | 3 | 三处标脏守卫形态不一致(forgetting 有守卫、insight「类型守卫」、scrub 直写),scrub 处会不会抛 `AttributeError` | **误报(措辞所致)+ 已补原文**:三处代码**完全同形**(`getattr` + `isinstance(..., dict)`),v1.0 表格把 scrub 那格缩写成 `_dirty[nid] = e` 造成误解。§3.1 新增三处原文并排代码块。另补:即便无守卫也不会抛——`getattr` 缺省 `None` ⇒ `isinstance` 假 ⇒ 跳过。**「跳过」是否等于 fail-open 见 §8.3 第 3 项** | §3.1 |
444
+ | 4 | §5.2 指路「§4.2 末三行」找不到 python 全量与容器两栈 | **误报(指路写错)+ 已更正**:v1.0 的「末三行」确实不是那三行(表尾是「实施段自报的未跑项 / 未做核实」两行)。§4.2 末新增更正说明,改按**行名**指路:`python 全量`、`容器栈一`、`容器栈二` | §4.2 末段 |
445
+ | 5 | `git diff --numstat` 输出不含 `warning:` 行,「去掉」不明所指,数字是否被过滤 | **已改措辞 + 补实测**:`warning:` 行是 **git 写 stderr 的 LF/CRLF 提示**,不是 stdout 内容;本报告实跑 `git diff --numstat 2>/dev/null \| wc -l` → **16**(stdout 干净),`git diff --numstat 2>&1 >/dev/null \| head -3` → 打印那 3 行提示。⇒ 表内数字是 **stdout 全量、零过滤** | §6.4 |
446
+ | 6 | §3.7「四可」与「绿场」是自造说法、无法定位 | **已补定义**:「四可」=该用例**自身打印**的四项判据——**可发现 / 可隔离 / 可恢复 / 可追溯**(每项取值「是」),§3.7 就地逐项写出并注明出自用例输出(本报告实跑可见);「绿场①/②/③」同样注明为用例自身标签 | §3.7、§0.1 |
447
+
448
+ ### 8.2 `unsupported`(8 条)
449
+
450
+ | # | 读者问题 | 处置 | 落点 |
451
+ |---|---|---|---|
452
+ | 1 | 「一行一缺陷、六条腿」无可核口径;与 10 条记录、C-1 占 4 条、R-1b 非缺陷腿接不上;原 §5.2 把「六条腿」与「10 条记录」等号化 | **已改措辞 + 新增计数表**:文件头改为 **6 项缺陷 / 8 条缺陷取证腿 / 10 条复现记录**;§2 新增 2.0 计数表逐条标注**类别**与**是否计入缺陷取证腿**(C-1d=登记态复测、R-1b=非缺陷基线,两者均**不计入**);§5.2 引文中的「六条腿取证」改为按新口径转述 | 文件头、§0.1、§2.0、§5.2 |
453
+ | 2 | 总口径称「六条腿全部是脱钩且静默家族」,但 R-2 是性能项、R-6 是告警+死代码,不在三格里 | **已改措辞**:§0.1 新增「总口径(收紧)」——**4 项**(C-1/C-7/R-1/R-3)属该家族;**R-2 是性能项、R-6 是构建面卫生项**,纳入本批的理由是「可机械判定、低风险、无行为变更」,**不是**同族。§1 表中 D6/D8 行内亦标注「性能项;无正确性错误」「构建面」 | §0.1、§1 D6/D8 |
454
+ | 3 | 「与 Python 同一把尺子」无证据;R-3 的腿里 Python 侧未进对照 | **已补证据(双侧源码键定义对照)+ 保留边界**:§3.4 补 `md_cg/mdcos.py:987-989` 的排序键 `(-score, -importance, id)` 与 `rust/src/retrieval.rs:201-220` 的 `sort_path` 实现/doc 注释**逐项对照**;**同时如实标注**:L-i 那条腿 Python 侧**未进对照** ⇒ 「真实语料上同序」**仍未经实测**,本报告只给到「键定义一致」这一级 | §3.4 |
455
+ | 4 | R-2 修前读数文本内互斥(30.59/27.12 vs 8.62/1.97),§6.3 只框了 152ms,未纳入这组 | **已补第一手复测 + 重写 §6.3**:§4.1 新增第 9 行(我自己的 release 探针:8.96 ms / 30.06 ms / 18,000,000 字节);§6.3 重写为**三组读数并列 + 可算对账 + 成因未查明**(含 88.7% vs 77.0% 的分母差异、1358.3 vs 900 字节/串 的语料差异) | §4.1 第 9 行、§6.3 |
456
+ | 5 | 「两条 crate 内单测」后列了三个名字 | **已改措辞**(v1.0 数错):改为**三条**,逐一列名,并注明三条在 §4.1 的 `cargo test` 中**均被执行并 `ok`**(测试名清单由实跑 `-- --list` 得到) | §3.5 |
457
+ | 6 | HEAD 口径行号自相矛盾:`main.rs:271-320` vs `271-321`;seeds `302-310` vs `302-312` | **已统一**:本报告实读 HEAD 文本,`fn search` = **`:271-321`**(`:321` 为收尾 `}`)、seeds 支路 = **`:302-312`**;§1 D5/D7、§2 L-f/L-i 已全部改用该组数字 | §1、§2 |
458
+ | 7 | 同处声明「零写入」与「探针曾落 `rust/tests/` 后删」冲突 | **已改措辞(收窄口径)**:§7 第 8 项写明——「零写入」仅对**本报告(含本轮修订)**成立;采集/验证段的临时件由**其它环节**写入并自述已删;本报告实跑核实现状:`rust/tests/` 下只有两个受追踪文件、`git status --porcelain` 无未追踪探针件 ⇒ **当前无残留**;「历史上是否曾写、是否全部清理」本报告**未核证** | §7 第 8 项 |
459
+
460
+ ### 8.3 `nextQuestions`(7 条)
461
+
462
+ | # | 读者问题 | 本报告能给的依据(实测/读码,含行号) | 归属 |
463
+ |---|---|---|---|
464
+ | 1 | C-7 收紧后,**历史上已按旧口径升格**进 knowledge 的弱节点怎么办?存量有多少?要不要回扫/降级? | **事实面**:① 本报告实跑全仓检索未找到「回扫/降级已升格节点」的现成入口;可用的机械面是 `promote_memories(..., apply=False)` 的**预演**(只出报表不写盘,`md_cg/consolidate.py:899-901` 参数与 `:945-946` 的 `if not apply: continue`),但它的扫描面是**源层**(`source_layer="contextual"`,`:909` `cg._candidates(layer=source_layer)`),**不覆盖已在 knowledge 层的节点**。② 因此「缺「验证方式」的已升格节点」**没有现成的回扫口径**;存量计数**本报告未测**(需真库只读扫描,本报告未取得真库根,也不猜它)。 | **使用者裁定 + 需真库只读扫描**(本报告不做,也不填数字) |
465
+ | 2 | 「C-1 三处同族写点」如何确认为穷尽?有没有机械面扫过全部 `_write_node`? | **已补一次文件级扫描(本报告实跑)**:53 个调用点 / 18 个非测试模块 / 9 个模块无 `_dirty`;其中 `ccgc`/`crosscheck`/`backfill` 属仓库**文档化的兜底形态**(`md_cg/mdcg.py:908-911`:直写文件 + rebuild 收尾,靠 `clear(broad=True)` 的 `broad_gen` 兜底);其余 6 个模块(`consolidate`/`subgraph`/`evolution`/`vision_evidence`/`weights`/`govern`)**未逐点判定**。**⇒ C-1 的「三处」不是经调用点级穷尽扫描得出的**,本报告不主张穷尽(全文见 §6.6)。 | 事实已补;「要不要做调用点级穷尽扫描」=**使用者裁定** |
466
+ | 3 | `getattr` 守卫在「cg 无 `_dirty`」形态下 fail-open;那些形态下陈旧读是否仍可发生?本批是彻底关掉还是只在主路径关掉? | **读码结论**:**不是 fail-open,是立崩或不可能共存**。① `readcache._fresh` 读 `cg._dirty` **无守卫**(`md_cg/readcache.py:82`:`dirty = cg._dirty`;`:104` 同),故「装了读缓存但 cg 无 `_dirty`」的形态会在**第一次读**抛 `AttributeError`(**不是静默陈旧**)。② 主路径上 `_dirty` 恒存在:`MdCG.__init__` 以 `_DirtyDict()` 建立(`md_cg/mdcg.py:1018`),且仓库纪律禁止换成普通 dict(`:891-893` 消费方纪律)。③ 若 `_dirty` 退化为**普通 dict**,`_fresh` 走回落口径 `hit[0] == getattr(dirty, "write_gen", len(dirty))`(`:88`、`:104`)——标脏赋值改变 `len` ⇒ 仍失效(**整代际粗粒度**,不会静默陈旧)。④ 故三处 `getattr` 守卫实际服务的是**未装读缓存的裸对象/测试替身**形态——那种形态下缓存不存在,陈旧读无从发生。 | **事实已给全**;「是否要把守卫改成对缺失 `_dirty` 显式告警」=**使用者裁定** |
467
+ | 4 | R-1 改变了评测 CLI 输出(3 条 query top-1 变化),既往用评测 CLI 产出的数字/对拍/文档要不要重跑或标失效? | **可核的消费面盘点(本报告实跑 grep)**:`mdcg-eval` 在 `docs/`+`scripts/`+`data/`+`.github/` 的命中文件共 8 个:① `scripts/rank_parity.py`——**走 `--serve`**(`:102-140`),不在 R-1 改动径路上,采集 ⑥ 实测改前改后分数相同;② `docs/eval/横评_六家100题中英双查_v1.0.md:186` 自述其 rust 行为「**`mdcg-eval --serve` 引擎**」(引用的是 `docs/experiments/bench6-rust-rerun/` 的脚本与数据)⇒ **serve 路**;③ `data/external/eval_results/*.json` 6 份,其引用形态是元数据字段 `"engine": "rust (mdcg-eval)"`(只记**引擎身份**,不含 CLI 路径)。⇒ **本报告读到的消费面均不走被 R-1 改动的评测 CLI `--root/--lib` 路**;是否存在未盘点的消费面(外部引用、会话记录等)**本报告未断言**。 | 事实已补;「要不要重跑/标失效」=**使用者裁定** |
468
+ | 5 | `md_cg/predict.py` 不在变更面内,但行为被本批改变——算不算本批改动面?其 docstring「五要素」与夹具要不要一起收口? | **事实(本报告实跑 + 采集)**:① `git status --porcelain` **无** `md_cg/predict.py`(文件未改);② 其行为**确实随本批变化**——`_is_settled` 转发 `consolidate.CCG_REQUIRED`(`md_cg/predict.py:845-846`),采集复核 V3-D 实测该项「修前 `True`→修后 `False`」;③ 文案漂移在位:`:832` docstring 写「CCG 五要素齐全」,`:830` 生效条件措辞正确。⇒ **「行为被本批改变但文件未改」是事实**:改的是它依赖的常量真源。 | **使用者裁定**(合并收口 or 另开编号);本报告只记录(§6.2) |
469
+ | 6 | 提交前怎么处置 `package-lock.json` 与未追踪的 `.zcode/`?还原还是保留、要不要进 `.gitignore`? | **事实(本报告实跑)**:① `package-lock.json` **已被 git 追踪**(`git ls-files --error-unmatch package-lock.json` → rc=0),`M` 是内容/行尾层面的差异;其归属本报告**不主张**(§6.4)。② `?? .zcode/`:`git check-ignore -v .zcode` **无输出、rc=1** ⇒ **未被忽略**;`.gitignore` 里只有一条 zcode 相关规则(`:121` `.zcodeignore`,匹配的是文件名 `.zcodeignore`,**不匹配目录 `.zcode/`**)。 | **使用者裁定**(还原 / 保留 / 加 ignore 规则);本报告不改任何文件 |
470
+ | 7 | 守卫基线是「当前工作区源码 + 定点变异」,若实现与 `_MUTATIONS` 锚点同改则守卫仍全绿;除 ANCHOR-MISS 外有无第二道判据? | **同意读者的推论,并给出现状的机械面**:守卫**只有变异表一道**判据——同改实现与锚点(例如把标脏改成 `pass` 同时删掉对应 `_MUTATIONS` 条目)会**全绿**,无机械面发现(`test_opt_batch1_md_cg.py:37-41` 自书基线源即当前工作区源码)。除 ANCHOR-MISS(锚点找不到 → rc=2)之外,**不依赖变异表的独立面**只有行为面用例:`test/chaos_injection/test_fi_m03_reinforce_stale_read.py`(覆盖 **C-1a** 的写后读可见性)、`registry.py:74` 的登记一致性(跑 `run_all.py -k M` 时生效)、以及 `md_cg` 套件里既有的回归模块;采集侧的 `probe_delete_assert.py`(内存删组表)**是复核环节的一次性探针,不在常驻门禁里**。⇒ **覆盖不全**:C-1b/C-1c/C-7 没有独立于守卫变异表的常驻行为面。 | **真实缺口** —「要不要给守卫加第二道判据 / 把三处写后读做成 chaos 用例」=**使用者裁定** |
471
+
472
+ **明确未代裁的点**:第 1、2、3、4、5、6、7 条都涉及「改不改代码 / 加不加守卫 / 保不保留文件 / 何时做」,本次硬边界是「只改本报告文件、不得动源码」,故一律只给现状依据与可核行号,**不做实现、不代裁**。
473
+
474
+ ---
475
+
476
+ ## 附:本报告执行的动作留痕
477
+
478
+ | 动作 | 命令 / 手段 | 性质 |
479
+ |---|---|---|
480
+ | L1 直跑:守卫正向 | `python -X utf8 -m md_cg.test_opt_batch1_md_cg` | 只读(临时目录合成库、守卫自带隔离前置);**风险=无/单次/可逆** |
481
+ | L1 直跑:变异自证 | `python -X utf8 -m md_cg.test_opt_batch1_md_cg --mutate` | 同上 |
482
+ | L1 直跑:md_cg 面套件 | `python -X utf8 scripts/run_tests.py md_cg` | 同上 |
483
+ | L1 直跑:chaos 单格与筛选 | `python -X utf8 test/chaos_injection/test_fi_m03_reinforce_stale_read.py`、`python -X utf8 test/chaos_injection/run_all.py -k M` | 同上 |
484
+ | L1 直跑:rust 两态单测 | `CARGO_TARGET_DIR=/tmp/… cargo test --offline [--features no-probe]`(在 `rust/`) | 只读(构建产物落系统临时目录,仓库零写入) |
485
+ | L1 直跑:HEAD 源码树告警复现 | `git archive HEAD rust/ \| tar -x -C /tmp/…` + `cargo check --all-targets` | 只读(解包与构建全在临时目录) |
486
+ | L1 直跑:R-2 独立探针(v1.0-r1 新增) | 临时 crate `/tmp/optb1_r2probe`(path 依赖本仓库 `rust/`)→ `CARGO_TARGET_DIR=/tmp/… cargo run --release --offline` | 只读(探针与构建全在系统临时目录;仓库零写入) |
487
+ | 只读核对(v1.0 轮) | `git status --porcelain`、`git diff --numstat`、`git show HEAD:<path>`(forgetting/insight/scrub/consolidate/main/engine/retrieval/atoms/Cargo.toml)、`git ls-files`、`grep -n` / `sed -n` 若干、`Read` 若干 | 只读 |
488
+ | 只读核对(v1.0-r1 修订轮) | `md_cg/mdcg.py:882-944`(`_DirtyDict`)、`md_cg/readcache.py:55-105`(`install`/`_fresh`)、`md_cg/mdcos.py:987-989`(Python 三键)、`rust/src/retrieval.rs:201-220`(`sort_path`)、三处标脏原文 `sed -n`、`_write_node` 调用点全量 grep 与文件级 `_dirty` 对照扫描、`git diff --numstat 2>/dev/null \| wc -l`、`git diff --numstat 2>&1 >/dev/null`、`git check-ignore -v .zcode`、`git ls-files --error-unmatch package-lock.json`、`ls rust/tests/`、`grep -rln mdcg-eval docs/ scripts/ data/ .github/`、`git show HEAD:rust/src/main.rs` 逐行核行号、`git show HEAD:md_cg/{forgetting,insight,scrub}.py \| grep -c _dirty` | 只读(未重跑测试套件之外的门禁;未改源码) |
489
+ | 落盘 | 本文件(`docs/eval/优化第一批_接线与等价变换_v1.0.md`,v1.0-r1 整件改写) | **唯一写操作** |
490
+
491
+ **纪律声明**(按工作纪律 0.2,未输出即视为未执行):
492
+
493
+ - 按工作纪律第 4 条: 根因纪律——先取证现场不猜测; 根因找到并验证后归档认知图并补不适用条件。
494
+ - 按工作纪律第 5 条: 验证纪律——入库前必须过回放/断言/回归验证, 未验证不固化。
495
+ - 按工作纪律第 8 条: 中文思考——中文书写; 复杂(新奇/挑战/曾受批评/高信息差)→「我们需要」交流确认互补盲区; 简单→「让我」快速执行不空耗; 每段推理开篇用中文短语锚定语言。
496
+ - 按工作纪律第 15 条: 命令执行统一走python——argv列表+显式UTF-8+PYTHONUTF8=1, 不经Windows shell, 规避GBK解码异常。(本次 `git`/`cargo`/`tar` 等原生程序调用由内置 Bash 工具直出,属跨进程解码面;报告内结论所依据的关键读数均取自 `python -X utf8` 包装的套件与 cargo 的 ASCII 尾行。)
497
+ - 按工作纪律第 17 条: 任务派发统一走蜂巢——任何执行性任务经蜂巢 spawn/submit 执行并留痕(spec/status/result), agent本体只做编排; 宿主自带subagent/team不是等价通道, 兜底须声明。L1只读判定(产物落点=不改仓库/外部状态)可直跑, 须输出「L1 直跑:<命令> — 风险/频次/可逆性」留痕。
498
+ - 按工作纪律第 18 条: 工作区索引优先——查工作区文件先读 WORKSPACE_INDEX.md(仓根, 管线生成); 无则先跑 scripts/workspace_index.py --write 生成再读, 不以重复全盘浏览代替。(本次为已明确路径的单文件操作,属该条「不适用」面。)