@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,683 @@
1
+ # 优化第二批(H-6 依赖透传 · CH-1 对拍口径 · C-3 负缓存)—— 修复工程报告 v1.0
2
+
3
+ - 日期:2026-09-29
4
+ - **修订:v1.0-r1**(按读者反馈逐条处置:新增「前件出处与外部编号」一节与「行号与计数口径声明」的位移表/计数约定;四可补定义与出处;`_dep_gate` 报文与 `as_str_vec` 出处补出;新增 §附A「断言标签 → 断言文本对照」(43+40+43);§0.2 证据结构改为「主证据+启发式佐证」并更正「态②归因」;§4.2 补两栈定义表;§7 第 1 项与 §4.2 的冲突更正;新增 §8 逐条处置(unclear 7 / unsupported 8 / nextQuestions 8);另补两次实测——在役池 `guard-model` 残留核证、`--ab` 冲突态读数)
5
+ - 仓库:`D:/program/dsh-memory-main`(下称 `<repo>`);`HEAD = 4b0b3294`
6
+ - 批次标识:**opt-batch2**(三项:H-6 / CH-1 / C-3)
7
+ - **批次最重要的结论**:CH-1 的**归属更正**——**清单原判「三条 DIFF 由 R-4/R-5 造成」这一归因**被本批三态实验推翻(**推翻的是归因,不是「R-4/R-5 仍是潜在差异」的可能**——边界声明见 §0.2 末段),见 §0.2 与 §3.2、§4.3。
8
+ - 变更面(本报告实跑 `git status --porcelain` 所见,逐条照录):
9
+ - Python:`M md_cg/fsutil.py`、`M md_cg/mdcg.py`、`M md_cg/readcache.py`、`M scripts/rank_parity.py`
10
+ - Python 守卫(新增未追踪):`?? md_cg/test_c3_transient_read_negative.py`、`?? md_cg/test_rank_parity_score_mode.py`
11
+ - hive(python 面):`M hive/README.md`、`M hive/hive_mcp/mcp_server.py`、`M hive/orch.py`、`?? hive/test_h6_mcp_depends_on.py`
12
+ - Rust:`M rust/src/engine.rs`、`M rust/src/main.rs`、`M rust/src/serve.rs`
13
+ - 用例登记:`M test/chaos_injection/registry.py`、`M test/chaos_injection/test_fi_m02_transient_read_negative_cache.py`
14
+ - 另见 `M package-lock.json`(与本次修复无因果关系,本报告**不主张其归属**,仅记录现场)、`?? .zcode/`(宿主工作区件,非本批产物)
15
+ - **`hive/src/` 干净**(`git status` 无该目录任何条目)——`spec.rs` / `main.rs` / `job.rs` / `scheduler.rs` **零改动**,见 §4.4
16
+ - 未 `git add` / 未 `commit` / 未 `push`
17
+ - 本报告只落盘一行产物(本文件);**未改任何源码或其它文件**
18
+
19
+ ## 行号与计数口径声明
20
+
21
+ ### 行号:两套口径 + 位移对照表
22
+
23
+ 本文行号分两套,逐处标注:
24
+
25
+ - **工作区口径**=本报告读码当时的磁盘文本(**修后**文本,即**落点 / 现状站点**)。
26
+ - **HEAD 口径**=`git show HEAD:<path>` 的**修前**文本(**修前站点**)。
27
+
28
+ **位移对照表**(回应读者「声明了『逐处给出』却没兑现」):下表列出**本报告中同时出现过两套口径**的站点(修前数字取自 §2 采集腿,修后数字为本报告读码)。位移=修后起点 − 修前起点;`n/a`=该处为**新增代码**,修前不存在。**只出现过一种口径的站点不列**(例:`rust/src/job.rs`、`hive/src/spec.rs`、`hive/src/main.rs`、`hive/src/scheduler.rs` 全程修前=修后,因本批零改动)。
29
+
30
+ | 站点 | 修前(HEAD 口径) | 修后(工作区口径) | 位移 |
31
+ |---|---|---|---|
32
+ | `hive/hive_mcp/mcp_server.py` `_valid_job_id` | `:148-158` | `:152-162` | +4 |
33
+ | `hive/hive_mcp/mcp_server.py` `_dep_gate` | **n/a(新增)** | `:171-196` | — |
34
+ | `hive/hive_mcp/mcp_server.py` `_submit` | `:338-366` | `:376-404` | +38 |
35
+ | `hive/hive_mcp/mcp_server.py` `SPAWN_ALLOWED_KEYS` | `:450-455` | `:490-495` | +40 |
36
+ | `hive/hive_mcp/mcp_server.py` 未知键显式拒绝 | `:459-467` | `:500-507` | +41 |
37
+ | `hive/hive_mcp/mcp_server.py` `TOOLS[0].inputSchema` | `:663-691` | `:713-751` | +50 |
38
+ | `hive/orch.py` `_spawn_schema` | `:115`起 | `:115-154` | 0(同起点,尾部延长) |
39
+ | `hive/orch.py` 子 spec 白名单键循环 | `:504-507` | `:518-520` | +14 |
40
+ | `md_cg/mdcg.py` `get` 的 `except OSError` | `:2593-2606` | `:2592-2610` | −1 |
41
+ | `md_cg/mdcg.py` `_read` | `:2609-2618` | `:2646-2648` | +37 |
42
+ | `md_cg/mdcg.py` `_read_status` / `_note_read_oserror` | **n/a(新增)** | `:2625-2644` / `:2612-2623` | — |
43
+ | `md_cg/readcache.py` 缓存包装(`_cached` → `_cached_status`) | `:102-110` | `:139-151` | +37 |
44
+ | `scripts/rank_parity.py` `python_topk` | `:87-99` | `:152-178`(`pin_python_score_mode`)/ `:213-234`(`rust_open`) | +65 / +126 |
45
+ | `scripts/rank_parity.py` Rust 侧拉起 | `:110` | `:225` | +115 |
46
+ | `md_cg/mdcos.py` 读缓存装配点 | `:377-379` | `:377-379` | 0(未改) |
47
+
48
+ ### 计数:`depends_on` 白名单「15 键 / 16 键」的口径
49
+
50
+ **这两个数都对,差在时点**:`:450-455` 的 **15 键**是**修前**的 `SPAWN_ALLOWED_KEYS`(§0 摘要行与 `H6-1` 描述的是**缺陷现场**);`:490-495` 的 **16 键**是**修后**(本批新增 `depends_on`)。本报告凡出现「15 键」处均指修前、出现「16 键」处均指修后;§1.1 的表格(工作区口径)只列 16 键,缺陷定义的 15 键在 §2.1 `H6-1` 内。
51
+
52
+ ### 工作区快照的计数约定
53
+
54
+ `git status --porcelain` 的 `M` / `??` 计数**按快照时点**读,**本报告文件自身计入 `??`**:
55
+
56
+ - **开工快照**(写本文件之前):**13 个 `M` + 4 个 `??`**(`??`=`.zcode/` + 三个守卫文件)。
57
+ - **收尾快照**(写出本文件之后):**13 个 `M` + 5 个 `??`**(新增的那一项即**本文件**)。
58
+
59
+ §4.4 表内「两次**逐条相同**(13 M + 4 ??)」指的是**开工快照**与**落盘前的那次核对快照**;两处**均不含本文件**,非「把本报告排除在计数外」的另一种口径。
60
+
61
+
62
+ ---
63
+
64
+ ## 前件出处与外部编号(本版新增;回应读者「清单 / 契约无出处、N 号无说明」)
65
+
66
+ 本报告引用三类**外部前件**。逐类给出「它指什么」与「它在本仓的哪个位置」——**凡本报告未见到的,就写明未见**:
67
+
68
+ | 前件 | 指什么 | 出处 / 在本仓的位置 |
69
+ |---|---|---|
70
+ | **清单** | 本批修前那份**优化改进清单**的总表(H-6 / CH-1 / C-3 / H-1 / R-4 / R-5 / R-7 … 的同一份编号体系) | **不在本仓的 git 追踪面内**。本报告实跑 `grep -rn "R-7\|优化清单\|改进清单"`(`--include=*.md --include=*.ts`,排除 `.git`/`node_modules`)**只命中 `.zcode/` 工作流草稿与本报告自身**,未见清单原件。⇒ 本报告**只能引其经工作流草稿转述的两条原判**:R-4=两侧 `strip_tense` 规则不同、R-5=entity 路 `tags` 取值两侧不同源(`.zcode/workflow-drafts/优化第二批-H6依赖透传-CH1对拍口径-C3负缓存.dwf.ts:7`、`:43`、`:59`)。**原始清单文件本报告未见,也不主张已见。** |
71
+ | **契约** | 本批三项的**修复契约**——`CONTRACT_H6` / `CONTRACT_CH1` / `CONTRACT_C3` | `.zcode/workflow-drafts/优化第二批-H6依赖透传-CH1对拍口径-C3负缓存.dwf.ts`(**该文件是本次工作流的草稿件,未被 git 追踪**):H-6 在 `:15-40`、CH-1 在 `:42-66`、C-3 在 `:68-89`;三项共用的全局硬边界在 `:91-95`。§3 各节的「契约(原样要点)」即该三段的摘要 |
72
+ | **N 号** | 本仓「**缺陷挖掘·自主迭代**」系列的**缺陷编号**(N 序列,编号=缺陷身份,与提交/批次不是一回事) | 例:**N134**=「`_read` 的 OSError 负结果被 readcache 当正常值写入缓存」,**第 16 轮首报**,首报处 `docs/eval/缺陷挖掘_自主迭代_v16.md:86`(并见同件 `:18`、`:161`、`:179`);**N225**=「索引/日志非对象装载面类型闸」,**首报于 `docs/eval/缺陷挖掘_自主迭代_v25.md:118`**,修复报告 `docs/eval/N225_索引日志非对象装载面类型闸_v1.0.md`。**「三类坏行记账」**指 `NONOBJECT_ROW_SKIPS`(三类合计)+两个子面 `BAD_PAYLOAD_ROW_SKIPS` / `BAD_SORTKEY_ROW_SKIPS`,定义在 `md_cg/fsutil.py:286-290` |
73
+
74
+ **两套编号互不对应**(这一点第 48 行已声明,此处重申):**清单的 R-x** 与本批的 **H-6 / CH-1 / C-3** 是**两份不同的编号体系**——清单是**总表**,本批三项是**从总表里选出并新定性的项**(其中 **CH-1 这一编号本身是本批新起的**,不在清单里)。同理 **H-6 / CH-1 / C-3** 与 §2 的 **腿号(`H6-1…`、`CH1-1…`、`C3-1…`)** 也不是一回事:腿号是**本报告**为「修复前的一条复现记录」编的序号。
75
+
76
+ ---
77
+
78
+ ## 0. 结论速览
79
+
80
+ | 项 | 结论 | 证据 |
81
+ |---|---|---|
82
+ | **H-6** · `spec.depends_on` 依赖门禁在 MCP 面与编排面不可用 | 仓库以「I-1 依赖门禁」为卖点,但只有 CLI `hive submit` 支持。MCP 工具面 `_submit` **零校验**(哑写入者),`_t_spawn` 既**不收**也不写 `depends_on`(**修前**白名单 15 键;修后 16 键——计数口径见「行号与计数口径声明」);`orch._spawn` 的子 spec 白名单**也没有**该键 ⇒ 程序化接入(含 orch 派生)声明的依赖被**静默丢弃**,子任务**无依赖立即开跑**。调度侧 `scheduler.rs::deps_gate` 语义**早已实现且可用**(两态实跑证实) | §1.1、§2.1、§3.1 |
83
+ | **CH-1** · `rank_parity` 对拍两侧打分口径未接线 | harness 全文件零口径开关,长期拿 **Python 缺省 `legacy`** 比 **Rust 缺省 `jaccard`** ⇒ 用两套词法公式互相对拍。**归属更正**:清单原判的 R-4(两侧 `strip_tense` 规则不同)/ R-5(entity tags 取值不同源)**不是**这三条 DIFF 的成因——只对齐打分口径即 10/10/10 全绿 | §0.2、§1.2、§2.2、§3.2、§4.3 |
84
+ | **C-3** · 瞬态读失败被负缓存固化成「节点永久从检索面消失」 | `_read` 把**瞬时** OSError(独占句柄/资源剥夺)与「真缺」一律折叠成 `(None, None)`,`readcache._cached` 又对**任何**返回值无条件入缓存 ⇒ 一次瞬态失败即固化(条目字面 `(gen,(None,None))`),而 `cg.get` 直读照常可读 ⇒「get 能读、search 搜不到」撕裂 | §1.3、§2.3、§3.3 |
85
+ | 修法性质 | **接线**(H-6 两闸接进 MCP/编排面;CH-1 口径收单点并回读对照;C-3 三态标签单点 + 接纳判据接线)+**新建记账面**(C-3,与 N225 坏行记账同风格)+**新暴露面**(Rust `serve info.score` 回读字段,向后兼容新增) | §3 |
86
+ | **本报告实跑**验证 | 三项守卫正向 `43/43`、`40/40`、`43/43`,三处 rc 均 `0`;三处变异自证逐处红项数**恰好命中预期**;`run_tests.py` 全量 `262/262 通过、5 跳过` rc=0;`rank_parity` 修后缺省 `10/10·10/10·10/10` rc=0、冲突态 rc=3;**另用 HEAD 版 harness 的临时副本第一手复现了修前三态**(`7/10·10/10·7/10` rc=1、`6/10·9/10·6/10` rc=1、`10/10·10/10·10/10` rc=0) | §4.1、§4.2 |
87
+ | 未由本报告复跑 | 修前复现的 29 条腿(§2)、容器两栈(§4.5)、rust `cargo test`、独立复核各探针。**§4.2 表内 8 项采集项中,1 项已复跑**(`python 全量`,同一条命令)、**7 项未复跑** | §4.2、§4.5 |
88
+ | 独立复核 | 三项**全 ACCEPT**;三项各自列出的 uncovered 见 §5.2 | §5 |
89
+ | 边界与未覆盖 | `--ab` 路径绕过口径闸、`_submit` 仍零校验、非 Windows 分支为登记基线非实测、`hive/src` 未动的连带边界;**R-4/R-5 是否仍是潜在差异=未证伪(留池)**、H-1、R-7 留池 | §6 |
90
+
91
+ ### 0.1 计数口径与图例
92
+
93
+ **项的编号**:**3 项缺陷**(H-6 / CH-1 / C-3);**3 个守卫文件**;**3 项独立复核**(全 ACCEPT)。
94
+
95
+ **腿的编号**:§2 给每条修前记录一个前缀(**`H6-1 … H6-7`**、**`CH1-1 … CH1-10`**、**`C3-1 … C3-12`**)=共 **29 条修前复现记录**。其中 **28 条 `reproduced=true`**,**1 条 `reproduced=false`**(`CH1-10`:契约点名的守卫文件在改动前的树上**不存在**,属**修复产物**而非现状)。
96
+
97
+ **其它符号**:`§4.1` 表内「实跑」=本报告本次会话亲跑;「采集」=本工作流其它环节产出、本报告**未复跑**。**清单原判的 R-4 / R-5** 是**本批修前那份优化清单**的编号(清单出处与「R-x ↔ H-6/CH-1/C-3」两套编号的关系见「前件出处与外部编号」一节),与 §2 的腿号**无任何对应关系**,仅在 §0.2 与 §3.2 出现。
98
+
99
+ **「四可」的完整定义(回应读者「只出现两次、从未说明指哪四条」)**:**可发现 / 可隔离 / 可恢复 / 可追溯**(**顺序即此序**)。它**不是本报告自造词**,而是本仓故障注入套件的**既定判据栏**:
100
+
101
+ - 口径定义处:`docs/eval/故障注入实测_v1.0.md:21`——表头括注逐字为「(详证见第三节;**四可顺序=可发现/可隔离/可恢复/可追溯**)」。同一表 `:26` 给出 **FI-M02 在改动前的四可取值=「否·是·是·是」**(即**可发现=否**——这正是 C-3「静默」这一半的量化)。
102
+ - 用例内的四项断言:`test/chaos_injection/test_fi_m02_transient_read_negative_cache.py:143-149` 逐项写明——**可发现=是**(stderr 一行告警 + 进程内计数/样本可读)/ **可隔离=是**(按 path 精确处置,对照 root 与其余节点不受累)/ **可恢复=是**(无需人工介入:释放即命中;`clear` 仍为兜底)/ **可追溯=是**(计数 + 有界样本含 path 与异常类型)。C-3 的修复把**可发现**由「否」翻为「是」,其余三条本已是「是」。
103
+
104
+ **「契约」这个词在本文的两种用法**(回应读者「同一个词指两样东西」):① **本批修复契约**——§3.1/§3.2/§3.3 各节开头「契约(原样要点)」引的是 `.zcode/workflow-drafts/优化第二批-….dwf.ts` 的 `CONTRACT_H6/CH1/C3`(出处见前一节);② **被本报告判决的契约原文**——`CH1-5` 与 `CH1-10` 两处判的是**同一份** `CONTRACT_CH1` 里的具体句子,其**原文已在 §2.2 表下整段引出**(回应读者「被判决的原文没有引出,无从对照」)。
105
+
106
+ ### 0.2 归属更正:清单原判「三条 DIFF 由 R-4/R-5 造成」被本批三态实验推翻(本批最重要的结论)
107
+
108
+ **清单原判**(修前那份优化清单的归因,转述见工作流草稿 `:7`、`:43`、`:59`):`rank_parity` 对拍出现三条 DIFF,是因为 **R-4**=两侧 `strip_tense` 规则不同、**R-5**=entity 路 `tags` 取值两侧不同源。
109
+
110
+ **本批三态实验的实测**(在**改动前**的树上由本工作流编排会话定性;本报告另用 HEAD 版 harness 的临时副本**第一手复现**,见 §4.3):
111
+
112
+ | 态 | 变量 | 逐位 / 集合 / top-1 | rc | DIFF 条数 |
113
+ |---|---|---|---|---|
114
+ | ① 缺省 | 不设任何 `MDCG_*` | **7/10 · 10/10 · 7/10** | 1 | 3 |
115
+ | ② 只关归一层 | `MDCG_UNIFY_QUERY=0` | **6/10 · 9/10 · 6/10** | 1 | 4 |
116
+ | ③ 只切 jaccard | `MDCG_SCORE_MODE=jaccard` | **10/10 · 10/10 · 10/10** | 0 | 0 |
117
+ | **②+③ 同关归一层且同口径** | 两个变量同设 | **10/10 · 10/10 · 10/10** | 0 | 0 |
118
+
119
+ **证据结构(回应读者「一条够不够:既说『缺一不可』又说『充分』」——本版改为「一条主证据 + 一条启发式佐证」,强度不同、不并列)**:
120
+
121
+ 1. **主证据(充分性由此条承担,单独成立)**:**态①与态②的全部 DIFF,在「只对齐打分口径」后被清空**。
122
+ - 态①的 3 条:由**态③**(只切口径,归一层照开)清成 0 条、rc 1→0。
123
+ - 态②的 4 条:由**「②+③」那一行**(同关归一层**且**同口径)清成 0 条、rc 1→0——**不是**由单跑态③清掉的(单跑态③时归一层仍开着,是态①而非态②的变量组合,**本版更正**:上一版把两行的结果都算在态③头上,读者指认属实)。
124
+ - ⇒ 无论在哪个归一层开关态下,**只补上打分口径对齐**即可让 DIFF 归零;R-4/R-5 的解释**不需要**被引入即已足够说明现象。
125
+ 2. **启发式佐证(不承担充分性,只与主证据方向一致)**:DIFF 的**形态**指向打分公式而非分词/实体面——三条 DIFF 的 `py` / `rust` 两侧**分数多重集逐项相同、id 集合相同**,只是**同一批分数被分配给不同节点**(例:`蜂群调度 依赖门禁` py=`[(zh_08,.016393),(zh_09,.016129)]` vs rust=`[(zh_09,.016393),(zh_08,.016129)]`),而 RRF 只吃路内**名次**。
126
+ - **该条是启发式,不是证明(本版如实降级)**:读者指出「分词差异同样可能只改命中词数、改分数、改名次,而不改 id 集合」——**这一点成立**,本报告不再主张「症状形态」构成对 R-4/R-5 的排除。**排除力的唯一来源是第 1 条。**
127
+
128
+ **该结论的边界(本版措辞收紧,回应读者「第 6 行『推翻』与第 68 行『未证伪』强度矛盾」)**:本实验推翻的是**一条具体的归因判断**——「这三条(以及态②下的第四条)DIFF 是 R-4/R-5 造成的」**为假**;它**没有**、也不能证伪「R-4/R-5 本身是否仍是两侧的潜在差异」——那需要**专门的漂移样本**,本批未做,**留池**(§6.1 第 1 条)。全文凡说「推翻」处均指**前者**。
129
+
130
+ ---
131
+
132
+ ## 1. 三项的定义与真实站点
133
+
134
+ ### 1.1 H-6 · `spec.depends_on` 依赖门禁在 MCP 面与编排面不可用
135
+
136
+ **定义**:仓库根 `README.md` 与 `hive/README.md` 把「I-1 依赖门禁:`spec.depends_on` 任务 DAG(上游全 `done` 才被领取,失败传播)」当作能力卖点,但该能力**只接在 CLI `hive submit` 一条路上**。MCP 工具面与编排面既不能声明依赖、也没有任何校验 ⇒ 程序化接入方「以为写好了 DAG,实际子任务无依赖并发跑」。
137
+
138
+ **真实站点(工作区口径=本报告读码所见的修后文本)**:
139
+
140
+ | 面 | 站点 | 我读到的事实 |
141
+ |---|---|---|
142
+ | **判据单点(新)** | `hive/hive_mcp/mcp_server.py:171-196`(`_dep_gate`) | `:184` `deps is None → None`(缺省不校验不写);`:186` 非 list → 类型原因串;`:192` `if not _valid_job_id(d)` → 格式原因串;`:194` `if not os.path.isdir(os.path.join(jobs, d))` → 存在性原因串;`:196` 全过返回 `None`。**三条报文字面见本表下方的引出块** |
143
+ | 格式判据复用面 | `hive/hive_mcp/mcp_server.py:152-162`(`_valid_job_id`) | `:159` `isinstance(str) and startswith("h")`;`:161-162` 其余字符限 ASCII 字母/数字/下划线 |
144
+ | MCP 入参白名单 | `hive/hive_mcp/mcp_server.py:490-495`(`SPAWN_ALLOWED_KEYS`) | `frozenset` **16 键**,`:494` 含 `"depends_on"` |
145
+ | MCP 提交面 | `hive/hive_mcp/mcp_server.py:499-524`(`_t_spawn`) | `:500` 未知键显式拒绝;`:514` `jobs = _jobs_dir()`;`:522` `dep_err = _dep_gate(jobs, a.get("depends_on"))`——**位置在 `:525 _ensure_serve(jobs)` 之前**;`:523-524` 不过闸即 `{"ok": False, "error": dep_err}` |
146
+ | MCP spec 落盘 | `hive/hive_mcp/mcp_server.py:553-556` | `if a.get("depends_on") is not None: spec["depends_on"] = list(a["depends_on"])`(原样、保序;显式 `[]` 也落键) |
147
+ | MCP 哑写入者(**未改**) | `hive/hive_mcp/mcp_server.py:376-404`(`_submit`) | 建目录 → 写 `spec.json` → 写 `status.json`,**全函数零校验**(闸落在两个构建 spec 的入口,不在 `_submit` 内——见 §3.1 的偏离声明) |
148
+ | MCP 工具 schema | `hive/hive_mcp/mcp_server.py:713-751` | `:716` description 写「**只接受下方 properties 列出的 16 个参数**」;`:739-747` `properties.depends_on`(array of string,含两闸说明) |
149
+ | 编排工具 schema | `hive/orch.py:115-154`(`_spawn_schema`) | `:141-149` `depends_on`(array of string,说明 id 形如 `poll_subtasks` 返回的 job_id、须已存在) |
150
+ | 编排子 spec 透传 | `hive/orch.py:510-521` | `:518-519` 白名单键清单含 `"depends_on"`;`:520` 沿用它既有纪律 `if a.get(k) not in (None, "", [], {})`(显式传值优先、缺省不写) |
151
+ | 编排同闸 | `hive/orch.py:541-551` | `:549` `dep_err = _hm._dep_gate(jobs, a.get("depends_on"))`——**调同一个函数**;`:550-551` 不过即 `{"ok": False, "error": dep_err}`;`:552` 才 `_hm._submit(jobs, sub)` |
152
+ | 文档同步 | `hive/README.md:153`、`:277`、`:282`、`:461` | `:277` 新增完整的 `depends_on` 字段行(三维支持:CLI / MCP / orch);`:282` 「只接受其中 **16** 键」;`:461` `spawn_subtask` 行补可选 `depends_on` |
153
+
154
+ **`_dep_gate` 的报文字面(本版新增,回应读者「『文案与 CLI 逐字对齐』无法核对」)**——三条报文逐字如下(本报告读 `mcp_server.py:189-195` 所见):
155
+
156
+ | 分支 | `_dep_gate` 的报文(工作区口径,`mcp_server.py`) |
157
+ |---|---|
158
+ | 非列表 | `:189-190` `f"depends_on 必须是字符串列表(job_id 数组),got {type(deps).__name__}: {deps!r}——不静默强转/不降级为「无依赖」"` ← **此条 CLI 侧没有对应物**(见 §3.1 偏离 2) |
159
+ | 格式闸不过 | `:193` `f"depends_on 项非法: {d}(须为 h 开头且不含路径成分的 job_id)"` |
160
+ | 存在性闸不过 | `:195` `f"依赖不完整: {d}(任务不存在,先提交上游任务)"` |
161
+
162
+ 与 CLI 侧**逐字符相同**的**只有后两条**:`hive/src/spec.rs:204-206` 的 `format!("depends_on 项非法: {d}(须为 h 开头且不含路径成分的 job_id)")`、`hive/src/main.rs:292-294` 的 `format!("依赖不完整: {dep}(任务不存在,先提交上游任务)")`(本报告读码逐字比对)。第一条是本面**独有**的更严判据。
163
+
164
+ **同判据的 Rust 侧真源(本批零改动,`git status` 无 `hive/src/` 条目)**:
165
+
166
+ | 站点 | 事实 |
167
+ |---|---|
168
+ | `hive/src/job.rs:63-67` | `pub fn valid_job_id`:非空 ∧ 以 `h` 开头 ∧ 每字符 `is_ascii_alphanumeric() \|\| '_'` |
169
+ | `hive/src/spec.rs:195-208` | 提交侧**格式闸**:`:203` `if !crate::job::valid_job_id(d)` → `:204-206` 报文「`depends_on 项非法: {d}(须为 h 开头且不含路径成分的 job_id)`」 |
170
+ | `hive/src/main.rs:282-298` | 提交侧**存在性闸**:`:289` `if !jobs.join(dep).is_dir()` → `:290-295` 报文「`依赖不完整: {dep}(任务不存在,先提交上游任务)`」 |
171
+ | `hive/src/scheduler.rs:699-738` | 调度侧 `deps_gate`:`:704` 读 `spec.json` 的 `depends_on`;`:712` 结构闸;`:716` `is_dir`;`:727-735` `done → continue` / `error\|timeout\|killed\|needs_review → Err` / 其余 `Ok(false)` 等待 |
172
+ | `hive/src/scheduler.rs:220-243` | 领取循环接线:`:224` `match deps_gate(...)`;`:225-240` `Err` → `patch_status` 写 `state=error`;`:241` `Ok(false) → continue`;`:242` `Ok(true) → {}` |
173
+ | `hive/src/json.rs:63-81` | **`as_str_vec` 本体(本版新增,回应读者「CLI 宽松采信无出处」)**:`:63-64` 生效条件写「本值为 `Arr` → 逐项转字符串……**非数组 → 单元素含原文本**;`Null` → 空」;`:65` 不适用条件写「**不做类型校验(宽松取值,如 `depends_on`/`as_str_vec` 的容错读取)**」;`:78-79` 实现即 `Json::Null => Vec::new()` / `other => vec![other.as_str()...]` ⇒ **顶层裸字符串(或任何非数组)被当作单元素列表采信**。`depends_on` 的两处消费点均走它:`spec.rs:195-198`、`scheduler.rs:704`(另 `main.rs:284-287` 的存在性闸同款) |
174
+
175
+ ### 1.2 CH-1 · `rank_parity` 两侧词法打分口径未接线
176
+
177
+ **定义**:`scripts/rank_parity.py` 做「Python `search_rrf` ↔ Rust `mdcg-eval --serve`」的**逐位对拍**,但它**从不钉打分口径**——两侧各自吃**产品缺省**,而两侧产品缺省**不同**(Python `legacy` / Rust `jaccard`)⇒ 该 harness 长期在**拿两套词法打分公式互相比较**。这是**本批新定性**的缺陷,替换清单原 R-4/R-5 归因(§0.2)。
178
+
179
+ **真实站点(工作区口径)**:
180
+
181
+ | 面 | 站点 | 我读到的事实 |
182
+ |---|---|---|
183
+ | 口径单点(新) | `scripts/rank_parity.py:64-67` | `:67` `SCORE_MODE = "jaccard"`——顶部注释 `:64-66` 写明「**唯一单点**……不接受用 env 改口径」 |
184
+ | 两侧缺省事实(新) | `scripts/rank_parity.py:69-73` | `:72` `_PY_DEFAULT = "legacy"`;`:73` `_RUST_DEFAULT = "jaccard"` |
185
+ | Python 侧钉住(新) | `scripts/rank_parity.py:152-177`(`pin_python_score_mode`) | `:165` `from md_cg import eval_common`;`:169-172` env `MDCG_SCORE_MODE` 与钉住值冲突 → **原样交回冲突**(不静默覆盖/不静默照吃);`:173-174` `eval_common.use_jaccard()`;`:177` 读回 `mdcg.SCORE_MODE` |
186
+ | Rust 侧回读(新) | `scripts/rank_parity.py:191-210`(`rust_reported_score`) | `:197` 发 `{"op":"info"}`;`:207` `mode = resp.get("score")`;`:208-209` 读不到即 `RuntimeError`(fail-closed) |
187
+ | Rust 侧显式入参(新) | `scripts/rank_parity.py:213-234`(`rust_open`) | `:225` `Popen([exe, "--root", root, "--serve", "--score", score], ...)`——**不吃 `Config::default()`** |
188
+ | main 接线 | `scripts/rank_parity.py:287-291`、`:330-337`、`:339-356`、`:358-360` | `:288` 钉 Python 侧;`:291` 单点坏掉 rc=3;`:332` 拉起 + 回读;`:337` 回读失败 rc=4;`:340-356` 两侧口径对照,不一致即 rc=3 且**不给逐位读数**;`:358-360` 头部自描述 `score=jaccard=rust jaccard(两侧显式钉住)` |
189
+ | 对拍判定 | `scripts/rank_parity.py:362-384` | `:382-383` 打印三项读数;`:384` `return 0 if order_ok == total else 1` |
190
+ | `--ab` 分支 | `scripts/rank_parity.py:294-321` | `:312` 自描述口径;`:321` `return 0`——**先于 `:340` 的两侧对照闸返回**(§6.2 残余面) |
191
+ | **Python 产品缺省**(未改) | `md_cg/mdcg.py:499-500` | `SCORE_MODES = ("legacy", "jaccard")`;`SCORE_MODE = os.environ.get("MDCG_SCORE_MODE") or "legacy"` |
192
+ | **Rust 产品缺省**(未改) | `rust/src/engine.rs:49-53` | `:52` `jaccard: true`(`EngineConfig::default()` 内) |
193
+ | **Rust CLI 缺省**(未改) | `rust/src/main.rs:99` | `jaccard: true, // 缺省 jaccard(长度自惩罚),与 Python SCORE_MODE 缺省一致` |
194
+ | 评测面既定单点(未改) | `md_cg/eval_common.py:79-96`(`use_jaccard`) | `:96` `m.SCORE_MODE = "jaccard"` |
195
+ | Rust 侧新增暴露面 | `rust/src/engine.rs:65-68`(`score_label`)、`:169-170`(`SearchEngine::jaccard()` 访问器);`rust/src/main.rs:182-183`(转调单点)、`:204-209`(`--score` help + 两侧缺省不同提示)、`:776-782`(serve 就绪行自报);`rust/src/serve.rs:65-79`(`info` 回带 `score`)、`:15-21`(协议 docstring) | `--serve` 与评测 CLI 共用 `:154` 的 `--score` 解析;就绪行与 `info` 同源于 `engine::score_label` |
196
+
197
+ **失实注释(既有、本批未改,`git diff` 无这两处 hunk)**:`rust/src/main.rs:13-14` 自书「打分 `sim = |qb ∩ db| / |qb ∪ db|`(缺省 jaccard,与 Python `mdcg.SCORE_MODE` 缺省一致)」——**与事实相反**(Python 缺省是 `legacy`)。本报告实跑核对:`git show HEAD:rust/src/main.rs` 的 `:13-14` 与 `:99` 与工作区**逐字相同**,而 `git diff -U0 rust/src/main.rs` 的 hunk 只落在 `179/183/204/206/776/780` ⇒ **该失实断言是本批之前就存在的**,属 §6.2 列出的陈化文案。
198
+
199
+ ### 1.3 C-3 · 瞬态读失败被负缓存固化成「节点永久从检索面消失」
200
+
201
+ **定义**:`md_cg/mdcg.py::_read` 把**瞬时** OSError(Windows 独占句柄、权限剥夺、同名目录顶位、磁盘瞬时故障)与「真缺 / 无密钥」**一律**折叠成 `(None, None)`;`md_cg/readcache.py` 的接纳逻辑对**任何**返回值——包括 `(None, None)`——**无条件入缓存**,且该 path 无写事件时 `_fresh` 判定**恒真** ⇒ 一次瞬态 OS 失败被固化成「该节点从检索面永久消失,直到进程重启或该 path 再写盘」(cache 条目字面 `(gen, (None, None))`)。而 `cg.get` 走**裸 open**、不入缓存,照常可读 ⇒ 「**get 能读、search 搜不到**」撕裂。既有 chaos 用例 FI-M02(N134)以 `EXPECTED_GAP` 登记该缺口。
202
+
203
+ **真实站点(工作区口径=修后)**:
204
+
205
+ | 面 | 站点 | 我读到的事实 |
206
+ |---|---|---|
207
+ | 判别真源(新) | `md_cg/fsutil.py:431-439` | `:431` `READ_FAIL_ABSENT = "absent"`;`:432` `READ_FAIL_TRANSIENT = "transient"`;`:434-439` 模块级计数 `TRANSIENT_READ_FAILURES` + 样本 `TRANSIENT_READ_SAMPLES` + `_TRANSIENT_READ_SAMPLE_CAP = 32` + `_TRANSIENT_READ_WARN_CAP = 32` |
208
+ | **唯一判别点**(新) | `md_cg/fsutil.py:443-450`(`classify_read_failure`) | `:448-450` `if isinstance(exc, FileNotFoundError): return READ_FAIL_ABSENT` / `return READ_FAIL_TRANSIENT`——即「判不准一律归瞬时」(fail-closed 方向:宁可多读一次,不把可读节点判死) |
209
+ | 记账面(新) | `md_cg/fsutil.py:454-473`(`note_transient_read_failure`)、`:477-479`(`transient_read_stats`)、`:483-487`(`reset_transient_read_stats`) | `:460` 无条件累加;`:461-463` 有界补样本(元素 `(path, 异常类型名, errno)`);`:464-465` 超 `_TRANSIENT_READ_WARN_CAP` 后不再写 stderr(**计数恒完整**);`:466-472` stderr 一行汇总告警 |
210
+ | 记账调用面(新) | `md_cg/mdcg.py:2612-2623`(`_note_read_oserror`,`@staticmethod` 于 `:2613`) | `:2620-2622` 仅当 `classify_read_failure(exc) == READ_FAIL_TRANSIENT` 才记账并返 `True` |
211
+ | **三态单点**(新) | `md_cg/mdcg.py:2625-2644`(`_read_status`) | `:2636-2637` `ValueError`(越界)→ `(None, None, None)` 终态;`:2639-2640` 打开成功 → `nodefile.loads(...) + (None,)`;`:2641-2644` `except OSError`:记账成功 → `(None, None, fsutil.READ_FAIL_TRANSIENT)`,否则 → `(None, None, None)` |
212
+ | 对外二态收缩(新) | `md_cg/mdcg.py:2646-2648` | `:2648` `return self._read_status(entry)[:2]`——返回形状与改前**逐位一致**,包内既有调用点零改动 |
213
+ | `get()` 记账(新) | `md_cg/mdcg.py:2592-2610` | `:2601` `except OSError as exc`;`:2605` `self._note_read_oserror(p, exc)`;`:2606` 仍 `return None`(公开语义不变) |
214
+ | 导入面(新) | `md_cg/mdcg.py:28-29` | `from . import (..., fsutil)` |
215
+ | 缓存接纳判据(新) | `md_cg/readcache.py:128-153`(`install` 的三态分支) | `:128` `status_fn = getattr(cg, "_read_status", None)`;`:139-151` `_cached_status`:`:143-145` 命中即返回 `hit[1] + (None,)`;**`:147-149` `if val[2] is not None: return val`——瞬时读失败一律不入缓存**;`:150` 才 `cache[p] = (gen, (val[0], val[1]))`(**存储面恒为二态**) |
216
+ | 回落分支(新) | `md_cg/readcache.py:154-169` | 无 `_read_status` 的载体走保守侧:`:166-168` `if not val or val[0] is None or val[1] is None: return val`(空结果不接纳) |
217
+ | 文档串 | `md_cg/readcache.py:31-39`(模块)、`:84-103`(`install`);`md_cg/fsutil.py:407-439` | 写明「不入缓存 vs 带标记入缓存」的取舍与代价面论证 |
218
+ | 未动的失效判据 | `md_cg/readcache.py:106-126`(`_fresh`)、`:71`(`install`)、`:196`(`clear`) | `_fresh` / `write_gen` / `broad_gen` 逐字未动(D-4 面不碰——契约明列「不许动」) |
219
+ | 既有用例 | `test/chaos_injection/test_fi_m02_transient_read_negative_cache.py:45-55`(平台分支)、`:90-99`(`ctypes.WinDLL` 独占句柄置景)、`:110-149`(判据 ①–⑤ + 恢复面 + **四可**——四可=**可发现/可隔离/可恢复/可追溯**,定义见 §0.1,用例内四项断言在 `:143-149`) | 非 Windows 走 `:47-55` → `case.finish("pass","pass")`(**登记基线,非实测**) |
220
+ | 用例登记 | `test/chaos_injection/registry.py:74-75` | `"FI-M02": {"expected_verdict": "pass", "gap_tag": None, ...}`(由 `gap` 转 `pass`,缺口结案留痕 `:64-73`) |
221
+
222
+ ---
223
+
224
+ ## 2. 修前现场(改动前取证,由本工作流「缺陷复现」环节取得)
225
+
226
+ **来源与边界**:本节逐条引用本工作流**缺陷复现环节**采集的实测记录(共 29 条,其中 `reproduced=true` 28 条、`false` 1 条)。**本报告未复跑这 29 条腿**(§4.5),唯一例外是 **§4.3 的 CH-1 三态**——那部分本报告用 HEAD 版 harness 的**临时副本**在改动后的树上**第一手复现**,数字与采集**逐条一致**。所有腿都在系统临时目录合成库上跑。
227
+
228
+ ### 2.0 计数表
229
+
230
+ | 项 | 腿号区间 | 条数 | `reproduced=false` |
231
+ |---|---|---|---|
232
+ | H-6 | `H6-1 … H6-7` | 7 | 0 |
233
+ | CH-1 | `CH1-1 … CH1-10` | 10 | **1**(`CH1-10`) |
234
+ | C-3 | `C3-1 … C3-12` | 12 | 0 |
235
+ | **合计** | | **29** | **1** |
236
+
237
+ ### 2.1 H-6(7 条)
238
+
239
+ | 腿 | payload(采集原文摘要) | observed(采集原文摘要) | 站点 |
240
+ |---|---|---|---|
241
+ | **H6-1** | ①静态读 `TOOLS[0].inputSchema.properties` 与 `SPAWN_ALLOWED_KEYS`;②真实 JSON-RPC 路径 `_rpc` 调 `hive_spawn`,`arguments` 带 `depends_on=['h1790000000000_abcd']`,`HIVE_JOBS_DIR` 指向临时池 | ① schema **15 键**(无 `depends_on`),`'depends_on' in properties = False`;`SPAWN_ALLOWED_KEYS` 基数 **15**,`'depends_on' ∈ 白名单 = False`。② 返回 `{"ok": false, "error": "hive_spawn 不接受参数:depends_on——本工具只提交 LLM 委托型任务,入参白名单外的键进不了 spec,故显式拒绝(不再静默丢弃)。…(指路 CLI)"}`;且临时 JOBS 目录**未被创建**(`os.path.isdir=False`)⇒ 守卫在 `_jobs_dir()/_ensure_serve` **之前**就返回,未触任何 serve。③ 对照组(不带 `depends_on`)落 `_submit` 的 spec 键 `['context_budget_tokens','model','reasoning_effort','timeout_s','user_prompt','workdir']`,`'depends_on' not in spec` | 修前 `hive/hive_mcp/mcp_server.py:459-467`(未知键显式拒绝)、`:450-455`(`SPAWN_ALLOWED_KEYS`)、`:663-691`(`TOOLS[0].inputSchema`) |
242
+ | **H6-2** | 临时池上直接调 `hive.hive_mcp.mcp_server._submit(jobs, spec)`,`spec.depends_on` 取四组合成载荷:`['../escape']` / `['x1','notajob']` / `['h1790000000000_dead']` / `['../escape','x1','h1790000000000_dead']` | 四组**全部无异常**返回 job_id(如 `h1790664504274_9388bb`);落盘 `spec.json` **逐字保留**该 `depends_on`(逐字对比 `True`),`status.state='pending'`(可被 serve 领取)。池外**未出现** `escape` 目录 | 修前 `hive/hive_mcp/mcp_server.py:338-366`(`_submit`:建目录→写 spec→写 status,**全函数零校验**;文件内 `'depends_on'` 出现 **0** 次) |
243
+ | **H6-3** | 桩掉 `orch._hm._submit` 捕获子 spec,`orch._CFG` 设临时 `job_dir`/池,调 `orch._spawn({'user_prompt':'子任务:跑一遍回归','model':'deepseek-flash','depends_on':['h1790000000000_abcd']})`;第二组载荷 `['../escape','x1']` | 两组**均**返回 `{"ok": true, "job_id": "hCHILD0001", "state": "pending", …}`;实际提交的子 spec 键 `['context_budget_tokens','model','orch_job','reasoning_effort','timeout_s','tools','user_prompt','workdir']`,`'depends_on' in sub = False`;非法 id 组同样 `ok:true`、子 spec 无该键、**无任何 error** ⇒ **静默降级为无依赖**。另:`spawn_subtask` schema 的 `parameters.properties` 仅 **8 键**,无 `depends_on` | 修前 `hive/orch.py:504-507`(白名单键循环,无 `depends_on`;**全文件 `'depends_on'` 仅出现 1 次**且在 `:114` 的过时注释里)、`:499-528`(子 spec 构造与提交)、`:115` 起(`_spawn_schema`) |
244
+ | **H6-4** | **正对照**:`tempfile.mkdtemp` 临时池 + 预置上游目录;`hive.exe submit --jobs <temp> --spec <temp spec>`,四组 spec 分别 `['../escape']` / `['x1']` / `['h1790000000000_dead']` / `['h1790000000000_beef']` | ① `../escape` → rc=1,报文「`depends_on 项非法: ../escape(须为 h 开头且不含路径成分的 job_id)`」;② `x1` → rc=1,同款格式闸;③ `h1790000000000_dead` → rc=1,「`依赖不完整: …(任务不存在,先提交上游任务)`」(存在性闸);④ 依赖目录已存在 → rc=0,`{"ok":true,"job_id":"h1790664529410_76e0",…}`。**逐条与 MCP 面(H6-2)行为相反** | `hive/src/spec.rs:195-208`(格式闸)、`hive/src/main.rs:282-298`(存在性闸)、`hive/src/job.rs:63-67`(真源) |
245
+ | **H6-5** | **正对照**:临时池 + 临时桩执行器 + 临时 `hive.exe serve --workers 1`;上游 A(`hold`)先提交,下游 B 经 CLI 提交且 `depends_on=[A]` | 态1(放行文件未创建):A `state='running'` 且 `claimed.lock=True`;B `state='pending'` 且 `claimed.lock=False` ← 依赖未 done 时**未被领取**。态2(放行 → 桩写 `result.json`):A `done`;B `done` 且 `claimed.lock=True`,`B result.content='stub handled …'` ← done 后可领取。临时 serve 已 terminate,全程未碰在役 serve/池 | `hive/src/scheduler.rs:699-738`(`deps_gate`)、`:224-243`(领取循环接线) |
246
+ | **H6-6** | **旁证**:18 个 id 逐一手工对照 python 侧 `_valid_job_id(jid)` vs rust 侧 `spec::validate` 行为观测(`hive.exe submit`,按 stdout 区分三态,并预置 python 侧判合法的 id 目录) | **18/18 逐项一致(`逐项一致 = True`)**:`h1`/`h1_aa`/`habc`/`h_`/`h`/`h1790000000000_beef` 两侧均 True;`Habc`/`x1`/`..`/`../x`/`h/../../x`/`h\..`/(空串)/`h 1`/`h-1`/`h1.a`/`h1/a`/`h∴` 两侧均 False。另:`mcp_server.py` 中 `'_valid_job_id'` 仅 **5 处**出现(`:148` 定义、`:523/:528` `_t_poll`、`:558/:562` `_t_kill`),**依赖路径零调用** | `hive/hive_mcp/mcp_server.py:148-158`、`hive/src/job.rs:63-67` |
247
+ | **H6-7** | **后果闭环**:临时池上 `hm._submit(JOBS, {model:'cmd', user_prompt:'leg7', timeout_s:60, depends_on:['../escape']})` 直接收单,随后起临时 serve(桩执行器)观察终态 | 落盘 spec 含 `depends_on:["../escape"]`;serve 一拍后终态 `state='error'`、`error='依赖不完整: ../escape(非法 job_id,含路径成分)'`,`result.json` 未产出 ⇒ 与 CLI「**提交即拒、不入池**」对照,MCP/程序化通路要多付**一次进池 + 调度**才失败,且失败的是**任务**不是**提交** | `hive/hive_mcp/mcp_server.py:338-366`(收单)→ `hive/src/scheduler.rs:712-714`(兜底拒) |
248
+
249
+ ### 2.2 CH-1(10 条)
250
+
251
+ | 腿 | payload(采集原文摘要) | observed(采集原文摘要) | 站点 |
252
+ |---|---|---|---|
253
+ | **CH1-1** | `grep -n -i "SCORE_MODE\|eval_common\|use_jaccard" scripts/rank_parity.py` | `grep exit=1`,**零命中**(无任何输出);同文件仅 :88/:103/:130 命中单词 `'score'`——那是 docstring 与响应键名 `h.get("score")`,**不是口径开关**。打分口径两处入口:Python 侧 `python_topk` 直接 `cg.search_rrf`;Rust 侧 `Popen([exe, "--root", root, "--serve"])` **不传任何口径入参** | 修前 `scripts/rank_parity.py:87-99`、`:102-113`、`:110` |
254
+ | **CH1-2** | 读两侧缺省值定义 | `md_cg/mdcg.py:500` `SCORE_MODE = os.environ.get("MDCG_SCORE_MODE") or "legacy"`;`rust/src/engine.rs:52` `EngineConfig::default()` 内 `jaccard: true`;`rust/src/main.rs:99` `jaccard: true`。另注 `rust/src/main.rs:13-14` 的自书注释断言「缺省 jaccard,与 Python `mdcg.SCORE_MODE` 缺省一致」——**与事实相反**,这正是长期静默对拍得以持续的掩体 | `md_cg/mdcg.py:500` / `rust/src/engine.rs:52` / `rust/src/main.rs:99`(失实注释 `:13-14`) |
255
+ | **CH1-3** | 状态①缺省态对拍:`python scripts/rank_parity.py --exe rust/target/release/mdcg-eval.exe`(**不设任何** `MDCG_*`;库根由 harness 自身 `tempfile.mkdtemp` 建于 `%TEMP%`) | 输出「语料节点 ~30 · queries=10 · unify=1(默认开)」+ **rc=1**;三条 DIFF:`newuser 探针结论` / `蜂群调度 依赖门禁` / `安全 审计 令牌`。**逐条解剖**:三条 DIFF 的 py/rust **score 多重集逐项相同、id 集合相同**(例:`蜂群调度` py=`[(zh_08,0.016393),(zh_09,0.016129)]` vs rust=`[(zh_09,0.016393),(zh_08,0.016129)]`)——因 RRF 只用路内名次,同分重排即「名次脚手架相同、节点分配不同」,**正是两套词法公式的指纹**。共跑 3 次,数字与 DIFF 集合逐次相同。与契约数字逐字一致 | `scripts/rank_parity.py:204-226`(判定与退出码) |
256
+ | **CH1-4** | 状态③:`MDCG_SCORE_MODE=jaccard python scripts/rank_parity.py --exe ...`(该变量只影响 Python 侧:实测 `rust/src/*.rs` 无任何 `MDCG_SCORE_MODE` 读取面,grep 零命中) | rc=0,**无 DIFF**,`10/10 · 10/10 · 10/10`;3 次重复一致。另测 2c(显式 `MDCG_SCORE_MODE=legacy`)得到与状态①**完全相同**的 `7/10·10/10·7/10` 与**同三条** DIFF ⇒ 反向确认 Python 侧缺省确为 `legacy`、harness 确实在吃缺省 | `scripts/rank_parity.py:204-226` |
257
+ | **CH1-5** | 状态②(两侧同关归一层 `MDCG_UNIFY_QUERY=0`)对拍 | **契约记述不成立**:契约称「同样三条 DIFF 逐位重复」,**实测 rc=1、逐位 `6/10` · 集合 `9/10` · top-1 `6/10`;DIFF 四条**——前三条与状态①逐位重复,**第四条 `memory recall pipeline` 为状态①所无,且集合层也不同**:py=`[(en_01,.016393),(en_08,.016129),(en_11,.015873),(en_00,.015625),(en_03,.015385)]` vs rust=`[(en_08,.016393),(en_01,.016129),(en_11,.015873),(en_00,.015625),(en_10,.015385)]`。三次重复跑稳定。为排除「是 batch1(`4b0b3294`,rust 三文件大幅改动)引入」,用 `git archive` 把父提交 `f75a343e` 整棵树导出到 `%TEMP%`(只读,未写仓库)、以临时 `CARGO_TARGET_DIR` 重建 release 二进制(零第三方依赖,build rc=0)、再用那份 harness(与 HEAD **逐字节相同**,已比对)复跑三态,得**完全相同**的 `7/10·10/10·7/10`、`6/10·9/10·6/10`、`10/10·10/10·10/10` ⇒ **差异与 batch1 无关,契约该条的记述本身不准确** | `scripts/rank_parity.py:204-226`(对比脚本) |
258
+ | **CH1-6** | 状态②的第 4 条 DIFF 是否同因:`MDCG_UNIFY_QUERY=0 MDCG_SCORE_MODE=jaccard python scripts/rank_parity.py ...`(两侧同口径) | rc=0;`10/10 · 10/10 · 10/10`,**零 DIFF** ⇒ 关掉归一层后的**全部 4 条** DIFF(含那条**集合层**差异)在**只对齐打分口径**后全部消失。故 CH-1 的根因「harness 口径漏接线」是**充分的**,无需引入 `strip_tense` / entity tags 解释 | `scripts/rank_parity.py:204-226` |
259
+ | **CH1-7** | **Rust `--serve` 已接受并生效显式 `--score`(契约③的前提不成立)**:同一临时库上对同一二进制跑 `--root <lib> --serve`(缺省)与 `--root <lib> --serve --score legacy`,并按 `MDCG_SCORE_MODE` 两态取 Python 答案对照;query=`newuser 探针结论` | `rust --serve` **缺省**=`[en_07,.016393 \| en_09,.016129 \| en_03,.015873 \| en_13,.015625 \| en_08,.015385]`,与 Python 在 `MDCG_SCORE_MODE=jaccard` 下**逐位相同**;`rust --serve --score legacy`=`[en_03,.016393 \| en_07,.016129 \| en_09,.015873 \| en_13,.015625 \| en_08,.015385]`,与 Python 缺省(legacy) **逐位相同**。即 serve 链路已把 `--score` 透传为 `EngineConfig.jaccard`(`main.rs:154` 解析 → `:760`;`engine.rs:124/163/247` 使用)⇒ 契约③「若 serve 无法接受显式口径入参…让 serve 也接受」的前提**不成立**:**Rust 侧一行都不用改**,只需在 `rank_parity.py:110` 的 argv 加 `--score jaccard` | `rust/src/main.rs:154`、`:756-764` |
260
+ | **CH1-8** | eval 面既定单点确认(但「**全部** bench 脚本都调它」不精确):`python` 统计 `md_cg/bench*.py` 对 `use_jaccard` 的引用 | **23 个 `bench*.py` 中 8 个**直调 `use_jaccard()`;`bench_lme_zh.py:361/371` 直接置 `m.SCORE_MODE`;`bench_locomo.py:72` 明确注明「**不切 jaccard**」。故契约括注「全部 bench 脚本都调它」为**不精确表述**,但操作性主结论成立:评测面确有既定单点 `md_cg/eval_common.py::use_jaccard()`(`:79-96`),harness 应走它而非新写第二套开关 | `md_cg/eval_common.py:79-96` |
261
+ | **CH1-9** | 零仓库写入 / 未动在役数据根 / 库根全在系统临时目录:对仓内 15530 个文件(排除 `.git`、`node_modules`)做 `(size, mtime_ns)` 指纹前后比对;`git status`;`rust/target` 二进制 mtime 核对 | 三次 harness 对拍前后指纹 `changed=0`;活动结束后 `git status --porcelain` **仍只有会话开始即存在的 `?? .zcode/`**;`rust/target/release/mdcg-eval.exe` mtime 保持 `2026-09-29 14:01:14` 未被改写(⇒ 三态实验用的就是 HEAD 的二进制)。父树探针的 `cargo build` 走临时 `CARGO_TARGET_DIR`,`git archive -o` 输出到 `%TEMP%`。所有实验库根来自 `tempfile.mkdtemp`。**未触碰** `D:/program/AEIS`、hive 在役 jobs 池、`data/policy.json`;全程未 `git add/commit/push`;未编辑工作区任何文件 | n/a(跨切面核验) |
262
+ | **CH1-10** ⚠ `reproduced=false` | 契约验证项「新建守卫 `md_cg/test_rank_parity_score_mode.py` 并跑 ①②③」**无法执行**:`ls md_cg/test_rank_parity_score_mode.py` | `No such file or directory` ——守卫是**本次修复的产物**而非现状,且该任务硬边界禁止编辑工作区,故采集方**未执行任何断言**。替代做法(采集原文自标为**替代**):直接以真实 harness 跑三态对拍,并额外机械验证了守卫①③所依赖的两个事实——缺省态**并非** 10/10/10(`7/10/10/7`,rc=1)与两侧同口径为 `10/10/10` rc=0。守卫的「锚点漂移报 ANCHOR-MISS 退出码 2」「SKIP 不计通过」两项当时**未运行**,无从判定 | `md_cg/`(当时**无**该文件) |
263
+
264
+ > `CH1-10` 的 `reproduced=false` 是**采集面的如实标注**,不是缺陷不成立。本报告 §4.1 已在**修后**树上实跑该守卫,其 ANCHOR-MISS / SKIP 两项由 §5.2 复核条目补齐。
265
+
266
+ > **被本报告判决的两条契约原文(本版整段引出,回应读者「被判决的原文在报告里没有引出,读者无从对照」)**——两处均出自同一份 `CONTRACT_CH1`,即 `.zcode/workflow-drafts/优化第二批-H6依赖透传-CH1对拍口径-C3负缓存.dwf.ts` 的 `:42-66`:
267
+ >
268
+ > - **`CH1-5` 所判的那句**(草稿 `:48`):「(2) 两侧同关归一层(`MDCG_UNIFY_QUERY=0`):**同样三条 DIFF 逐位重复**(分数多重集逐项相同、只是分配给不同节点);」——本报告 `CH1-5` 实测其在**改动前的树上不成立**(实为 **4 条** DIFF、读数 **6/10 · 9/10 · 6/10**,且第 4 条 `memory recall pipeline` 在**集合层**也不同)。
269
+ > - **`CH1-10` 所判的那句**(草稿 `:60`):「验证:**新建守卫 `md_cg/test_rank_parity_score_mode.py`** ——」+紧随的 `:61`「① 在临时库上跑一次 harness 的等价对拍,断言缺省态即 10/10/10 且退出码 0;」/`:62`「② 人为把两侧口径拨不一致(例如只给 Python 侧设 `MDCG_SCORE_MODE=legacy`),断言 harness 非 0 退出并报出口径不一致,而不是静默给出低分;」/`:63`「③ 定点变异自证:把口径钉住的那行去掉,第 ① 项必须转红;锚点漂移报 ANCHOR-MISS 且退出码 2,禁止以 git HEAD 为基线源。」——本报告 `CH1-10` 判其在**改动前的树上**无法执行:该文件当时**不存在**(它是本次修复的产物)。
270
+
271
+ ### 2.3 C-3(12 条)
272
+
273
+ | 腿 | payload(采集原文摘要) | observed(采集原文摘要) | 站点 |
274
+ |---|---|---|---|
275
+ | **C3-1** | 临时库 `MdCGSecure(knowledge/orphan/m1.md, 正文含唯一令牌 alpacauniquek3)` + 默认读缓存,冷缓存下 `kernel32.CreateFileW(path, GENERIC_RW, dwShareMode=0)` **独占**持住节点 md;同刻 `open()` 实测抛 `PermissionError errno=13`(瞬态) | 命令 `python -X utf8 %TEMP%\c3_repro\repro_c3.py`(EXIT=0)。对照面无注入 `search('alpacauniquek3 苹果')=['m1']`;**持锁期冷缓存** search 同一查询 → **m1 缺席**(返回 `['m2']`);该次查询真读盘 2 次 | 修前 `md_cg/mdcg.py:2609-2618`(`_read`:`:2613` ValueError 越界→`(None,None)`、`:2617-2618` `except OSError`→`(None,None)`);调用面 `md_cg/mdcg.py:3252-3257`(`_read_many`:`c is None → continue`) |
276
+ | **C3-2** | 负结果以「**新鲜**」身份固化:取证方式 = 直接 `repr` 打印 `cg._read_cache[entry['path']]`(缓存键 = `entry['path']` = `'knowledge/orphan/m1.md'`,**非绝对路径**) | `repr(cg._read_cache['knowledge/orphan/m1.md']) = (7, (None, None))`;`gen=7` (int)、`val=(None, None)` (tuple)、`val == (None,None) -> True`;整缓存字典**两个键**,其中负结果条目数 = **1** | 修前 `md_cg/readcache.py:102-110`(`_cached`:`:108` `val = orig(entry)`;`:109` `cache[p] = (gen, val)` —— **对任何 val 无条件入缓存**);新鲜度判据 `:80-100`(`_fresh`)不区分 val 语义 |
277
+ | **C3-3** | 释放句柄后仍 miss:`CloseHandle` 释放独占句柄后,普通 `open(path)` **成功读 514 字节**(盘面已恢复),随即连续 2 次 search 同一查询 | 释放后 `hits = ['m2'] / ['m2']`(**m1 仍缺席**);释放后真读盘次数 = **0**(缓存判定新鲜,根本不再触盘);缓存条目仍 = `(7, (None, None))`。持锁期再连查 2 次亦为 `['m2']` 且真读盘 0 次 | 修前 `md_cg/readcache.py:106-107`(hit 且 `_fresh` → 直接返回 `hit[1]`,**不重试**) |
278
+ | **C3-4** | **决定性取证**:同一 entry、同一瞬间,穿透缓存的真读成功 vs 走缓存返回负结果——连调 `cg._read_uncached(e1)`(readcache 钉住的真原始 `_read`)与 `cg._read(e1)`(缓存包装层) | `cg._read_uncached(entry) = ('m1'…, 'alpacauniquek3'…)`(**真读到盘面内容**);`cg._read(entry) = (None, None)`(走缓存仍是固化负结果)⇒ **固化发生在缓存层,不在盘面** | 修前 `md_cg/readcache.py:74-76`(install 把 `_read_uncached` 钉为未被包装的原始 `_read`);`:102-110` |
279
+ | **C3-5** | **撕裂**:固化成立后,对同一节点调用 `cg.get('m1')` | `cg.get('m1') = {'id':'m1','importance':0.5,'content[:12]':'alpacaunique'}`(**非 None,可读**);**同一瞬间** `search('alpacauniquek3 苹果')` 仍**不返回** m1。get 走裸 open **不入缓存** | 修前 `md_cg/mdcg.py:2593-2606`(`get` 裸 `open` + `nodefile.loads`,`except OSError → None`)vs `md_cg/mdcg.py:2609-2618` + `md_cg/readcache.py:102-110`(search 经 `_read_many`→`_read`→缓存) |
280
+ | **C3-6** | **因果对照**:同一注入在「不装读缓存」下可自愈 ⇒ 固化由**缓存层**造成。同一注入 × 三种缓存配置,冷缓存 → 持锁连查 3 次 → 释放 → 连查 2 次:(a) `MDCG_READ_CACHE=0`;(b) 默认态;(c) 默认态 + 单点判据「读失败不入缓存」 | `nocache -> after_unlock_hits [['m1'],['m1']]`、`real_disk_reads_after_unlock 4`、无缓存面;`shipped -> [['m2'],['m2']]`、`real_disk_reads_after_unlock 0`、`cache_entry_after_unlock '(7, (None, None))'`;`variant -> [['m1'],['m1']]`、`real_disk_reads_after_unlock 1`、负结果条目 **0**。(b) 与 (a)(c) 唯一差别就是读缓存层 ⇒ **固化归因锁定在 `readcache`** | 修前 `md_cg/readcache.py:102-110`;默认装配点 `md_cg/mdcos.py:377-379`(`if _rc.enabled(): _rc.install(self)`) |
281
+ | **C3-7** | **定点变异自证**:变体 = 只在缓存包装外插一行判据(`val == (None, None)` 时 `cache.pop(entry['path'])`),**不改** `_fresh`/代际语义、**不改** `_read` 返回值契约。注意极性:**shipped 代码本身就是「判据关掉」态** | ① 判定 = 持锁期 miss 且释放后命中。(判据关 = shipped)释放后 `hits [['m2'],['m2']]` → **①红(缺口成立)**;(判据开 = variant)`[['m1'],['m1']]` → **①绿**。两种极性实测都拿到,说明该断言对「负结果不入缓存」这一点**有判别力** | 修前 `md_cg/readcache.py:108-109`(判据缺失处) |
282
+ | **C3-8** | **失败不可发现(静默)**:持锁期 search 全程 `redirect_stderr` 捕获;并盘点 `readcache` / `mdcg` 模块级与 `cg` 实例上的记账面名字 | `stderr_during_lock = ''`(**空串,零告警**)。`readcache` 模块级名字 = `['clear','direct_read','enabled','install','os']` → 疑似读失败记账面 **[]**;`mdcg` 模块级 **[]**;`cg` 实例 **[]**。对照 N225 风格的既有记账面确实存在:`fsutil.NONOBJECT_ROW_SKIPS` / `BAD_PAYLOAD_ROW_SKIPS` / `BAD_SORTKEY_ROW_SKIPS` + 各自 `*_SAMPLES` + `_NONOBJECT_SAMPLE_CAP=32` + `*_row_stats()` reader ⇒ **契约③要求的记账面当前完全不存在** | 修前 `md_cg/readcache.py`(全文 129 行,无计数器/样本/reader);对照 `md_cg/fsutil.py:286-292`、`:327-356` |
283
+ | **C3-9** | **失效条件与隔离面**:固化成立后依次 `cg.add('m2', …)+flush`、`cg.add('m1', …)+flush`;另有独立对照 `readcache.clear(cg)+search` | 写 m2 后 `search(Q1) = ['m2']`(**m1 仍缺席**,脏集**按 path 精确失效**,不累及他节点);再写 m1 后 `search(Q1) = ['m1']`(恢复)。`clear(cg)` 返回 1 且随后 `search = ['m1']`。另观察:持锁期**邻居 m2 命中正常**(固化按 path 隔离)⇒「永久消失直至重启/再写盘」成立 | 修前 `md_cg/readcache.py:80-100`(`_fresh` 按 `path_gen`/`broad_gen` 判新鲜);`:clear` |
284
+ | **C3-10** | **重试代价数据(供修复选型论证)**:同一注入下统计「真读盘次数」(计数点落在 `_read_uncached` 之下的真原始读):持锁窗口 3 次查询 + 释放后 2 次查询 | 持锁窗口真读盘:`nocache 6`(3 查询 × 2 节点)、`shipped 2`(后续查询被负缓存喂饱)、`variant 4`(m1 每次重试);释放后:`nocache 4`、`shipped 0`、`variant 1` ⇒「不入缓存」路线在故障窗口内确为**每查询重试**(**有限窗口内**),**不是永久性能悬崖** | 修前 `md_cg/readcache.py:108`(`orig(entry)` 调用点即重试点) |
285
+ | **C3-11** | **既有 chaos 用例在未改动树上维持 `EXPECTED_GAP` 一致**(Windows 实测;非 Windows 分支为 SKIP→gap):直跑既有用例;另把 `os.name` 临时改成 `'posix'` 后在已导入模块上调用其 `main()`,机械确认非 Windows 分支**不伪装 pass** | `python -X utf8 test/chaos_injection/test_fi_m02_transient_read_negative_cache.py` → 全部 8 项 check OK,末行 `CASE_RESULT {"case_id":"FI-M02","verdict":"gap","expected":"gap","consistent":true}`,rc=0。`os.name` 改 `'posix'` 后 `main()` → NOTE 非 Windows 平台…维持 gap 基线,`verdict gap / consistent true`,返回 0。**声明**:后者是本机 Python 上对 `os.name` 打桩的**分支模拟**,不是真实 Linux 运行(容器栈一未接触) | `test/chaos_injection/test_fi_m02_transient_read_negative_cache.py:32-37`(非 nt → `case.finish("gap","gap")`);登记见 `test/chaos_injection/registry.py:66-67` |
286
+ | **C3-12** | **复现面合规**:不动在役数据根 / 不编辑工作区:全部实验库根由 `tempfile.mkdtemp` 生成;核对 git 工作树与 `MDCG_*` 解析结果 | `git status --porcelain` → `'?? .zcode/'`(会话开始快照即如此,**无新增改动**);`HEAD = 4b0b3294310aaf1b90ae25c481fefd6d8298c066`;`mdcg_root`/`data_root`/`state_dir`/`aux_root`/`state_root` 与 `MDCG_ROOT`/`DATA_ROOT`/`AUX_ROOT`/`STATE_ROOT`/`TOKEN_FILE`/`SUSTAIN_DIR` 全部 `under_temp=True`。未 `git add/commit/push`,未改 `data/policy.json`,未动 `D:/program/AEIS` 与 hive 在役池,未重建/重启在役 serve | `test/chaos_injection/mdcg_support.py:20-36`(`apply_env` 全部 `MDCG_*` 钉到临时目录) |
287
+
288
+ ---
289
+
290
+ ## 3. 修法契约与落点
291
+
292
+ 修法口径有界,按性质分三类:**接线**(把已有机制接上唯一判据)、**新建记账面**(C-3,与既有坏行记账同风格)、**新暴露面**(Rust `serve info.score`,加字段向后兼容)。**未新增任何第二套判据**。
293
+
294
+ ### 3.1 H-6:两闸接进 MCP 面与编排面(接线)
295
+
296
+ **契约(原样要点,出处=`.zcode/workflow-drafts/优化第二批-H6依赖透传-CH1对拍口径-C3负缓存.dwf.ts` 的 `CONTRACT_H6`,`:15-40`)**:① MCP 工具面接受并写入 `depends_on`;② 写入前过与 CLI **同判据**的两道闸(格式 + 存在性),不满足即 fail-closed,**不得静默忽略、不得静默降级为「无依赖」**;③ `orch._spawn` 子 spec 白名单透传;④ **判据不得分叉出第二套实现**,守卫里用两侧对照钉住;⑤ 同步「生效条件」注释与工具 schema/文档。
297
+
298
+ **落点(工作区口径,本报告读码所见)**:
299
+
300
+ - **判据单点**:`hive/hive_mcp/mcp_server.py:171-196` `_dep_gate(jobs, deps)`——`:192` 格式闸复用 `_valid_job_id`(`:152-162`),`:194` 存在性闸 `os.path.isdir(os.path.join(jobs, d))`;**文案与 CLI 逐字对齐**(与 `spec.rs:204-206`、`main.rs:292-294` 同款串)。
301
+ - **MCP 面调用点**:`hive/hive_mcp/mcp_server.py:522`——位置在 **`:525 _ensure_serve` 之前**、**spec 组装(`:526`)之前**;`:523-524` 不过闸即返回 `{"ok": False, "error": dep_err}`。⇒ **不写 spec、不拉 serve、不静默忽略、不降级**。
302
+ - **落盘**:`:553-556`——过闸后 `spec["depends_on"] = list(a["depends_on"])`,**原样保序不裁剪**;显式 `[]` 也落键(= 提交方声明无依赖)。
303
+ - **白名单**:`:490-495` `SPAWN_ALLOWED_KEYS` 收下 `"depends_on"`(第 **16** 键),注释 `:488-489` 说明它是**调度语义**键、过两闸即写。schema 同步:`:716` 「16 个参数」、`:739-747` `properties.depends_on`。
304
+ - **编排面**:`hive/orch.py:141-149`(`_spawn_schema` 增 `depends_on`);`:518-519`(子 spec 白名单键补 `depends_on`,沿用 `:520` 的 `not in (None, "", [], {})` 显式传值优先纪律);`:549-551`(**同闸**:调**同一个** `_hm._dep_gate`,不过即 `{"ok": False, "error": ...}`);`:552` 才提交。
305
+ - **注释/docstring/文档同步**:`mcp_server.py:165-170`(`_dep_gate` 生效条件)、`:498`(`_t_spawn` 生效条件补依赖门禁分支)、`:151`/`:157`(`_valid_job_id` docstring 把 `_dep_gate` 列入「拼路径前必过此闸的入口」)、`:15-16`(模块头);`orch.py:476`(`_spawn` 生效条件)、`:482-484`(护栏清单);`hive/README.md:153`、`:277`、`:282`、`:461`。
306
+ - **Rust 侧零改动**(`hive/src/` 在 `git status` 中**无条目**):`spec.rs` / `main.rs` / `job.rs` / `scheduler.rs` 一字未动——契约「不许动什么」逐条满足(§4.4)。
307
+
308
+ **【与契约的两处偏离·如实报告】**(采集原文)
309
+
310
+ 1. **契约③只要求 orch 透传,实施方额外在 orch 面加了同一道闸**(`:549-551`)——理由是子任务 `depends_on` 是**模型可控**的 function calling 参数,静默透传坏值等于把缺陷换个门;判据仍**单点** `_hm._dep_gate`,**未分叉第二套**。
311
+ 2. **非列表形态**(裸字符串 `"h1_a"`)在 MCP 面**拒**(`:186-190`),而 CLI 的 `as_str_vec` 会宽松采信为单元素列表——**有意更严**(工具 schema 声明的是 `array`),已在 `:187-188` 就地声明。故守卫 D 组对照只覆盖**数组形态**,数组外形态差异在 G 组单独钉住。**「CLI 宽松采信」的出处(本版补,回应读者「该定性唯一依据无 `path:line`」)**:`hive/src/json.rs:63-81`——`:65` 不适用条件自书「不做类型校验(**宽松取值**,如 `depends_on`/`as_str_vec` 的容错读取)」,`:78-79` 实现为 `Json::Null => Vec::new()` / `other => vec![other.as_str()...]`(**非数组 → 单元素**)。**仍未有的证据(如实标注)**:该行为**没有专门的采集腿**——`H6-4` 的四组 CLI 载荷全是数组形态(`['../escape']` / `['x1']` / …),故「CLI 对裸字符串确实 accept」这一具体行为,本报告只给到**源码定义级**证据(`json.rs` 的生效条件+实现),**未做端到端实测**。
312
+
313
+ 另:**`_submit` 保持「哑写入者」未加校验**(其 docstring `:375` 的「不做校验」契约未动)——闸落在**两个构建 spec 的入口**(`_t_spawn` / `orch._spawn`),不在 `_submit` 内。**若契约本意是闸在 `_submit` 内,请明示**(采集原文提出,本报告照录,不代裁)。
314
+
315
+ **【事故与处置·采集原文如实报告】**(本报告照录,**不代为淡化**)
316
+
317
+ > `hive/` 首版守卫的 `_patch` 曾把变异源码 `exec` 进 `vars(mod)` 的**快照副本**,变异函数的 globals 看不见 `mock.patch.object` ⇒ 首轮 `--branch-baseline` 的 2 个变异轮把 **9 条 job(`model=guard-model`,state 全 `error`)写进了在役池 `hive/jobs`** 并被在役 serve 领取执行(真 API 调用失败,**未产生成功产物**)。已按 `model==guard-model` + 终态白名单逐条核验属实后 `rmtree` 删除那 9 个目录(在役池恢复为原有目录数,前后计数一致);根因已修(`_patch` 改 `exec` 进模块 `__dict__`,globals 为活命名空间)+ 新增 `_assert_isolated` 隔离自检(冻结引用解析出的池不是本次临时池即抛错判红,实测可触发),修改后两轮变异全跑在临时池上、**在役池计数零变化**。
318
+
319
+ **本报告对该事故的独立核对**:本报告在跑 H-6 守卫**之前与之后**各一次快照在役池(`hive/jobs`):两次均为 **17 个条目**(15 个 `h*` 任务目录 + `_serve.json` + `_serve.log`),**逐条同名同序**(§4.4)。⇒ 本轮运行**未**复现该泄漏形态。**本版另补**:逐目录读 `spec.json`,15 个任务目录的 `model` 全部为 `deepseek-flash`,**`guard-model` 残留 0 条**(§4.4 末两行)。**边界(如实)**:这只核到「**现在没有残留**」,核不到「当时删了几个、是否删净」——那属历史动作,本报告**无从核**。
320
+
321
+ **【未动】**(采集原文):`scheduler.rs::deps_gate` 领取语义、CLI 侧行为、`job_id` 格式/前缀排序(H-1)、`content_hash` 去重(H-1)、任何其它 spec 校验、`data/policy.json`、forbidden 规则。
322
+
323
+ ### 3.2 CH-1:口径收单点 + 两侧显式钉住 + 回读对照(接线)
324
+
325
+ **契约(原样要点,出处=同一草稿的 `CONTRACT_CH1`,`:42-66`)**:① 两侧口径由**单点**显式钉住,不得各自吃缺省(Python 走**既有** `eval_common.use_jaccard()`,**禁止新写第二套开关**;Rust 侧显式传参,不依赖 `Config::default()`);② **漂移必须变响**(同一次运行读出两侧实际口径并对照,不一致即非 0 退出并打印两侧口径与修复提示);③ 若 `--serve` 无法接受显式口径入参,最小改动是让 serve 也接受(缺省不变);④ 顶部用法注释写明本 harness 缺省口径。**契约③的原文**(草稿 `:55-56`):「③ 若 Rust 侧 `--serve` 目前无法接受显式打分口径入参(只有 CLI 的 `--score`),允许的最小改动是让 serve 也接受同一入参,缺省值不变(向后兼容),并把「两侧缺省值不同」这一事实在 harness 里显式化;」
326
+
327
+ **落点**:
328
+
329
+ - **单点常量**:`scripts/rank_parity.py:67` `SCORE_MODE = "jaccard"`;`:72-73` `_PY_DEFAULT = "legacy"` / `_RUST_DEFAULT = "jaccard"` 把「两侧缺省不同」**显式化**。
330
+ - **Python 侧钉住 + 读回**:`:152-177`——`:165` `from md_cg import eval_common`;`:173-174` `eval_common.use_jaccard()`(**既有单点,未新写开关**);`:177` 返回 `mdcg.SCORE_MODE` 实际值;`:169-172` env 声明冲突时**返回冲突**(不静默覆盖 / 不静默照吃)。
331
+ - **Rust 侧显式入参 + 回读**:`:213-234` `rust_open` 的 argv `:225` 显式 `--score <SCORE_MODE>`;`:191-210` `rust_reported_score` 发 `{"op":"info"}` 并读 `:207` `resp.get("score")`,读不到即 `RuntimeError`(fail-closed)。
332
+ - **main 接线**:`:288` 钉 Python → `:291` 单点坏掉 rc=3;`:332` 拉起 + 回读 → `:337` **rc=4**(回读失败);`:340-356` **漂移闸 rc=3**(且**不给逐位读数**);`:358-360` 头部自描述。
333
+ - **`--ab` 亦按钉住口径**:`:310-312`(行为变更:`off` 侧 `beef noodles lunch` 由 `ds_en_02` 变 `ds_en_03`,条数仍 5/10)——但 `:321` 的 `return 0` **先于** `:340` 的对照闸,见 §6.2。
334
+ - **Rust 侧新增(不改变排序)**:`engine.rs:65-68` `score_label` 标签映射单点;`:169-170` `SearchEngine::jaccard()` 回读访问器;`serve.rs:65-79` `info` 新增 `score` 字段(**加字段,向后兼容**)+ `:15-21` 协议 docstring;`main.rs:182-183` `score_label` 转调单点、`:204-209` `--serve` 亦接受 `--score` 说明 + 两侧缺省不同提示、`:776-782` 就绪行自报 `score=`。
335
+ - **产品缺省与检索算法零改动**(复核反查 `git diff` 确认):`md_cg/mdcg.py:499-500` 仍 `legacy`;`rust/src/engine.rs:52` 与 `rust/src/main.rs:99` 仍 `jaccard: true`;`md_cg/eval_common.py:96` 仍 `m.SCORE_MODE = "jaccard"`;`md_cg/mdcos.py`(`search_rrf` 所在)**未列入改动**;`git diff | grep -E 'strip_tense|entity'` **无命中**。
336
+
337
+ > **契约③的前提不成立**(`CH1-7` 实测):`--serve` **早已**接受并生效显式 `--score`(`main.rs:154` 解析与评测 CLI 共用同一入参)⇒ **Rust 侧一行都不用改**,本批对 Rust 的改动**全部是新增回读/自描述面**,不含口径传递逻辑。
338
+
339
+ ### 3.3 C-3:读路径三态单点判别 + 读失败不入缓存 + 可观测记账(接线 + 新建记账面)
340
+
341
+ **契约(原样要点,出处=同一草稿的 `CONTRACT_C3`,`:68-89`)**:① 区分「瞬时读失败」与「不存在/无密钥」,**区分点必须单点**,不得在缓存层再猜一遍;② 读失败结果**不得以「新鲜」身份固化**(不入缓存,或带标记与失效条件——须论证为何不会退化成「每次查询都重试」的性能悬崖);③ **不得静默**:要有可观测记账(模块级计数 + 有界样本),且该记账面**可被守卫读取**;④ 成功路径对外返回值语义**逐位不变**,须有**独立 oracle** 对照证明。
342
+
343
+ **落点**:
344
+
345
+ - **判别真源单点**:`md_cg/fsutil.py:443-450` `classify_read_failure`——`:448` 仅 `FileNotFoundError` 判**终态**(`READ_FAIL_ABSENT`),其余**一律瞬时**(`READ_FAIL_TRANSIENT`)。填充「失败判据的**第二份副本**」的风险由缓存层**不看异常类型**来消除(见下)。
346
+ - **记账面**:`md_cg/fsutil.py:454-473`(计数 + 有界样本 `cap=32` + stderr 限流 `cap=32`);`:477-479` `transient_read_stats()`(守卫/运维可读);`:483-487` `reset_transient_read_stats()`(建观测基线用)。**与 N225 三类坏行记账同模块、同风格、并存**(守卫 G5g 钉住)。
347
+ - **记账调用面单点**:`md_cg/mdcg.py:2612-2623` `_note_read_oserror`(`@staticmethod`)——`:2620` 是全文件**唯一**调用 `classify_read_failure` 的地方。
348
+ - **三态单点**:`md_cg/mdcg.py:2625-2644` `_read_status(entry) -> (fm, content, fail)`——`:2636-2637` ValueError(越界)→ 终态;`:2639-2640` 成功 → `(..., None)`;`:2641-2644` `except OSError` 经 `_note_read_oserror` 分流。`:2629-2632` docstring 明写「第三元素是读失败标签的**唯一来源**,缓存层据此拒绝接纳,自身不重新判别」。
349
+ - **对外面收缩**:`md_cg/mdcg.py:2646-2648` `_read` 收缩为 `self._read_status(entry)[:2]`——**返回形状/语义与改前逐位一致**,包内既有调用点零改动。
350
+ - **`get()` 不再静默**:`md_cg/mdcg.py:2601-2606`(`:2605` 记账,`:2606` 仍 `None`——公开语义不变;`get` 本就**不入任何缓存**,本处无固化面)。
351
+ - **缓存接纳**:`md_cg/readcache.py:139-151` `_cached_status`——`:143-145` 命中时补回 `(None,)` 标签(**存储面恒为二态**,故缓存条目形状不变);**`:147-149` 瞬时读失败一律不入缓存**;`:150` 才写 `(gen, (fm, content))`。`:154-169` 无 `_read_status` 载体的**保守回落分支**(空结果不接纳)。
352
+ - **未动**:`_fresh` / `write_gen` / `broad_gen` **逐字未动**(`readcache.py:106-126`);`nodefile.loads` / `read_jsonl` / `_open_content` 契约未动(契约明列「不许动」)。
353
+ - **用例登记**:`test/chaos_injection/registry.py:74-75` FI-M02 `gap → pass`(`:64-73` 结案留痕,并注明定点变异守卫位置);`test/chaos_injection/test_fi_m02_transient_read_negative_cache.py:110-149` 判据由 `EXPECTED_GAP` 改为修复后判据(持锁期 miss / 负结果不入缓存 / 释放即首次命中 / get 同批可见 / 记账可观测 + 恢复面 + **四可**);非 Windows 照 FI-R09 约定 **SKIP 并报登记基线**(`:47-55`)。**其中「四可」指 可发现/可隔离/可恢复/可追溯**——C-3 修复把 **可发现** 由改前的「否」翻为「是」(改前取值「否·是·是·是」见 `docs/eval/故障注入实测_v1.0.md:26`,定义见 §0.1)。
354
+
355
+ **选型论证(采集原文)**:选「**不入缓存**」而非「带标记入缓存」——后者必须新增 **TTL / 代际时间窗**,等于给失效判据开**第二维**(违反单点,且 TTL 窗内仍保留同型撕裂);不入缓存则**瞬态窗口为零**(FI-M02 实测释放即命中)。性能面**无悬崖**:稳态一次查询只有失败的那 **1 个 path** 恰 1 次 `open`、成功节点 **0 次**(守卫 G1e 以模块级 open 闸门计数),且真缺 `FileNotFoundError` **仍照旧入缓存**故缺文件节点不会每查询重试(守卫 G1i)。
356
+
357
+ ---
358
+
359
+ ## 4. 验证数字
360
+
361
+ ### 4.1 本报告实跑(2026-09-29,工作目录 `<repo>`,`python -X utf8`)
362
+
363
+ | # | 命令(原样) | 尾部数字 | 退出码 |
364
+ |---|---|---|---|
365
+ | 1 | `python -X utf8 -m hive.test_h6_mcp_depends_on` | `H-6 依赖门禁守卫(MCP 面 / orch 面):43 通过,0 失败` | `0` |
366
+ | 2 | `python -X utf8 -m hive.test_h6_mcp_depends_on --branch-baseline` | 未变异基线`失败=0`;**6 处变异逐处恰好命中预期**:`A:4` / `{B:10, D:14, E:1}=25` / `{C:2, D:4, E2:1}=7` / `{G:1}=1` / `{A:4, F:1, I:1}=6` / `{H:1}=1`;`定点变异自证:PASS` | `0` |
367
+ | 3 | `python -X utf8 -m md_cg.test_rank_parity_score_mode` | `CH-1 守卫(rank_parity 两侧口径接线):40 通过,0 失败,0 跳过` | `0` |
368
+ | 4 | `python -X utf8 -m md_cg.test_rank_parity_score_mode --mutate` | 未变异基线`失败=0`;变异1「撤 Python 侧 `use_jaccard`」**红项=10 预期=10**;变异2「撤两侧口径对照闸」**红项=6 预期=6**;`定点变异自证:PASS` | `0` |
369
+ | 5 | `python -X utf8 -m md_cg.test_c3_transient_read_negative` | `C-3 守卫(瞬态读失败不得固化):43 通过,0 失败,0 跳过` | `0` |
370
+ | 6 | `python -X utf8 -m md_cg.test_c3_transient_read_negative --mutate` | 未变异基线`失败=0`;`C-3a` 红项=**8 预期=8**;`C-3b` 红项=**9 预期=9**;`定点变异自证:PASS` | `0` |
371
+ | 7 | `python -X utf8 scripts/run_tests.py`(**全量**) | `===== SUMMARY 262/262 通过,5 跳过(依赖缺失/平台不符) =====`(含 `PASS hive.test_h6_mcp_depends_on`、`PASS hive.test_exec_tools`) | `0` |
372
+ | 8 | `python -X utf8 scripts/rank_parity.py --exe rust/target/release/mdcg-eval.exe` | 头部 `score=jaccard=rust jaccard(两侧显式钉住)`;`逐位一致 10/10 · 集合一致 10/10 · top-1 一致 10/10`;**无 `[DIFF]` 行** | `0` |
373
+ | 9 | `MDCG_UNIFY_QUERY=0 python -X utf8 scripts/rank_parity.py --exe ...` | 头部 `unify=0 · score=jaccard=rust jaccard`;`10/10 · 10/10 · 10/10` | `0` |
374
+ | 10 | `MDCG_SCORE_MODE=legacy python -X utf8 scripts/rank_parity.py --exe ...` | `!! 词法打分口径不一致:两侧不在同一套公式上,拒绝静默对拍`;`python 侧实际口径 = legacy(env MDCG_SCORE_MODE=legacy 与 harness 钉住的口径 jaccard 冲突);harness 钉住口径 = jaccard`;`rust 侧实际口径 = jaccard`;**且无逐位读数行** | `3` |
375
+
376
+ **守卫断言的构成(与实跑输出逐条一致)**——**每个标签(`A1`、`G1b-1`、`G3m`、`E2`…)对应的断言原文,逐条列在 §附A「断言标签 → 断言文本对照」**(本版新增,回应读者「红项读数只给标签、没有标签到断言的对照」):
377
+
378
+ - **H-6 `43`**:A 组(真实 serve 端到端)**4** · B 组(格式闸拒面)**10** · C 组(存在性闸拒面)**2** · D 组(rust/python 逐项对照)**21** · E1/E2(拦截后池中不新增目录)**1+1** · F1(缺省不写)**1** · G1(非列表被拒)**1** · H1(orch 透传)**1** · I1(orch 缺省不写)**1** ⇒ **43**。
379
+ - **CH-1 `40`**:G0(隔离与前置自证)**3** · G1(缺省态对拍)**7** · G1b(完全缺省调用)**3** · G2(漂移变响)**7** · G3(结构面含负向锚点)**16** · G4(过期二进制 fail-closed)**4** ⇒ **40**。
380
+ - **C-3 `43`**:G0(隔离/非 git 基线自证)**3** · G1(主判据 + 记账 + 代价面 + 三态标签)**11** · G2(无判别面载体的回落分支)**3** · G3(无故障路径三形态逐位一致)**7** · G4(盘上真值独立 oracle)**1** · G5(单点结构)**7** · G6(记账面:计数/样本有界/告警限流/可重置)**6** · G7(Windows 实测 `ctypes.WinDLL` 独占句柄)**5** ⇒ **43**。
381
+
382
+ **变异红项明细(实跑尾行,逐条照录关键项)**:
383
+
384
+ - **H-6**:① 关「MCP 面 `depends_on` 落盘(`_t_spawn` 写入分支)」→ `红项=4,命中组={'A': 4}`;② 关「MCP 面格式闸」→ `红项=25,命中组={'B': 10, 'D': 14, 'E': 1}`;③ 关「MCP 面存在性闸」→ `红项=7,命中组={'C': 2, 'D': 4, 'E2': 1}`;④ 关「MCP 面类型闸(非列表即拒)」→ `红项=1,命中组={'G': 1}`;⑤ 关「缺省即无依赖分支(`deps is None`→不校验不写)」→ `红项=6,命中组={'A': 4, 'F': 1, 'I': 1}`(**A 组同红是已声明的真实耦合**:A 夹具要提交一条不带 `depends_on` 的根任务);⑥ 关「orch 面白名单透传」→ `红项=1,命中组={'H': 1}`。六处**全部**「恰好命中预期」。
385
+ - **CH-1**:变异1 红项 **10 / 预期 10**(`G1b/G1c/G1d/G1e/G1g/G1b-1/G1b-2/G3c/G3m/G3n`),读值含 `G3m ← got=legacy conflict=None`、`G3n ← legacy`;变异2 红项 **6 / 预期 6**(`G2b..G2g`),含 `G2b ← rc=1`、`G2g ← (7, 10, 7, 10)`——**该读数即修前形态**。
386
+ - **C-3**:`C-3a`(撤接纳判据)红 **8/8**:`G1c ← cache['knowledge/orphan/c3_n01.md']=(10, (None, None))`、`G1d ← stats=(1, (('…c3_n01.md','PermissionError',13),))`、`G1e ← opens={}`、`G1f ← status=(None, None, None)`、`G1g ← after_release=['c3_n02','c3_n03']/[…]`、`G1h ← get=True`、`G7c ← cache=(4, (None, None))`、`G7d ← after=[]`;`C-3b`(判别退化为一律终态)红 **9/9**(同上 8 项 + `G7e ← (0, ())`)。
387
+
388
+ **锚点漂移面(实跑,fail-closed)**:三处守卫的 ANCHOR-MISS 路径均由**采集/复核环节**实测为「打印 `ANCHOR-MISS` + **退出码 2**」;**本报告未复跑该路径**(需在进程内篡改守卫的变异表)。**守卫基线源**为**当前工作区源码**(`inspect.getsource` / 直接 `open` 工作区路径),**不以 git HEAD 为基线**——见 §4.2 的 `G0c` 与 §5.2。
389
+
390
+ ### 4.2 由工作流采集的数字与**逐项复跑状态**(本版改标题:原先写「未复跑的数字」,而表内**至少有一项确实被复跑**——见下)
391
+
392
+ **表内「本报告是否执行」列逐行标注**,不要把整张表读成「一律未复跑」。
393
+
394
+ **先补两栈是什么(回应读者「容器栈一 / 栈二自始至终没说明各是什么、各跑哪套命令」)**——定义出自本工作流草稿 `.zcode/workflow-drafts/优化第二批-H6依赖透传-CH1对拍口径-C3负缓存.dwf.ts:301-330`:
395
+
396
+ | 栈 | 容器与命令(草稿原文) |
397
+ |---|---|
398
+ | **容器栈一(rust 腿)** | `docker run --rm -v <REPO>:/work -w /work -e CARGO_TARGET_DIR=/tmp/target rust:bookworm bash scripts/linux_verify.sh full`(草稿 `:301-305`) |
399
+ | **容器栈二(TS 腿)** | `docker run --rm -v <REPO>:/work -w /work node:22-bookworm bash -c "npm install --include=dev && npm run build && node --import tsx --test test/*.test.ts"`(草稿 `:317-322`) |
400
+
401
+ ⇒ 读者问的「`npm install` / `cargo build` / `linux_verify.sh full` 哪条属于哪栈」:**`linux_verify.sh full`(及其内部的 `cargo`)属栈一**;**`npm install` / `npm run build` / `node --test` 属栈二**。
402
+ ⇒ 读者问的「栈二是否跑过任何一条用例」:**采集片段只有 4 行**(草稿 `:323` 取 `stdout` 末 4 行),即 `# cancelled 0` / `# skipped 3` / `# todo 0` / `# duration_ms 5242.404858`。Node 内置 test runner 的汇总块行序中,`# tests` / `# suites` / `# pass` / `# fail` 位于 `# cancelled` **之前**,故这 4 行**是被 `slice(-4)` 截断后的尾部**、三行计数**未被采集**(此系按该 reporter 的已知行序推断,**非本报告实测**)。⇒ **从采集材料本身无法判定 `# pass` / `# fail` 的值**;本报告**不代补**、也不把它写成「跑过 N 条用例」。可确证的只有:该 runner 确实产出了汇总块(`# skipped 3`、`# duration_ms …` 同时在场),据此它至少**枚举**到了用例。
403
+
404
+ | 采集项 | 结果(原文照录) | 本报告是否执行 |
405
+ |---|---|---|
406
+ | **python 全量** | 退出码 `0`;`===== SUMMARY 262/262 通过,5 跳过(依赖缺失/平台不符) =====` | **已复跑并一致**(§4.1 第 7 行,同一条命令) |
407
+ | **容器栈一** | 退出码 `0`;尾行片段:`结果: 21 pass / 0 fail`、`[PASS] smoke_test (linux)`、`=== 汇总: 38 pass / 0 fail ===` | **未执行**(§4.5) |
408
+ | **容器栈二** | 退出码 `0`;尾行片段:`# cancelled 0`、`# skipped 3`、`# todo 0`、`# duration_ms 5242.404858`。**采集片段未含 `# pass` / `# fail` 计数行** ——本报告照录,**不代补** | **未执行**(§4.5) |
409
+ | 实施段定向套件(H-6) | ① `scripts/run_tests.py hive` `23/23` rc=0;③ `hive/hive_mcp/smoke_test.py` `21 pass / 0 fail` rc=0;④ `scripts.test_judgment_manifest` `16 通过` rc=0 | **未复跑**(本报告跑的是**全量**,已含 `hive` 组,见 §4.1 第 7 行) |
410
+ | 实施段定向套件(CH-1) | `cargo test --release` `27 passed / 0 failed`;`cargo build --release` rc=0;漂移态 rc=3;过期二进制 rc=4 | **未复跑** |
411
+ | 实施段定向套件(C-3) | `scripts/run_tests.py md_cg` `194/194 通过,3 跳过` rc=0;`run_all.py -k M0` `9/9` 一致 rc=0;FI-M02 单格 `verdict=pass expected=pass consistent=true` rc=0 | **未复跑**(全量已含 `md_cg` 组与 chaos 面,见 §4.1 第 7 行);**已由独立复核复跑**(§5.2 条目三) |
412
+ | 独立复核各探针 | 见 §5.2 | **未复跑**(引用复核结论) |
413
+ | 修前复现的 29 条腿(§2) | 见 §2 | **未复跑**(唯一例外:CH-1 三态,见 §4.3) |
414
+
415
+ ### 4.3 CH-1 三态**第一手复现**(本报告实跑;这是本批最重要的结论的证据)
416
+
417
+ **方法(零工作区写入)**:`git show HEAD:scripts/rank_parity.py` 取**修前** harness 原文 → 写进 `%TEMP%` 的**临时副本** → 对该副本做**一处定点文本变异**(把 `_REPO` 的计算改成仓根绝对路径,因为副本不在仓内;其余逐字不动)→ 以 `PYTHONPATH=<repo>` 跑。**工作区文件未被读写为实验体**。
418
+
419
+ | 态 | 命令(原样,`--exe rust/target/release/mdcg-eval.exe`) | 逐位 / 集合 / top-1 | rc | `[DIFF]` 条数 |
420
+ |---|---|---|---|---|
421
+ | **① 缺省** | `python -X utf8 %TEMP%\ch1_pre_uuzdejvm\rank_parity_pre.py --exe …` | **7/10 · 10/10 · 7/10** | `1` | **3**(`newuser 探针结论` / `蜂群调度 依赖门禁` / `安全 审计 令牌`) |
422
+ | **② 只关归一层** | 上列命令前加 `MDCG_UNIFY_QUERY=0` | **6/10 · 9/10 · 6/10** | `1` | **4**(前三条逐位重复 + **`memory recall pipeline`**,**该条集合层也不同**) |
423
+ | **③ 只切 jaccard** | 上列命令前加 `MDCG_SCORE_MODE=jaccard` | **10/10 · 10/10 · 10/10** | `0` | **0** |
424
+ | **②+③ 同关归一层且同口径** | 两个变量同设 | **10/10 · 10/10 · 10/10** | `0` | **0** |
425
+
426
+ **修后(工作区 harness,§4.1 第 8–10 行)对照**:缺省 `10/10·10/10·10/10` rc=`0`;`MDCG_UNIFY_QUERY=0` 仍 `10/10·10/10·10/10` rc=`0`;`MDCG_SCORE_MODE=legacy` → rc=`3`(口径不一致,**不给逐位读数**)。
427
+
428
+ **这几行读数的结论(与 §0.2 同一口径,本版重写)**:
429
+
430
+ - **主证据**=「补上打分口径对齐即 DIFF 归零」:态①的 3 条由**单跑态③**清空(rc 1→0);态②的 4 条由**「②+③」那一行**清空(rc 1→0)——**不是单跑态③的结果**(单跑态③时归一层仍开着,变量组合与态②不同;**本版更正**上一版把两行结果都记在态③头上)。⇒ R-4/R-5 无需被引入即已足以解释现象,**「三条(四条)DIFF 由 R-4/R-5 造成」这一归因被推翻**。
431
+ - **佐证(启发式,不单独承担排除力)**=态①/态②的 DIFF 形态(同分重排、id 集合相同)与主证据方向一致;读者已指出该形态**不是**对分词面差异的排除证明,本报告据此**降级其为佐证**(§0.2 证据结构)。
432
+ - **未证伪面**:R-4/R-5 **是否仍是两侧的潜在差异**,本实验**未判**——需专门的漂移样本,留池(§6.1 第 1 条)。
433
+
434
+ ### 4.4 隔离与「不许动什么」核对(本报告实跑)
435
+
436
+ | 核对项 | 命令 / 手段 | 我看到的 |
437
+ |---|---|---|
438
+ | 在役 hive 池**运行前**快照 | `os.listdir(D:\program\dsh-memory-main\hive\jobs)` | **17 个条目**:`_serve.json`、`_serve.log` + 15 个 `h*` 任务目录 |
439
+ | 在役 hive 池**运行后**快照(跑完三项守卫 + 全量套件后) | 同上 | **17 个条目,逐条同名同序**(与运行前**完全一致**) |
440
+ | **在役 hive 池的「时点敏感」补记**(本版新增,回应读者对计数口径的追问) | 同 `os.listdir`,连续两次 | 某一次列举得到 **18 个条目**:多出一个**非目录**条目 **`_serve.tmp20528`**(文件名内嵌 pid **20528**=**在役 serve 的 pid**,mtime `15:26:02`,恰与 `_serve.json` 的 `15:26:01` 同批);**下一次列举即消失、恢复 17 条目**。⇒ 它是**在役 serve 心跳原子写(tmp+rename)中途**被列举恰巧抓到的**瞬时件**,**非本报告产物**(本报告从未对该池发起任何写) |
441
+ | **在役池无 `guard-model` 残留**(本版新增,回应 nextQuestions 第 2 条) | 逐目录读 `spec.json` / `status.json` | 15 个任务目录的 `model` **全部**为 `deepseek-flash`(state:14 `done` + 1 `timeout`),**`guard-model` 命中 0 条**(本报告实跑按 `model=='guard-model'` 逐目录筛) |
442
+ | 在役 serve | `wmic process where "name='hive.exe'" get ProcessId,CommandLine` | 恰好 1 个:`hive.exe serve --jobs D:\program\dsh-memory-main\hive\jobs`(**本报告未启停它**) |
443
+ | `hive/src/` 是否被动 | `git status --porcelain` | **无任何 `hive/src/` 条目** ⇒ `spec.rs` / `main.rs` / `job.rs` / `scheduler.rs` 零改动 |
444
+ | 检索/排序判据是否被动 | `git status --porcelain` + 复核读码 | `md_cg/mdcos.py`(`search_rrf` 所在)与 `md_cg/nodefile.py` / `md_cg/eval_common.py` **未列入改动** |
445
+ | 工作区整体 | **开工快照**与**落盘前核对快照**各一次 `git status --porcelain` | **两次逐条相同:13 个 `M` + 4 个 `??`**(`??`=`.zcode/` + 三个守卫文件)。**这两个快照都不含本文件**;写出本文件后的**收尾快照**为 13 个 `M` + **5** 个 `??`(新增项即本文件)。计数约定见「行号与计数口径声明 → 工作区快照的计数约定」 |
446
+ | 在役数据根 | 本报告全部命令 | 未触碰 `D:/program/AEIS`、`data/policy.json`、hive 在役池;库根全部来自 `tempfile.mkdtemp` |
447
+
448
+ ### 4.5 未由本报告执行的验证(完整清单)
449
+
450
+ - **容器栈一(`rust:bookworm` + `linux_verify.sh full`)/ 容器栈二(`node:22-bookworm` + `npm install && npm run build && node --test test/*.test.ts`)**:**均未执行**(两栈的完整命令见 §4.2 的定义表)。理由与本仓前批一致——本机 win32、无 docker 形态的隔离执行面;且栈二在挂载点内跑 `npm install` / `npm run build`,会写 `node_modules` 与 `package-lock.json`,与「只改这一个文件、不得动源码/工作区」的硬边界冲突。两栈**只记录采集退出码 `0`,不写成实测**;栈二采集片段**未含 `# pass` / `# fail` 计数行**(成因见 §4.2),本报告**不代补**。
451
+ - **Rust `cargo test` / `cargo build --release`**:**未复跑**(本轮未改动 `rust/` 之外的构建面;且需 CARGO_TARGET_DIR 隔离构建)。
452
+ - **三处守卫的 ANCHOR-MISS 路径**:**未复跑**(需在进程内篡改变异表)。
453
+ - **`python -X utf8 -m hive.test_orch`**(复核抽查面):**未复跑**;已由全量套件覆盖(§4.1 第 7 行含 `PASS hive.test_orch`)。
454
+ - **`git archive` 父树 `f75a343e` 的重建探针**(`CH1-5` 里为排除 batch1 而做):**未复跑**;本报告用的是 HEAD 版 harness 副本 + 现行二进制(§4.3),结论一致。
455
+ - **修前复现的 29 条腿(§2)**:**未复跑**(唯一例外为 §4.3)。
456
+
457
+ ---
458
+
459
+ ## 5. 三项独立复核的判定与它列出的 uncovered
460
+
461
+ ### 5.1 判定
462
+
463
+ | 项 | 判定 | 依据要点(复核原文摘要) | 复核自陈未跑 |
464
+ |---|---|---|---|
465
+ | **H-6**(契约 ①–⑤ + 守卫本体与变异自证) | **`ACCEPT`** | 四态判定单:①ACCEPT ②ACCEPT ③ACCEPT ④ACCEPT(含 1 处**已声明**的形态差异)⑤ACCEPT;「全部结论只采信本次会话我亲自跑出的观察」。逐条:`_dep_gate` 读码核对(`:184/:186/:192/:194` 与 `spec.rs:203` / `main.rs:289` 同口径)、`:522` 闸位在 `_ensure_serve` 与 spec 组装**之前**、`:556` 保序写入、`orch.py:519` 白名单与 `:549` **同一个** `_dep_gate`(全仓 grep `_dep_gate` 只有定义处 + 这两处调用,**无第二套判据**);守卫正向 `43 通过 0 失败`、变异 `6 处全部恰好命中`;**自建脚本两态实跑**(真实临时 serve:窗口 1 无依赖的 control 已 `done` ⇒ 排除「单 worker 忙所以 pending」这一替代解释;窗口 2 `lock_ts ≥ dep_done_ts`);**自选 35 项** rust/python 逐项对照 `33/35` 一致;**修前面貌内存近似复原**(把 `SPAWN_ALLOWED_KEYS` 退回旧集、`_dep_gate` 置恒 `None`、orch 白名单剔除)→ `4 通过 39 失败` 且**仅剩的 4 条恰是取反成立的 E1/E2/F1/I1** ⇒「本守卫在旧实现上必红」成立;`git show HEAD:…mcp_server.py \| grep -c '_dep_gate\|depends_on'` = **0** 而 6 处锚点全部命中 ⇒ **基线源确为工作区**;删断言探针、锚点漂移探针(`ANCHOR-MISS` + EXIT=2)均实测;隔离核对:**在役池 17 条目、mtime 全为 09-27/09-28、无新增任务目录** ⇒ 实验未触在役池;回归抽查 `hive/test_orch.py` `94 通过 0 失败` | 全量套件/容器、调度侧失败传播(error/timeout/killed/needs_review)实测、真实 MCP 宿主端到端接线、symlink/junction 形态、环检测与 `content_hash` |
466
+ | **CH-1**(口径接线 + 守卫本体) | **`ACCEPT`** | 「本复核为只读判定」声明在案;①缺省态亲跑 `逐位一致 10/10 · 集合一致 10/10 · top-1 一致 10/10` rc=0,头部印 `score=jaccard=rust jaccard`;②口径不一致亲造 → rc=`3` 且**无逐位汇总行**,并**另做正对照**(假 serve 让两侧口径一致但 hits 全不同 → rc=`1`、10 条 `[DIFF]`、**无口径横幅**)⇒「口径闸报警」与「对拍真劈叉」在**码值与输出形状**上可判然区分;③守卫本体 `40 通过 / 0 失败 / 0 跳过` rc=0,`--mutate` 红项 `10/10` 与 `6/6`,其中落到 `G2g` 的读数 `(7,10,7,10)` **与契约修前读数逐位吻合**;ANCHOR-MISS 路径实测 rc=2;**修前形态独立复现**(harness 副本 + 两处定点文本变异 → rc=1、`7/10·10/10·7/10`、三条 DIFF **恰为** `newuser 探针结论`/`蜂群调度 依赖门禁`/`安全 审计 令牌`);**Rust `--score` 真在参与排序**(合成语料上 `--score jaccard` 与 `--score legacy` 三问排序**全不相同**,`info.score` 随入参如实回报)⇒ 佐证三条 DIFF 是**公式差异**(词法并列处劈叉),非 `strip_tense`/entity;④**反查 `git diff`**:`grep -E 'strip_tense\|entity'` 无命中、`mdcos.py` 未列入改动、`mdcg.py:499-500` 仍 `legacy`、`main.rs:99`/`engine.rs:52` 仍 `jaccard: true`、`eval_common.py:96` 未改写、`data/policy.json` 未出现 | **`--ab` 路径绕过口径漂移闸**(见 §5.2 第 1 条);显式入参丢失在运行时**不可观测**(第 2 条);遗留误导注释(第 3 条);变异表只含 2 条(第 4 条);未跑全量/容器/hive 面(第 5 条) |
467
+ | **C-3**(契约 ①②③④ + 验证 ①–⑤) | **`ACCEPT`** | 验证①重跑 FI-M02(**真跑 nt 分支**)→ 10 行全 OK,`CASE_RESULT verdict=pass expected=pass consistent=true` rc=0,stdout 首行即 fsutil 告警(**可发现面非空**);验证②**自建探针**(`lock_probe.py`,不 import 任何夹具):live 实现 → 持锁期 miss、`cache[…]=None`、记账 `(1,((…c3_lock.md,'PermissionError',13),))`、释放后**首次即命中**;**HEAD 实现**(`git show HEAD:md_cg/readcache.py` exec 成模块,确认 HEAD 无 `_read_status`)→ 持锁期 cache 条目字面 `(7,(None,None))`、释放后两次 search 仍 miss,而同刻 `cg.get` 非 None ⇒ **撕裂复现**——同一探针两实现结果相反 ⇒ **探针有判别力**;验证③记账面直读;验证④**独立 oracle 不靠推理**:`git archive HEAD` 解出修复前整树到临时目录,同一夹具库三路快照(HEAD 源码+缓存开 / 现行源码+缓存开 / 现行源码缓存关)的 ids+12 位分数+结果键集+meta+8 节点 get 面,三份 JSON **sha256 全等** `6fd3a476f117a8872919a738f95b7fa5`(11114 字节,**非退化**:tier 有 T2/T3、candidates/scanned 各异、共用词命中 8);另有**原始字节 oracle**;验证⑤守卫 `43 通过` rc=0 + `--mutate` `8/8`、`9/9`;**删断言探针**(把 `md_cg` 整包复制到 temp 副本删掉 `G1c` 的 `ok(...)`)→ 变异自证 **MISMATCH**、EXIT=1;锚点漂移 → `ANCHOR-MISS` + EXIT=2;**性能悬崖论证独立复核**(自建探针 8 节点中令 3 个 path 抛 `PermissionError`:冷缓存一次查询 8 次 open、**稳态两次查询各恰 3 次**、成功节点重读 **0** 次、命中数恒 5);**禁改面核对**:`git diff --numstat md_cg/fsutil.py` = `83 增 0 删`、`nodefile.py`/`mdcos.py` `git status` 干净、`_fresh` 段与 HEAD **逐字相同**、`_DirtyDict` 与 HEAD **逐字相同**、`git diff -U0 md_cg/mdcg.py` 变更 hunk **仅** `@@2591~2648` 读面;**相邻回归**:`test_govern_directread` `40/0`、`test_readcache_precise_inval` `23/0` | **残余静默读失败面**(`mdcg.py:2983`、`:3869`,见 §5.2 第 1 条);`FileNotFoundError` 仍固化属**有意保留边界**;**Linux 行为未实测**(非 nt 分支只做读码核对);未跑 `run_all` 全量与 hive/容器面;清理时把 `%TEMP%` 下既有 chaos 旧残留一并删除 |
468
+
469
+ **三项判定均为 `ACCEPT`**;三项的**验证者≠执行者**(复核材料自陈「全部结论只采信本次会话我亲自跑出的观察」「未采信执行者自述」)。
470
+
471
+ > **H-6 格内两组数字的并置声明(本版新增,回应读者「④ 写『含 1 处形态差异』,同一格却写 33/35 一致即 2 处不一致,哪条对应哪一态没有交代」)**:这两个数**不是同一口径、也不互相矛盾**——
472
+ > - 「**自选 35 项** rust/python 逐项对照 `33/35` 一致」是复核员**自建的对照探针**读数,失配 **2** 项(该探针的 35 项明细**未随材料给出**);
473
+ > - 「①ACCEPT ②ACCEPT **③ACCEPT ④ACCEPT(含 1 处已声明的形态差异)** ⑤ACCEPT」是**四态判定单**对**契约 ①–⑤** 的判定,其中 ④=「判据单点 + 守卫两侧对照」这一条。
474
+ > ⇒ 前者是**探针的分类一致率**,后者是**契约条目的通过判定**,两者**不是同一格计数**。复核材料**未逐项点名**那 2 项失配对应的 id / 形态,故本报告**不做强配、不替它认定**。可核的旁证是:复核自己的 uncovered 第 4 条**恰好列出两处形态差异**(顶层裸字符串 CLI=accept / MCP=reject;`orch` 侧 `depends_on=[]` 不落键 vs MCP 侧落 `[]`)——与「2 项失配」在**数量上**吻合,**是否一一对应未经材料确认**。
475
+
476
+ ### 5.2 三项各自列出的 uncovered(**照录,不代为消除**)
477
+
478
+ **H-6 复核列出**:
479
+
480
+ 1. 未跑全量套件/容器(按要求);只跑了守卫本体两种模式 + `hive/test_orch.py` 抽查。
481
+ 2. 调度侧**失败传播**(上游 `error`/`timeout`/`killed`/`needs_review` → 下游直接 `error`)**未实跑**——`deps_gate` 未改动(`hive/src` 干净),属既有行为,本次只验证了「未 `done` 不被领取 / `done` 后可领取」两态。
482
+ 3. **未做真实 MCP 宿主(客户端)端到端接线**,只在进程内直调 `_t_spawn`;工具 schema 是否被宿主正确投递**未验证**。
483
+ 4. **已声明但仍值得留意的形态差异**:顶层**裸字符串**形态 CLI=accept(`as_str_vec` 宽松采信)/ MCP=type_reject(更严,`:186` 注释已声明该有意分歧,但 `hive/README` **未逐字写明**);另 orch 侧 `depends_on=[]` **不落键**、MCP 侧落 `[]`——各自沿用本面既有「空值=未设」纪律,`deps_gate` 对二者都视为无依赖(已实测)。
484
+ 5. **守卫卫生面**:`_cleanup_persist` 正常退出时确实删除对照池(已直接验证),但在**同一进程内**第二次调用 `_branch_baseline()`/`_parity_pool()` 时 `_PARITY` 缓存仍指向已被删的路径 ⇒ 基线假红并在 `%TEMP%` 留残(已复现机制并清理);单进程单次运行(守卫的两种官方用法)不受影响。`%TEMP%` 另有 3 个 `h6_parity_*` 残留,**创建于 14:56-14:57(早于该复核会话)**,非其产生,其未删。
485
+ 6. 未测 `symlink`/`junction` 形态的 `jobs/<dep>`(两侧同为 `isdir` 口径,未额外验证);**未做环检测与 `content_hash`**(契约明示不做)。
486
+
487
+ **CH-1 复核列出**(「残余面(不影响 CH-1 主判据,但如实登记)」):
488
+
489
+ 1. **`--ab` 路径绕过口径漂移闸**:`MDCG_SCORE_MODE=legacy … --dataset … --ab` → EXITCODE=`0`,头部印 `口径 legacy(本 harness 钉住)`——该标签**自相矛盾**(harness 钉的是 `jaccard`),且与 harness 自身 docstring 第 39–44 行「env 声明冲突即报错退出(3)」**相抵触**。成因:`main()` 里 `--ab` 分支(`rank_parity.py:294-321`)**先于**两侧对照闸(`:340`)返回,pin 冲突只被回传未拦截。A/B 是**单侧路径**、无「两侧对照」可言,故**未违反契约②的逐字口径**,但属同一「口径不得漂移」属性的缺口,且守卫 `G3p` 只做静态字符串断言、变异表未覆盖该路径。同一运行也确证了 docstring 关于修前读数的括注(legacy 下 `off` 侧 top-1 = `ds_en_02`,jaccard 下 = `ds_en_03`)**属实**。
490
+ 2. **显式入参的丢失在运行时不可观测**:把 `rust_open` 的 argv 里 `"--score", score` 删掉(临时副本,未动工作区)后跑真 harness → **仍 rc=0、仍印 `score=jaccard=rust jaccard`**(回读拿到的是 Rust 自身缺省 `jaccard`)。即契约①「不依赖 `Config::default()`」目前**只由静态锚点 `G3e` 守着,行为面无法自证**;若将来把 `SCORE_MODE` 常量改成 `legacy`,该行缺失才会被回读闸抓到。
491
+ 3. **遗留(非本批、未改)误导注释**:`rust/src/main.rs:99` 的「缺省 jaccard……与 Python SCORE_MODE 缺省一致」——与 CH-1 新增 help 文本(`main.rs:204-207`「注意 Python 侧缺省是 legacy……两侧缺省不同」)**正相反**。**HEAD 里即存在**;守卫负向锚点 `_RUST_CFG_DEFAULT_ANCHOR` 只匹到 `jaccard: true, // 缺省 jaccard` 前缀故**抓不到**这句陈化断言。(本报告独立确认:`git diff -U0 rust/src/main.rs` 的 hunk 只落在 `179/183/204/206/776/780`,`:99` 与 `:13-14` **不在改动面**。)
492
+ 4. **变异表只含 2 条**(钉住行、对照闸);**回读面本身**(`rust_reported_score` 被删)**无行为变异项**,只有 `G3f` 静态锚点 + `G4` 的假过期 serve 兜底。
493
+ 5. **未跑**:全量 pytest / 容器 / hive 面(按任务要求不重复跑);未核 `eval_common.use_jaccard` **之外**其它 bench 脚本的调用面是否同样无漂移(本批未涉)。
494
+
495
+ **C-3 复核列出**:
496
+
497
+ 1. **残余静默读失败面(同族,非 C-3 固化面)**:守卫 docstring 与 `_note_read_oserror`(`mdcg.py:2617`)声称「读路径上所有 `except OSError` 都必须经此转一次」,但**不字面为真**——`md_cg/mdcg.py:2983`(`MdCG.search` 内负记忆覆盖扫描,读 rejected/unresolved 节点文件失败即静默 `continue`)与 `md_cg/mdcg.py:3869`(`health()` 扫描)**仍是静默 `except OSError`**,不经 `_note_read_oserror`、不进记账。二者**不入读缓存** ⇒ **不产生 C-3 的负结果固化**,影响面仅限 `neg_coverage` 抑制信号与 health 计数;守卫 `G5b` 只统计 `classify_read_failure(exc)` 出现次数=1,**抓不到这两处**。**(本报告第一手读码确认该两处现为 `except OSError: continue`——`mdcg.py:2980-2984` 与 `:3866-3870`。)**
498
+ 2. **固有边界(有意保留、非回归)**:`FileNotFoundError` **仍按契约固化** `(gen,(None,None))`(`G1i` 实测),故「外部删除后由外部非 CG 写路径恢复同名文件」在本进程内仍不可见至写盘/重启——这是模块声明的「跨进程/外部改写不可见」边界,本次未改。
499
+ 3. **Linux(容器栈一)行为未实测**:本机 win32,非 nt 分支只做读码核对;FI-M02 在 Linux 将走 `case.finish("pass","pass")` 报 pass(与 registry `expected_verdict=pass` 一致 ⇒ 退出码 0),**不做任何实测**——即 **Linux 上的 pass 是登记基线而非实测结论**,与旧版报 `gap` 同属「无实测的基线声明」。
500
+ 4. 未跑 `run_all` 全量与 hive/容器面(契约明令不重复全量),故 registry 变更在整包裁决下的表现未实测,仅按 `run_all.py:104` 的 `(verdict==expected)` 口径读码推得一致。
501
+ 5. **清理声明(如实)**:收尾清临时目录时把 `%TEMP%` 下既有的 `chaos_fi_m03/m04/m05/m09/r07_*` 旧残留**一并删除**(均在系统临时目录,非在役数据根;在役 `D:/program/AEIS` 与 hive jobs 池未被触碰,工作区 `git status` 与开工时逐条相同)。
502
+
503
+ ---
504
+
505
+ ## 6. 边界与未覆盖
506
+
507
+ ### 6.1 本轮明确**不修**、留池的面
508
+
509
+ | # | 留池项 | 依据 |
510
+ |---|---|---|
511
+ | 1 | **清单原判 R-4**(两侧 `strip_tense` 规则不同)与 **R-5**(entity 路 tags 取值两侧不同源) | 本批实验证明它们**不是**对拍三条(四条)DIFF 的成因(§0.2、§4.3),但**它们是否仍是潜在差异未被证伪**——需要**专门的漂移样本**才能判,本批未做,**留池**。契约 `不许动什么` 也明列「不改两侧 `strip_tense` 实现 / 不改 entity 路 tags 取值」 |
512
+ | 2 | **H-1**(MCP 面绕过去重 + `new_job_id` 同毫秒碰撞) | 改 `job_id` 格式牵动 `h` 前缀排序契约,须使用者先裁方案;契约明列「不动 `job_id` 格式 / 不引入 `content_hash` 去重」 |
513
+ | 3 | **R-7**(把 rust 测试与 `rank_parity` 纳入门禁) | CH-1 修好后其**前提已具备**,但本批未做,留下一批 |
514
+ | 4 | `rust/src/main.rs:13-14` 与 `:99` 的**失实/陈化注释** | **HEAD 里即存在**,本批未改(§1.2、§5.2 CH-1-3);本报告只记录事实 |
515
+ | 5 | `--graph-seeds raw` 支路、`--order` 等排查阀 | 属排查阀,非缺陷面 |
516
+ | 6 | `.zcode/`(未追踪、未被 `.gitignore` 忽略)/ `package-lock.json`(`M`,与本批无因果) | 本报告**不主张归属**,仅记录现场;处置权归使用者 |
517
+ | 7 | `npm run gate` 与 `git add/commit/push` | 需写操作,不在本工作流脚本内,**留主会话收口** |
518
+
519
+ ### 6.2 本报告读码新见、**已登记但本批未处理**的缺口
520
+
521
+ 1. **`--ab` 路径绕过口径漂移闸**(`rank_parity.py:294-321` 早于 `:340` 返回)——CH-1 复核 uncovered 第 1 条;本报告独立确认 `--ab` 分支的 `return 0` 在 `:321`,而对照闸在 `:340`。
522
+ 2. **回读面的行为变异缺位**——CH-1 复核 uncovered 第 2 条(删掉 argv 的 `--score` 仍全绿)。
523
+ 3. **C-3「读路径 `except OSError` 全经单点」的 docstring 断言与实现不符**——`mdcg.py:2980-2984` 与 `:3866-3870` 两处仍是静默 `continue`(本报告读码确认);二者**不入读缓存**故**不属 C-3 固化面**,但属同类「静默读失败」缺口的**残余面**。
524
+ 4. **`_submit` 仍是哑写入者**(`mcp_server.py:376-404` 零校验);闸落在 `_t_spawn` / `orch._spawn` 两个**构建 spec 的入口**。采集原文明确请求:「**若契约本意是闸在 `_submit` 内,请明示**」——本报告照录,**不代裁**。
525
+ 5. **顶层裸字符串形态的两面分歧**(CLI 宽松 / MCP 更严)——已声明但仍值得留意;`hive/README` **未逐字写明**该分歧(H-6 复核 uncovered 第 4 条)。
526
+ 6. **`orch` 侧 `depends_on=[]` 不落键 vs MCP 侧落 `[]`** ——各自沿用本面既有「空值 = 未设」纪律,`deps_gate` 对二者都视为**无依赖**(已实测)。
527
+ 7. **守卫卫生面**:H-6 守卫在**同一进程内**二次调用 `_branch_baseline()` / `_parity_pool()` 会因 `_PARITY` 缓存指向已删路径而**基线假红**并在 `%TEMP%` 留残——单进程单次运行不受影响(H-6 复核 uncovered 第 5 条)。
528
+
529
+ ### 6.3 三项共有的边界
530
+
531
+ - **未跑容器两栈**(§4.5):本机 win32;栈内命令与硬边界冲突。两栈**只记录采集退出码 `0`**。
532
+ - **未跑真实外部宿主**:H-6 的 MCP 面只在**进程内**直调 `_t_spawn`,**真实 MCP 客户端**投递工具 schema 的端到端**未验证**。
533
+ - **非 Windows 分支是登记基线而非实测**:C-3 的 FI-M02 在 Linux 报 `pass` 是**登记基线**(与旧版报 `gap` 同属「无实测的基线声明」);采集的「`os.name` 打桩分支模拟」是**本机 Python 上的桩**,不是真实 Linux 运行。
534
+ - **锚点漂移面**(ANCHOR-MISS → rc=2)由采集/复核环节实测,**本报告未复跑**(§4.5)。
535
+ - **守卫的自证结构**:三处守卫的基线源均为**当前工作区源码 + 定点变异**(`G0c` 自证),**不以 git HEAD 为基线**;除 ANCHOR-MISS(锚点找不到 → rc=2)外,**不依赖变异表的独立面**只有各自的行为面(H-6 的 A 组临时 serve 两态、CH-1 的 `G1b` 完全缺省调用、C-3 的 `G7` Windows 实测与 FI-M02 用例)。
536
+
537
+ ### 6.4 C-3 的「残余静默面」与 H-6 的「后果面」两处**未覆盖**(并列,不互相消解)
538
+
539
+ - **C-3**:`mdcg.py:2980-2984`、`:3866-3870` 两处静默 `except OSError` **未收口**(§6.2 第 3 条)。本报告只判事实:它们**不经** `_note_read_oserror`、**不进**记账,且**不入**读缓存 ⇒ **不产生** C-3 的固化形态,影响面限于 `neg_coverage` 抑制信号与 `health()` 计数。
540
+ - **H-6**:调度侧**失败传播**(上游非 `done` 终态 → 下游直接 `error`)**未实跑**(`hive/src` 干净,属既有行为);本批只验证了「未 `done` 不被领取 / `done` 后可领取」两态(采集 `H6-5` + 复核自建两态脚本)。
541
+
542
+ ---
543
+
544
+ ## 7. 诚实留痕
545
+
546
+ 1. **修前复现的 29 条腿(§2)本报告未复跑** —— 唯一例外是 **CH-1 三态**:本报告用 HEAD 版 harness 的**临时副本**(仅改 `_REPO` 计算一行)第一手复现,数字与采集**逐条一致**(§4.3)。
547
+ **§4.2 的表则逐行不同(本版更正)**:原句把「§2 的 29 条腿」与「§4.2 的表」并成一句「未复跑」,与表内 `python 全量` 行自书的「**已复跑并一致**」相冲突(读者指认属实)。准确口径是:§4.2 表内 **已复跑 1 项**(`python 全量`——同一条命令 `python -X utf8 scripts/run_tests.py`,`262/262 通过、5 跳过`,rc=0);**未复跑 7 项**(容器栈一、容器栈二、实施段的三组定向套件、独立复核各探针)。
548
+ 2. **容器两栈未执行** —— 本机 win32,且栈内命令与「只写这一个文件、不得改源码」的硬边界冲突。两栈**只记录采集退出码 `0`,不写成实测**。容器栈二的采集片段**未含 `# pass` / `# fail` 计数**,本报告**不代补**。
549
+ 3. **三处守卫的 ANCHOR-MISS 路径未由本报告复跑** —— 该路径由采集与三项复核环节实测(`ANCHOR-MISS` + rc=2),本报告引用其结论并标注来源。
550
+ 4. **`rust/` 的 `cargo test` / `cargo build --release` 未由本报告复跑** —— 本报告对 `rust/` 的处理是**只读核对**(`git status`、`git diff -U0`、读码)。
551
+ 5. **H-6 首版守卫的池泄漏事故由采集原文如实报告,本报告照录** —— 本报告的独立核对是**在役池快照前后一致(17 条目,逐条同名同序)**,据此只能说「**本轮运行未复现该形态**」,**不足以**核证事故当时的历史细节(删了几个目录、是否全部清理)——那部分本报告**无从核**。
552
+ 6. **R-4/R-5 只被证明「不是这三条(四条)DIFF 的成因」** —— **未证伪**它们作为潜在差异存在的可能;本报告不把它读成「R-4/R-5 已被排除」(§0.2、§6.1 第 1 条)。
553
+ 7. **`rust/src/main.rs:13-14` / `:99` 的失实注释为既有、本批未改** —— 本报告实跑 `git diff -U0` 确认其不在改动 hunk 内,只记录事实,处置权归使用者。
554
+ 8. **本文「实跑」与「采集」严格分栏** —— §4.1 全部为本报告本次会话亲跑(命令原样列出);§4.2 全部标为「未复跑」;§2 与 §5 分别引用「缺陷复现」与「独立复核」环节的原始记录,凡涉及它们的结论均注明来源。
555
+ 9. **未 `git add` / `commit` / `push`** —— 唯一写操作即本文件。
556
+
557
+ ---
558
+
559
+ ## 8. 读者反馈的逐条处置(本版新增)
560
+
561
+ 处置原则:**能补证据的补证据(标注实测/读码);能说清的改措辞;确认是误报的说明为什么不改**。凡涉及「改不改代码 / 何时做 / 谁来裁定」的,本报告只给事实与依据,**裁定权归使用者**(本文件硬边界:不得动源码)。
562
+
563
+ ### 8.1 `unclear`(7 条)
564
+
565
+ | # | 读者问题 | 处置 | 落点 |
566
+ |---|---|---|---|
567
+ | 1 | 「四可」从未说明指哪四条 | **已补定义 + 出处 + 它在验收里的角色**:四可=**可发现 / 可隔离 / 可恢复 / 可追溯**(顺序即此序);口径出处 `docs/eval/故障注入实测_v1.0.md:21`,用例内四项断言 `test/chaos_injection/test_fi_m02_transient_read_negative_cache.py:143-149`;**FI-M02 改前取值「否·是·是·是」**(`:26`)⇒ C-3 把**可发现**由「否」翻为「是」。§2.3 与 §3.3 两处出现处均加了就地定义 | §0.1、§2.3 表、§3.3 |
568
+ | 2 | 「N134」「N225」无说明 | **已补**:新建「前件出处与外部编号」一节——N 号=本仓「缺陷挖掘·自主迭代」的**缺陷编号**;**N134**(第 16 轮首报)首报处 `docs/eval/缺陷挖掘_自主迭代_v16.md:86`;**N225** 首报处 `docs/eval/缺陷挖掘_自主迭代_v25.md:118`、修复报告 `docs/eval/N225_索引日志非对象装载面类型闸_v1.0.md`;并给出「三类坏行记账」的落点 `md_cg/fsutil.py:286-290` | 新节「前件出处与外部编号」 |
569
+ | 3 | 「清单」「契约」无出处;被判决的原文未引出;两套编号来源未交代 | **已补**:① 出处表(清单**不在本仓追踪面内**——已如实声明未见原件;契约=工作流草稿 `.zcode/workflow-drafts/优化第二批-….dwf.ts` 的 `:15-40`/`:42-66`/`:68-89`);② **两条被判决的契约原文整段引出**(草稿 `:48` 与 `:60-63`,见 §2.2 表下引块);③ 重申「清单 R-x ↔ 本批 H-6/CH-1/C-3 ↔ §2 腿号」三套编号互不对应 | 新节、§0.1、§2.2、§3 各节开头 |
570
+ | 4 | 红项读数只给标签、无标签到断言的对照 | **已补 §附A**:三处守卫 **43 + 40 + 43 = 126 条**断言逐条「标签·断言原文」列出,并按表反推 §4.1 的每组红项数由哪些标签构成 | §附A、§4.1 |
571
+ | 5 | 容器两栈各是什么、各跑哪套命令;栈二是否跑过用例 | **已补定义表**(草稿 `:301-305` / `:317-322` 原文):栈一=`rust:bookworm` + `linux_verify.sh full`;栈二=`node:22-bookworm` + `npm install && npm run build && node --test test/*.test.ts`。栈二的 `# tests/# pass/# fail` 三行**因采集只取末 4 行而未落**(按 Node reporter 行序推断,非实测)⇒ **从采集材料无法判定 pass/fail**,本报告不代补 | §4.2、§4.5 |
572
+ | 6 | 同一对象两个计数(15 键 / 16 键)口径未标 | **已补口径声明**:15 键=**修前**、16 键=**修后**(本批新增 `depends_on`);两处出现位置已分别标注时点 | 「行号与计数口径声明 → 计数」、§0、§1.1、§2.1 |
573
+ | 7 | 13 M + 4 ?? 与报告自身是否计入 | **已补约定**:开工快照=13 `M` + 4 `??`;**收尾快照(写出本文件后)=13 `M` + 5 `??`**(第 5 项即本文件)。§4.4 原句指「开工」与「落盘前」两次,**均不含**本文件——非另一种口径 | 「行号与计数口径声明 → 工作区快照」、§4.4 |
574
+
575
+ ### 8.2 `unsupported`(8 条)
576
+
577
+ | # | 读者问题 | 处置 | 落点 |
578
+ |---|---|---|---|
579
+ | 1 | 摘要「推翻」与正文「未证伪」强度矛盾 | **已改措辞(全文统一)**:**被推翻的是「三条 DIFF 由 R-4/R-5 造成」这一归因判断**;「R-4/R-5 是否仍是潜在差异」**未被证伪**(留池)。文件头、§0、§0.2 末段、§4.3、§7 第 6 项五处已统一为同一句法 | 文件头、§0、§0.2、§4.3、§7 |
580
+ | 2 | 「两条依据缺一不可」与「充分」打架;形态二分未论证 | **已改结构**:降为「**一条主证据(承担充分性,单独成立)+ 一条启发式佐证(不承担排除力)**」;并**接受**读者对该形态论证的指认(分词差异同样可能只改分数/名次而非 id 集合)——**不再主张症状形态构成对 R-4/R-5 的排除**;排除力唯一来源=主证据 | §0.2 |
581
+ | 3 | 把态②那四条归给了态③ | **已更正**:态①的 3 条由**单跑态③**清空;态②的 4 条由**「②+③」那一行**清空(单跑态③时归一层仍开着)。原句「只对齐打分口径这一件事(态③)……把态②的全部四条也清成 0」**撤回** | §0.2、§4.3(表已把态②行改标为「只关归一层」) |
582
+ | 4 | §7 第 1 项「§4.2 表内采集项未复跑」与 §4.2 首行「`python 全量` 已复跑并一致」冲突 | **已更正**:§7 第 1 项拆为两句——**§2 的 29 条腿未复跑**(唯一例外 CH-1 三态);**§4.2 表内「已复跑 1 项(`python 全量`)+ 未复跑 7 项」**。§4.2 标题同步改为「与逐项复跑状态」 | §4.2、§7 第 1 项 |
583
+ | 5 | 「两套口径逐处给出」未兑现 | **已补位移对照表**:15 行「修前行号 ↔ 修后行号 ↔ 位移」,并声明**只列两套口径都出现过的站点** | 「行号与计数口径声明」 |
584
+ | 6 | 「文案与 CLI 逐字对齐」无法核对 | **已补**:`_dep_gate` 三条报文**逐字引出**(`:189-190` / `:193` / `:195`),并与 CLI 两条(`spec.rs:204-206`、`main.rs:292-294`)对照——**逐字相同的只有后两条**,第一条是本面独有 | §1.1 |
585
+ | 7 | 「CLI `as_str_vec` 宽松采信」无 `path:line`、无腿 | **已补 `path:line`**:`hive/src/json.rs:63-81`(`:65` 不适用条件自书「不做类型校验(宽松取值…)」;`:78-79` 非数组→单元素)。**同时如实标注仍未有的证据**:该行为**无采集腿**(`H6-4` 四组载荷全是数组),只到**源码定义级** | §1.1、§3.1 偏离 2 |
586
+ | 8 | ④ACCEPT「1 处形态差异」与同格「33/35 一致」对不上 | **已补并置声明**:两者**不是同一口径**(前者=契约条目判定,后者=复核自建 35 项探针的分类一致率);复核**未逐项点名** 2 项失配,本报告**不强配**,只指出其 uncovered 第 4 条**恰列两处形态差异**(数量吻合、是否一一对应未确认) | §5.1 表下 |
587
+
588
+ ### 8.3 `nextQuestions`(8 条)——**本报告只给事实与归属,不代裁**
589
+
590
+ | # | 读者问题 | 本报告能给的依据(实测/读码,含行号) | 归属 |
591
+ |---|---|---|---|
592
+ | 1 | H-6 的闸该落在哪一层?若 `_submit` 也要管,验收口径是否重做? | **现状**:闸在**两个构建 spec 的入口**——`:522`(`_t_spawn`)与 `orch.py:549`(`orch._spawn`);`_submit`(`:376-404`)是**哑写入者**,其生效条件注释 `:375` 自书「**不做校验**」。**机制判断**(供裁定用,非本报告主张):若把闸下沉进 `_submit`,两个入口的闸即成**冗余第二道**——守卫 A 组(走 `_t_spawn` 的合法提交)与 B/C/D/G 组(非法输入)**行为不变**,故**不需要重做**;但**需要新增**一个 `_submit` 层的守卫项,否则「闸在 `_submit`」这一新契约**无断言保护**。**代价**:`:375` 注释与 §3.1 的偏离声明须同步改写 | **使用者裁定**(改契约 or 改实现);本报告不改码 |
593
+ | 2 | 已删的池泄漏由谁核证删干净? | **已就地补一次核证(本报告实跑)**:`hive/jobs` 的 15 个任务目录 `spec.json` 中 `model` **全部** `deepseek-flash`、**`guard-model` 命中 0 条**;目录总数 15 与事故前口径一致(§4.4 末两行)。**边界**:核到的是「**现在无残留**」,**核不到**「当时删了几个、是否删净」(历史动作,本报告无从核) | **事实已补**;「是否接受该核证为闭环」=**使用者裁定** |
594
+ | 3 | Python 缺省 `legacy` 与 Rust 缺省 `jaccard` 的分歧本身要不要修? | **事实**:本批**刻意不动**两侧产品缺省(契约 `不许动什么` 明列);harness 改为**两侧都显式钉住**(§3.2)。**谁能拿到不同排序**:任何**直接消费 Python `md_cg` 检索缺省**的路(`SCORE_MODE` 缺省 `legacy`,`md_cg/mdcg.py:500`)与任何**直接用 `mdcg-eval` / `--serve` 缺省**的路(`jaccard: true`,`rust/src/engine.rs:52`、`main.rs:99`)产出的排序**可以不同**——这是**既成事实**,本批只是让 harness 不再踩它。**是「有意」还是「待修」,本报告不判** | **使用者裁定** |
595
+ | 4 | 判 R-4/R-5「是否仍是潜在差异」所需的漂移样本由谁造、放哪批? | **事实**:本报告只能指出该样本的**判据形状**——固定同一语料与同一 query 集合,**只切 `strip_tense` 或 entity tags 一个变量**、两侧其余口径(打分公式、归一层)全部钉住,再看是否产生 DIFF;这正是本批三态实验**没有做**的那一步(本批只证明了「不切它就已经全绿」)。**造样本与排批=使用者裁定** | **使用者裁定** |
596
+ | 5 | `--ab` 读数还能不能当排查结论用? | **已补第一手实测(本报告实跑)**:`MDCG_SCORE_MODE=legacy … --dataset scripts/retrieval_dataset.json --ab` → **rc=0**、头部逐字 `A/B(30 节点,top-1 变化;口径 legacy(本 harness 钉住)):`——**标签自相矛盾**(harness 钉的是 jaccard)且**不被拦截**;**不设 env** 时头部为 `口径 jaccard(本 harness 钉住)`,且 `beef noodles lunch` 的 `off` 侧为 `ds_en_03`(与复核所述「legacy 下 `ds_en_02`、jaccard 下 `ds_en_03`」一致)。⇒ **可用性判据**:**不设 `MDCG_SCORE_MODE`(常规用法)时的 `--ab` 读数可用**(A/B 两态同口径、只切归一层);**设了与钉住值冲突的 env 时不可用**(该次运行的读数与标签都不可信) | **事实已补**;「是否先修该路径」=**使用者裁定** |
597
+ | 6 | 三处已登记遗留面本批留池还是现在收? | **事实(本报告读码)**:① 两处静默 `except OSError`——`md_cg/mdcg.py:2980-2984`(负记忆覆盖扫描)与 `:3866-3870`(`health()` 扫描),二者**不入读缓存**故不属 C-3 固化面(§6.2 第 3 条);② `rust/src/main.rs:13-14` 与 `:99` 的失实注释——**HEAD 即存在**,`git diff -U0 rust/src/main.rs` 的 hunk 只落 `179/183/204/206/776/780`,**不在本批改动面**;③ `hive/README` 未逐字写明「裸字符串 CLI 宽松 / MCP 更严」的分歧(§6.2 第 5 条)。**三者本批均未动**(硬边界:不得改源码) | **使用者裁定**(收 or 留池) |
598
+ | 7 | 收口动作归谁、何时?`package-lock.json` 的 `M` 与 `?? .zcode/` 怎么处置? | **事实**:`npm run gate` 与 `git add/commit/push` **需写操作,不在本工作流脚本内**(草稿 `:4` 明书「提交/推送/npm run gate 不在脚本内,留编排会话收口」);`package-lock.json` 的 `M` 与本批**无因果关系**(本报告不主张归属);`.zcode/` **未被 `.gitignore` 忽略**(本仓前批已实测 `git check-ignore -v .zcode` 无输出;本报告未重跑该项)。本报告**未做任何 `git add/commit/push`** | **使用者 / 主会话** |
599
+ | 8 | 容器两栈与 Linux 面何时实测?FI-M02 的 Linux `pass` 算不算闭环? | **事实**:本机 win32,两栈**未执行**(§4.5);FI-M02 在 Linux 走 `case.finish("pass","pass")`(`test_fi_m02_transient_read_negative_cache.py:47-55`),与 registry `expected_verdict=pass` 一致 ⇒ **退出码 0,但那是登记基线、不是实测**(「跨平台机械判据」由 `md_cg/test_c3_transient_read_negative.py` 承担,其 G1/G2/G3/G4/G5/G6 组**不依赖 Windows**,本报告已在本机实跑 43/43)。**「是否要求两栈实测才算闭环」=使用者裁定** | **使用者裁定** |
600
+
601
+ ---
602
+
603
+ ## 附A:断言标签 → 断言文本对照(本版新增,回应读者「红项读数只给标签、无对照」)
604
+
605
+ 来源:**本报告实跑三处守卫的 stdout 逐行照录**(命令见 §4.1 第 1/3/5 行;下表摘录每一 `PASS` 行的原文)。
606
+
607
+ ### A.1 H-6 守卫 `hive/test_h6_mcp_depends_on.py`(43 条)
608
+
609
+ | 组 | 条数 | 标签·断言原文 |
610
+ |---|---|---|
611
+ | `A`(真实 serve 端到端) | 4 | `A1`·MCP 面提交带 `depends_on` 的任务 → `spec.json` 落盘含该键 | `A2`·落盘值与提交参数逐项一致(保序、不裁剪) | `A3`·依赖未 `done` 时不被领取(观察窗口内 `pending` 且无 `claimed.lock`) | `A4`·依赖 `done` 后才被领取且终态 `done`(领取不早于依赖 `done` 写盘) |
612
+ | `B`(格式闸拒面) | 10 | `B1`·格式非法被拒 `'../x'` | `B2`·`'x123'` | `B3`·`'h/../../x'` | `B4`·`'..'` | `B5`·`'h\..'` | `B6`·`'h:x'` | `B7`·`'h.%.txt'` | `B8`·`'h1_a '` | `B9`·`''` | `B10`·`'h..'`(十条均为「格式非法被拒」) |
613
+ | `C`(存在性闸拒面) | 2 | `C1`·不存在的依赖被拒 `h1999999999999_zz` | `C2`·不存在的依赖被拒 `h_notadir_x` |
614
+ | `D`(rust/python 两侧逐项对照) | 21 | `D1`·已有目录的合法 id | `D2`·已有目录的短合法 id | `D3`·已有目录的仅 `h` 前缀 id | `D4`·合法格式但目录不存在 | `D5`·合法格式但同名是文件 | `D6`·不以 `h` 开头 | `D7`·相对路径穿越 | `D8`·父目录锚 | `D9`·`h` + 路径穿越 | `D10`·反斜杠穿越 | `D11`·冒号(盘符/ADS 面) | `D12`·百分号与点 | `D13`·尾随空格 | `D14`·空串 | `D15`·整型元素 | `D16`·布尔元素 | `D17`·`null` 元素 | `D18`·嵌套数组元素 | `D19`·一好一坏(存在性拒面) | `D20`·空列表(声明无依赖) | `D21`·python 侧分类分布非退化(`accept`/`fmt_reject`/`exist_reject` 三态皆现)——`D1–D20` 均为「两侧逐项一致」,`D21` 是分布非退化 |
615
+ | `E1` / `E2` | 1 + 1 | `E1`·格式闸拦截后池中不新增任务目录(不静默写入/不降级为无依赖) | `E2`·存在性闸拦截后池中不新增任务目录(不静默写入) |
616
+ | `F1` | 1 | `F1`·缺省不带 `depends_on` → `ok=True` 且 spec 不含该键(缺省不写) |
617
+ | `G1` | 1 | `G1`·非列表(裸字符串)被拒且原因含「列表」 |
618
+ | `H1` / `I1` | 1 + 1 | `H1`·`orch._spawn` 透传 `depends_on` 进子 spec | `I1`·`orch._spawn` 缺省不写 `depends_on` |
619
+
620
+ **按上表复核 §4.1 的 H-6 变异红项数**(**构成说明由复核环节独立复算得出**,见 §5.1 H-6 格的「我用两侧判定独立复算了这些数字」):关落盘分支 → 红 `A:4`=`A1–A4`;关格式闸 → 红 `{B:10, D:14, E:1}`=B 十条全红 + **D 的 13 条 `fmt_reject` 项 + `D21` 分布非退化(13+1=14)** + `E1`;关存在性闸 → 红 `{C:2, D:4, E2:1}`=`C1`/`C2` + **D 的 3 条 `exist` 项 + `D21`(3+1=4)** + `E2`;关类型闸 → 红 `G:1`=`G1`;关「`deps is None` → 不校验不写」→ 红 `{A:4, F:1, I:1}`;关 orch 白名单 → 红 `H:1`=`H1`。
621
+
622
+ ### A.2 CH-1 守卫 `md_cg/test_rank_parity_score_mode.py`(40 条)
623
+
624
+ | 组 | 条数 | 标签·断言原文 |
625
+ |---|---|---|
626
+ | `G0`(隔离与前置自证) | 3 | `G0a` 辅助根落在守卫临时目录(绝不触真实凭据/密钥面) | `G0b` 口径类 env 干净:本守卫确实在**缺省态**上验证 | `G0c` 变异基线源 = 当前工作区源码(非 git HEAD/提交快照) |
627
+ | `G1`(契约①:缺省态即 10/10/10) | 7 | `G1a` 临时库建成 30 节点(正对照:夹具不空转) | `G1b` 缺省态退出码 0(口径已接线:两侧同钉 jaccard) | `G1c` 逐位一致 10/10(修前缺省态 7/10) | `G1d` 集合一致 10/10 | `G1e` top-1 一致 10/10(修前 7/10) | `G1f` 无 DIFF 行(三条伪差异已消失) | `G1g` 头部行印出两侧实际口径(自描述:`score=jaccard=rust jaccard`) |
628
+ | `G1b`(契约①:完全缺省调用) | 3 | `G1b-1` 缺省调用退出码 0 | `G1b-2` 缺省调用逐位/集合/top-1 = 10/10/10 | `G1b-3` 无 DIFF 行 |
629
+ | `G2`(契约②:漂移变响) | 7 | `G2a` 非 0 退出(口径不一致不得继续对拍) | `G2b` 退出码 = 3(口径不一致专用码,与逐位劈叉 1 区分) | `G2c` 打印口径不一致判定 | `G2d` 打印 Python 侧**实际**口径 = legacy(读回值,非假设) | `G2e` 打印 Rust 侧**实际**口径 = jaccard(回读自被拉起进程) | `G2f` 打印修复提示 | `G2g` **不打印逐位读数**(未静默给出低分——修前形态即此处静默) |
630
+ | `G3`(结构面) | 16 | `G3a` harness 口径**唯一单点**常量 `SCORE_MODE = "jaccard"` 在位 | `G3b` 顶部用法注释写明缺省口径 = jaccard(与 eval 面同判据) | `G3c` Python 侧经**既有** `eval_common.py::use_jaccard()` 注入(非自造开关) | `G3d` 评测面单点 `use_jaccard` 本体仍是 `m.SCORE_MODE = "jaccard"` | `G3e` Rust 侧 argv 显式钉住口径(`"--score", score`),不吃 `Config::default()` | `G3f` harness 回读 Rust 侧自报口径(`rust_reported_score` / `info.score`) | `G3g` `rust/src/serve.rs` 的 `info` 面回带 `score` | `G3h` engine 暴露实际生效口径的访问器 | `G3i` 口径标签映射单点(`main.rs` 转调 `engine::score_label`,与 serve 同源) | `G3j` **负向锚点**:Python 产品缺省仍是 legacy | `G3k` **负向锚点**:Rust `Cfg` 缺省仍是 `jaccard: true` | `G3l` 前置:本进程内 `mdcg.SCORE_MODE` 为产品缺省 legacy | `G3m` 行为自证:缺省态下 pin 后读回口径 = jaccard(且无冲突) | `G3n` 行为自证:模块级 `SCORE_MODE` 实际被拨到 jaccard | `G3o` env 声明冲突时返回冲突说明且实际口径仍为 legacy(不静默覆盖) | `G3p` `--ab` 路径头部自描述口径(不再隐式吃缺省) |
631
+ | `G4`(fail-closed:过期二进制) | 4 | `G4a` 退出码 = 4(口径不可读专用码) | `G4b` 打印「口径不可读」判定 | `G4c` 给出可执行的重编提示 | `G4d` 不给逐位读数(读不到对方口径不得继续对拍) |
632
+
633
+ **按上表复核 §4.1 的 CH-1 变异红项**:变异1(撤 `use_jaccard`)红 10 = `G1b`/`G1c`/`G1d`/`G1e`/`G1g`/`G1b-1`/`G1b-2`/`G3c`/`G3m`/`G3n`;变异2(撤对照闸)红 6 = `G2b`/`G2c`/`G2d`/`G2e`/`G2f`/`G2g`。
634
+
635
+ ### A.3 C-3 守卫 `md_cg/test_c3_transient_read_negative.py`(43 条)
636
+
637
+ | 组 | 条数 | 标签·断言原文 |
638
+ |---|---|---|
639
+ | `G0`(隔离与前置自证) | 3 | `G0a` 读缓存默认开(C-3 的成立前提) | `G0b` 令牌库落在守卫临时目录(绝不触真实凭据) | `G0c` 变异基线源 = 当前工作区源码(非 git HEAD/提交快照) |
640
+ | `G1`(主判据 + 记账 + 代价面 + 三态标签) | 11 | `G1a` 前置:无故障时查询命中全部 3 节点 | `G1a2` 前置:成功结果已入缓存(该 path 有缓存条目) | `G1b` 读失败 fail-closed:不可读节点不参与检索(不泄漏半读内容),同池其余节点不受累(可隔离) | **`G1c`**(定点变异红项的靶心):【②】负结果不入缓存:该 path 无缓存条目(修前为字面 `(gen,(None,None))` 的固化条目) | `G1d`【③】不得静默:瞬时读失败计入模块级计数且样本含 `(path, 异常类型, errno)` | `G1e`【②代价面】重试有界(稳态一次查询):失败 path 恰 1 次 `open`,成功节点零重读 | `G1f`【①】三态标签实测:瞬时读失败 → 第三元素 = `READ_FAIL_TRANSIENT` | `G1g`【②】释放后**首次**查询即命中(瞬态窗口为零) | **`G1h`**:撕裂消除——`cg.get` 直读与 `search` 同批可见(修前「get 能读、search 搜不到」) | `G1i`【②范围】终态「真缺」**仍入缓存**(`(gen,(None,None))`) | `G1j`【①】三态标签实测:`FileNotFoundError` → 终态(第三元素 `None`) |
641
+ | `G2`(无三态面载体的保守侧) | 3 | `G2a` 回落分支在位:`_read_uncached` 仍是穿透缓存的原始二态读 | `G2b` 成功结果照旧入缓存(二次读零重读) | `G2c` 无判别面时**保守不接纳**空结果 |
642
+ | `G3`(无故障路径三形态逐位一致) | 7 | `G3pre`×4 构造期望命中(镜湖 → `['c3_n01']`;霜桥 → `['c3_n02']`;碧玺 → `['c3_n05']`;共用词 → 8 节点全命中;oracle 来自夹具构造而非被测输出) | `G3a` 对照 B 确为「缓存关」形态(无 `_read_cache` 属性) | `G3b`【④】缓存开 == 缓存关:逐位一致 | `G3c`【④】修复后 == 修复前接纳口径(变异体):无故障路径逐位一致 |
643
+ | `G4`(盘上真值独立 oracle) | 1 | `G4a`【④】`get` 的 content/frontmatter 与盘上原始文件逐字一致(4 节点全过;oracle 只做文件字节比对,不经 `_read`/`_read_status`) |
644
+ | `G5`(单点结构) | 7 | `G5a` 判别函数单点:`fsutil.classify_read_failure` 恰好一处定义 | `G5b` 判别**调用**单点:`mdcg` 全文件仅一处调用 | `G5c` 缓存层不重判(不捕获 `OSError`、不做异常类型判别、不调判别函数) | `G5d` 接纳判据按**标签**而非返回值形状 | `G5e` 二态对外面单点转发:`_read` 恰为 `_read_status` 的前两项投影 | `G5f` 记账口单点:`mdcg` 内 `_note_read_oserror` 恰好一处定义 | `G5g` 记账面与 N225 坏行记账同模块同风格并存 |
645
+ | `G6`(记账面) | 6 | `G6a` 记账面可重置 | `G6b` 记账:计数累加 + 样本三元组 | `G6b2` 告警面:失败时向 stderr 写一行 | `G6c` 样本有界、计数不受限 | `G6d` 告警限流:101 次失败只写 31 行 | `G6e` 记账面复位 |
646
+ | `G7`(Windows 实测 `ctypes.WinDLL` 独占句柄) | 5 | `G7a` 注入生效:`CreateFileW(dwShareMode=0)` 独占持住节点 md 文件 | `G7b` 持锁期搜索 **miss** | **`G7c`** 持锁期负结果不入缓存(修前此处为 `(gen,(None,None))` 固化条目) | **`G7d`** 释放句柄后**首次**查询即命中(瞬态窗口为零) | `G7e` 持锁期记账可见(计数 ≥ 1) |
647
+
648
+ **按上表复核 §4.1 的 C-3 变异红项**:`C-3a` 红 8 = `G1c`/`G1d`/`G1e`/`G1f`/`G1g`/`G1h`/`G7c`/`G7d`;`C-3b` 红 9 = 上列 8 项 + `G7e`。
649
+
650
+ ---
651
+
652
+ ## 附B:本报告执行的动作留痕
653
+
654
+ | 动作 | 命令 / 手段 | 性质 |
655
+ |---|---|---|
656
+ | L1 直跑:H-6 守卫正向 | `python -X utf8 -m hive.test_h6_mcp_depends_on` | 只读(守卫夹具全在 `tempfile.mkdtemp` 临时池;**风险=无/单次/可逆**) |
657
+ | L1 直跑:H-6 变异自证 | `python -X utf8 -m hive.test_h6_mcp_depends_on --branch-baseline` | 同上 |
658
+ | L1 直跑:CH-1 守卫正向 | `python -X utf8 -m md_cg.test_rank_parity_score_mode` | 只读(临时库;同上) |
659
+ | L1 直跑:CH-1 变异自证 | `python -X utf8 -m md_cg.test_rank_parity_score_mode --mutate` | 同上 |
660
+ | L1 直跑:C-3 守卫正向 | `python -X utf8 -m md_cg.test_c3_transient_read_negative` | 只读(临时库;同上) |
661
+ | L1 直跑:C-3 变异自证 | `python -X utf8 -m md_cg.test_c3_transient_read_negative --mutate` | 同上 |
662
+ | L1 直跑:python 全量 | `python -X utf8 scripts/run_tests.py` | 只读(合成/临时库;同上) |
663
+ | L1 直跑:修后对拍三态 | `python -X utf8 scripts/rank_parity.py --exe …`(另加 `MDCG_UNIFY_QUERY=0` / `MDCG_SCORE_MODE=legacy` 两态) | 只读(库根 `tempfile.mkdtemp`;同上) |
664
+ | L1 直跑:修前对拍三态(**临时副本**) | `git show HEAD:scripts/rank_parity.py` → 写 `%TEMP%` → 仅改 `_REPO` 一行 → `PYTHONPATH=<repo> python -X utf8 …`(缺省 / `MDCG_UNIFY_QUERY=0` / `MDCG_SCORE_MODE=jaccard` / 两变量同设) | 只读(**工作区文件未被读写为实验体**;构建/库根全在临时目录) |
665
+ | L1 直跑(**本轮修订新增**):三处守卫重跑并**捕获全部标签** | `python -X utf8 -m hive.test_h6_mcp_depends_on`(43 条标签)、`… -m md_cg.test_rank_parity_score_mode`(40)+ `--mutate`、`… -m md_cg.test_c3_transient_read_negative`(43)+ `--mutate` | 只读(夹具全在 `tempfile.mkdtemp`;**stdout 经 python 落临时文件后再 Read**,以规避中文经 shell 管道被 GBK 化) |
666
+ | L1 直跑(**本轮修订新增**):`--ab` 冲突态与常规态 | `MDCG_SCORE_MODE=legacy python -X utf8 scripts/rank_parity.py --exe rust/target/release/mdcg-eval.exe --dataset scripts/retrieval_dataset.json --ab`(另跑不设 env 的同命令) | 只读(库根 `tempfile.mkdtemp`) |
667
+ | 只读核对(**本轮修订新增**):在役池逐目录审计 | 逐目录读 `hive/jobs/*/spec.json` 与 `status.json`,筛 `model=='guard-model'`;连续两次 `os.listdir` 观察 `_serve.tmp20528` 的瞬时性 | 只读(**未对该池发起任何写**) |
668
+ | 只读核对 | `git status --porcelain`、`git rev-parse HEAD`、`git diff --stat`、`git diff -U0 rust/src/main.rs`、`git show HEAD:rust/src/main.rs`、`git show HEAD:scripts/rank_parity.py`、`ls`、`grep -n`、`wmic process … hive.exe`、`os.listdir(hive/jobs)` ×2、`Read` 若干 | 只读 |
669
+ | 落盘 | 本文件(`docs/eval/优化第二批_依赖透传与对拍口径与负缓存_v1.0.md`) | **唯一写操作**(本轮修订亦只改本文件) |
670
+
671
+ ---
672
+
673
+
674
+ **纪律声明**(按工作纪律 0.2,未输出即视为未执行):
675
+
676
+
677
+
678
+ - 按工作纪律第 4 条: 根因纪律——先取证现场不猜测; 根因找到并验证后归档认知图并补不适用条件。
679
+ - 按工作纪律第 5 条: 验证纪律——入库前必须过回放/断言/回归验证, 未验证不固化。
680
+ - 按工作纪律第 8 条: 中文思考——中文书写; 复杂(新奇/挑战/曾受批评/高信息差)→「我们需要」交流确认互补盲区; 简单→「让我」快速执行不空耗; 每段推理开篇用中文短语锚定语言。
681
+ - 按工作纪律第 15 条: 命令执行统一走python——argv列表+显式UTF-8+PYTHONUTF8=1, 不经Windows shell, 规避GBK解码异常。(本次 `git`/`wmic` 等原生程序调用由内置 Bash 工具直出,属跨进程解码面;报告内结论所依据的关键读数均取自 `python -X utf8` 包装的套件与对拍,GBK 风险面为 `wmic` 与 `grep` 的中文标签管道——已在正文中以结构标签而非原文引用规避。)
682
+ - 按工作纪律第 17 条: 任务派发统一走蜂巢——任何执行性任务经蜂巢 spawn/submit 执行并留痕(spec/status/result), agent本体只做编排; 宿主自带subagent/team不是等价通道, 兜底须声明。L1只读判定(产物落点=不改仓库/外部状态)可直跑, 须输出「L1 直跑:<命令> — 风险/频次/可逆性」留痕。
683
+ - 按工作纪律第 18 条: 工作区索引优先——查工作区文件先读 WORKSPACE_INDEX.md(仓根, 管线生成); 无则先跑 scripts/workspace_index.py --write 生成再读, 不以重复全盘浏览代替。(本次为**已明确路径的单文件操作**,属该条「不适用」面;工作区结构由 `ls docs/eval/` 与 `git status` 定位。)