@furongjun1999/dsh-memory 0.4.8 → 0.4.9

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 (231) hide show
  1. package/README.md +54 -26
  2. package/codebuddy/CODEBUDDY.md +196 -195
  3. package/codebuddy/README.md +13 -1
  4. package/codebuddy/mcp.json +9 -0
  5. package/docs/GBrain/345/217/257/345/200/237/351/211/264/347/202/271_/347/201/265/346/236/242/350/220/275/347/202/271/344/272/244/346/216/245_20260919.md +169 -0
  6. package/docs/README.md +1 -1
  7. package/docs/discipline/harnesses.yaml +18 -7
  8. package/docs/discipline/templates/full.md.tmpl +4 -3
  9. package/docs/experiments/linkref_backfill/candidates_20260917.json +726 -0
  10. package/docs/experiments/linkref_backfill/candidates_internal_20260917.json +602 -0
  11. package/docs/experiments/linkref_backfill/candidates_internal_v2.json +603 -0
  12. package/docs/experiments/linkref_backfill/candidates_secret_20260917.json +884 -0
  13. package/docs/experiments/linkref_backfill/candidates_secret_v2.json +789 -0
  14. package/docs/hive//345/244/232/347/253/257harness/351/200/232/344/277/241/345/245/221/347/272/246_v0.1.md +42 -0
  15. package/docs/hive//346/243/200/347/264/242/346/224/266/346/225/233/345/256/236/346/265/213/344/270/216S1b/350/256/276/350/256/241_v0.1.md +43 -0
  16. 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 +102 -0
  17. package/docs/hive//347/234/237/345/256/236/345/272/223/347/253/257/345/210/260/347/253/257/345/256/236/346/265/213_S1b/344/270/216/345/217/254/345/233/236/346/235/203/350/241/241_v0.1.md +57 -0
  18. package/docs/hive//347/234/237/345/256/236/345/272/223/347/253/257/345/210/260/347/253/257/345/256/236/346/265/213_S7/345/200/222/346/216/222/345/200/231/351/200/211/345/261/202_v0.1.md +126 -0
  19. package/docs/hive//350/234/202/345/267/242/345/217/214/345/256/236/344/276/213/344/272/222/351/252/214_/350/256/276/350/256/241/345/256/232/347/250/277.md +503 -0
  20. package/docs/mdcg/D_meta_/345/267/245/347/250/213/345/214/226/346/226/271/346/241/210_v0.2.md +216 -0
  21. package/docs/mdcg/README/350/257/246/347/273/206/347/211/210_v0.4.5.md +631 -625
  22. package/docs/mdcg//344/273/243/347/240/201/350/257/204/345/256/241/344/270/216/346/235/241/344/273/266/345/214/226/346/263/250/351/207/212_/345/245/221/347/272/246_v0.1.md +82 -0
  23. package/docs/mdcg//345/205/250/345/272/223/344/273/243/347/240/201/350/257/204/345/256/241/344/270/216/346/235/241/344/273/266/345/214/226/346/263/250/351/207/212_/350/256/241/345/210/222_v0.1.md +600 -0
  24. 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 +47 -45
  25. package/docs/mdcg//345/255/220/344/273/243/347/220/206/351/205/215/347/275/256/346/240/207/345/207/{206_v0.4.md → 206_v0.5.md} +92 -4
  26. 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 +172 -0
  27. package/docs/mdcg//347/216/257/344/272/214_/347/231/275/347/256/261/345/241/253/345/205/205/346/265/201/346/260/264/347/272/277_v0.1.md +31 -0
  28. package/docs/mdcg//350/267/250/347/253/257/351/252/214/350/257/201/344/270/216/345/220/214/346/255/245/345/215/217/350/256/256_v0.1.md +93 -0
  29. package/docs/theory//345/271/266/345/217/221/345/277/205/347/204/266/346/200/247/347/220/206/350/256/272_v0.2.md +2 -2
  30. package/docs/theory//347/220/206/350/256/272_/346/234/272/345/210/266_/344/273/243/347/240/201_/345/256/236/351/252/214_/347/274/272/345/217/243/347/237/251/351/230/265_v0.1.md +3 -3
  31. package/docs/theory//350/256/244/347/237/245/344/273/243/347/220/206/344/270/216/346/224/266/346/225/233/347/273/223/346/236/204_/346/235/241/344/273/266/350/256/272/351/207/215/346/236/204_v0.1.md +2 -2
  32. 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 +434 -433
  33. package/docs//347/201/265/346/236/242/350/207/252/346/210/221/346/224/271/350/277/233/345/267/245/344/275/234/350/256/241/345/210/222_/345/244/226/351/203/250/347/240/224/347/251/266/347/263/273/345/210/227/345/220/270/346/224/266_v1_20260919.md +286 -0
  34. package/dsh/README.md +33 -0
  35. package/dsh/cordis.yml.example +13 -7
  36. package/dsh/hive-mcp-probe.mjs +94 -0
  37. package/dsh/hive-mcp.example.yml +62 -0
  38. package/dsh/update-lingshu.bat +11 -0
  39. package/dsh/update-lingshu.ps1 +337 -0
  40. package/lib/hooks.d.ts +3 -0
  41. package/lib/hooks.js +17 -23
  42. package/lib/index.d.ts +4 -2
  43. package/lib/index.js +29 -6
  44. package/lib/lib/datapath.d.ts +76 -1
  45. package/lib/lib/datapath.js +199 -13
  46. package/lib/lib/mdcg_client.d.ts +6 -3
  47. package/lib/lib/mdcg_client.js +6 -5
  48. package/lib/lib/mutual.js +4 -4
  49. package/lib/lib/token_store.js +4 -5
  50. package/md_cg/audit.py +17 -2
  51. package/md_cg/autonomy.py +86 -15
  52. package/md_cg/backfill.py +36 -1
  53. package/md_cg/backfill_bigdomain.py +34 -0
  54. package/md_cg/bench6_arms.py +28 -1
  55. package/md_cg/bench6_common.py +10 -1
  56. package/md_cg/bench6_competitors.py +6 -1
  57. package/md_cg/bench_axis_domain.py +9 -1
  58. package/md_cg/bench_blind_comp.py +7 -1
  59. package/md_cg/bench_en_atoms_public.py +9 -0
  60. package/md_cg/bench_governance.py +348 -0
  61. package/md_cg/bench_lme_zh.py +16 -1
  62. package/md_cg/bench_locomo.py +2 -1
  63. package/md_cg/bench_locomo_zh.py +16 -1
  64. package/md_cg/bench_locomo_zh_public.py +4 -1
  65. package/md_cg/bench_longmem.py +2 -1
  66. package/md_cg/bench_membench.py +27 -1
  67. package/md_cg/bench_p0.py +4 -1
  68. package/md_cg/bench_progressive.py +13 -1
  69. package/md_cg/bench_role_views.py +238 -0
  70. package/md_cg/bench_task_ab.py +8 -1
  71. package/md_cg/bench_task_ab_llm.py +13 -1
  72. package/md_cg/bench_unified_en.py +6 -1
  73. package/md_cg/bench_zh_mad.py +20 -1
  74. package/md_cg/blindspot_tickets.py +123 -0
  75. package/md_cg/branches.py +12 -1
  76. package/md_cg/build_postings.py +73 -0
  77. package/md_cg/ccgc.py +67 -2
  78. package/md_cg/census.py +5 -1
  79. package/md_cg/chain.py +24 -3
  80. package/md_cg/codeindex.py +134 -17
  81. package/md_cg/coldverify.py +265 -0
  82. package/md_cg/comment_gate.py +338 -0
  83. package/md_cg/cond_compose.py +190 -0
  84. package/md_cg/cond_facts.py +155 -0
  85. package/md_cg/cond_template.json +107 -0
  86. package/md_cg/condition_anchor.py +143 -0
  87. package/md_cg/conformance.py +69 -4
  88. package/md_cg/consistency.py +24 -1
  89. package/md_cg/consolidate.py +53 -2
  90. package/md_cg/corpus.py +4 -0
  91. package/md_cg/crosscheck.py +42 -2
  92. package/md_cg/crypto.py +35 -1
  93. package/md_cg/d_meta.py +310 -0
  94. package/md_cg/datapath.py +201 -26
  95. package/md_cg/docindex.py +122 -1
  96. package/md_cg/eval_common.py +29 -1
  97. package/md_cg/evidence.py +27 -1
  98. package/md_cg/evolution.py +21 -1
  99. package/md_cg/export.py +11 -1
  100. package/md_cg/forgetting.py +23 -1
  101. package/md_cg/fsutil.py +18 -1
  102. package/md_cg/hotcache.py +214 -0
  103. package/md_cg/hyperedge.py +251 -0
  104. package/md_cg/identity.py +18 -1
  105. package/md_cg/insight.py +17 -1
  106. package/md_cg/lexicon/build_cedict_en_zh.py +9 -0
  107. package/md_cg/lexicon/build_standard_en.py +171 -168
  108. package/md_cg/lexicon/expand_en_zh.py +6 -0
  109. package/md_cg/lifecycle.py +12 -1
  110. package/md_cg/linkref.py +281 -0
  111. package/md_cg/links.py +29 -1
  112. package/md_cg/mcp_server.py +362 -43
  113. package/md_cg/md_whitebox.py +53 -1
  114. package/md_cg/mdcg.py +1003 -27
  115. package/md_cg/mdcos.py +558 -36
  116. package/md_cg/metacognition.py +37 -2
  117. package/md_cg/migrate.py +4 -0
  118. package/md_cg/migrate_aeis.py +221 -213
  119. package/md_cg/migrate_roleplay.py +8 -0
  120. package/md_cg/migrate_wisdom_graph.py +14 -1
  121. package/md_cg/mreview/__main__.py +3 -0
  122. package/md_cg/mreview/bundle.py +8 -0
  123. package/md_cg/mreview/candidates.py +9 -0
  124. package/md_cg/mreview/govern.py +21 -1
  125. package/md_cg/mreview/locate.py +34 -0
  126. package/md_cg/mreview/pipeline.py +29 -1
  127. package/md_cg/mreview/ruleset.py +16 -1
  128. package/md_cg/nodefile.py +233 -3
  129. package/md_cg/pooling.py +23 -1
  130. package/md_cg/postings.py +298 -0
  131. package/md_cg/predict.py +89 -9
  132. package/md_cg/progressive.py +3 -0
  133. package/md_cg/protect.py +14 -1
  134. package/md_cg/protocol.py +372 -0
  135. package/md_cg/provenance.py +262 -0
  136. package/md_cg/reach.py +453 -0
  137. package/md_cg/refindex.py +47 -2
  138. package/md_cg/refine.py +20 -1
  139. package/md_cg/roleviews.py +89 -0
  140. package/md_cg/routing.py +76 -0
  141. package/md_cg/scrub.py +63 -2
  142. package/md_cg/security.py +26 -1
  143. package/md_cg/self_state.py +64 -1
  144. package/md_cg/selfreport.py +151 -0
  145. package/md_cg/semantic/canonical.py +5 -0
  146. package/md_cg/semantic/en_normalizer.py +364 -355
  147. package/md_cg/semantic/zh_en_atoms.py +139 -136
  148. package/md_cg/signer.py +41 -1
  149. package/md_cg/sources.py +583 -547
  150. package/md_cg/statushdr.py +179 -0
  151. package/md_cg/stg.py +59 -18
  152. package/md_cg/subgraph.py +23 -0
  153. package/md_cg/sustain.py +56 -1
  154. package/md_cg/tasks.py +26 -2
  155. package/md_cg/test_autonomy.py +26 -0
  156. package/md_cg/test_bench_governance.py +102 -0
  157. package/md_cg/test_blindspot_tickets.py +166 -0
  158. package/md_cg/test_ccgc.py +10 -0
  159. package/md_cg/test_codeindex.py +338 -0
  160. package/md_cg/test_comment_gate.py +187 -0
  161. package/md_cg/test_cond_compose_anchors.py +76 -0
  162. package/md_cg/test_condition_anchor.py +82 -0
  163. package/md_cg/test_d_meta.py +412 -0
  164. package/md_cg/test_datapath_root.py +188 -0
  165. package/md_cg/test_gain_gate.py +47 -1
  166. package/md_cg/test_hot_cold.py +187 -0
  167. package/md_cg/test_hyperedge.py +245 -0
  168. package/md_cg/test_linkref.py +306 -0
  169. package/md_cg/test_md_access_parity.py +15 -3
  170. package/md_cg/test_mr_m1.py +108 -18
  171. package/md_cg/test_mr_m3.py +8 -1
  172. package/md_cg/test_p26_refindex.py +49 -20
  173. package/md_cg/test_p27_docindex.py +236 -2
  174. package/md_cg/test_p2_mcp.py +1 -1
  175. package/md_cg/test_p31_insight.py +24 -0
  176. package/md_cg/test_p44_md_whitebox.py +14 -1
  177. package/md_cg/test_protocol.py +243 -0
  178. package/md_cg/test_reach.py +378 -0
  179. package/md_cg/test_reach_keys.py +201 -0
  180. package/md_cg/test_reach_meta_exits.py +145 -0
  181. package/md_cg/test_read_clip.py +8 -4
  182. package/md_cg/test_retr_s1.py +340 -0
  183. package/md_cg/test_retr_s1b.py +209 -0
  184. package/md_cg/test_retr_s3.py +194 -0
  185. package/md_cg/test_retr_s4.py +163 -0
  186. package/md_cg/test_retr_s5.py +200 -0
  187. package/md_cg/test_retr_s6.py +157 -0
  188. package/md_cg/test_retr_s7.py +385 -0
  189. package/md_cg/test_retr_s8_time.py +316 -0
  190. package/md_cg/test_retr_s9_edges.py +286 -0
  191. package/md_cg/test_retr_s9_entity_ctx.py +175 -0
  192. package/md_cg/test_review_conformance.py +59 -2
  193. package/md_cg/test_role_views.py +354 -0
  194. package/md_cg/test_trust.py +361 -0
  195. package/md_cg/test_units_poll.py +71 -0
  196. package/md_cg/test_v14_fixes.py +397 -0
  197. package/md_cg/test_validity_filter.py +280 -0
  198. package/md_cg/test_wisdom_md_store.py +7 -3
  199. package/md_cg/test_writepipe.py +5 -1
  200. package/md_cg/theory.py +16 -1
  201. package/md_cg/tokens.py +40 -8
  202. package/md_cg/tool_face.py +13 -2
  203. package/md_cg/trust.py +943 -0
  204. package/md_cg/twophase.py +12 -1
  205. package/md_cg/units.py +129 -10
  206. package/md_cg/vision_evidence.py +24 -1
  207. package/md_cg/weights.py +24 -1
  208. package/md_cg/whitebox.py +32 -1
  209. package/md_cg/whitebox_kb/data/verify_cache.json +21210 -365
  210. package/md_cg/whitebox_kb/data/verify_savings.jsonl +5078 -0
  211. package/md_cg/whitebox_kb/wisdom/audit_log/chain_heat.json +10 -10
  212. package/md_cg/whitebox_kb/wisdom/code_compose.py +113 -6
  213. package/md_cg/whitebox_kb/wisdom/code_solidified.json +1 -1
  214. package/md_cg/whitebox_kb/wisdom/verifier.py +340 -55
  215. package/md_cg/whitebox_kb/wisdom/wisdom-book-cloud.db +0 -0
  216. package/md_cg/writelimit.py +18 -4
  217. package/md_cg/writepipe.py +178 -7
  218. package/package.json +2 -2
  219. package/skills/skills/designer-perspective/scripts/__pycache__/designer.cpython-310.pyc +0 -0
  220. package/skills/skills/designer-perspective/scripts/designer.py +17 -1
  221. package/skills/skills/designer-perspective/tests/selftest.py +3 -1
  222. package/src/hooks.ts +17 -21
  223. package/src/index.ts +33 -6
  224. package/src/lib/datapath.ts +211 -13
  225. package/src/lib/mdcg_client.ts +12 -8
  226. package/src/lib/mutual.ts +411 -411
  227. package/src/lib/token_store.ts +4 -5
  228. package/zcode/AGENTS.md +196 -195
  229. package/zcode/README.md +4 -0
  230. package/md_cg/whitebox_kb/wisdom/wisdom-book-cloud.db-shm +0 -0
  231. package/md_cg/whitebox_kb/wisdom/wisdom-book-cloud.db-wal +0 -0
@@ -0,0 +1,187 @@
1
+ # -*- coding: utf-8 -*-
2
+ """comment_gate 验收(环二入口)。
3
+
4
+ 验收口径:
5
+ 1. 唯一真源:阈值取 refine.GATE_MIN_PASS_RATE(本模块不再定义一份)
6
+ 2. 候选判据机械:只有「代码节点且正文缺生效条件」入池(有注释的那条不入池)
7
+ 3. 工单:确定性抽样(同 seed 同工单)+ 带源码落点(code_ref 坐标 + 落点规则)
8
+ 4. 只读纪律:apply 只落留痕,**不改任何节点**(改前改后内容 sha 相同)
9
+ 5. 闸门:<0.90 不放行、>=0.90 放行、无批次不放行
10
+ 6. 分派:run(action=comment_gate) 走只读工单;comment_gate_verdict 走闸门
11
+ """
12
+ from __future__ import annotations
13
+
14
+ import os
15
+ import sys
16
+ import tempfile
17
+
18
+ from . import codeindex, comment_gate, refindex, refine
19
+ from .mdcos import MdCGSecure
20
+ from .security import Principal
21
+
22
+ _ok = 0
23
+ _bad = []
24
+
25
+
26
+ def _check(name, cond, detail=""):
27
+ global _ok
28
+ if cond:
29
+ _ok += 1
30
+ print(" ok %s" % name)
31
+ else:
32
+ _bad.append("%s %s" % (name, detail))
33
+ print(" FAIL %s %s" % (name, detail))
34
+
35
+
36
+ ANNOTATED = ('"""样本。"""' + chr(10) + chr(10) + chr(10) +
37
+ "# 生效条件:入参 x 为整数" + chr(10) +
38
+ "def with_cond(x):" + chr(10) + " return x + 1" + chr(10))
39
+ PLAIN = ('"""样本。"""' + chr(10) + chr(10) + chr(10) +
40
+ "def no_cond(x):" + chr(10) + " return x + 2" + chr(10))
41
+
42
+
43
+ def _mk_graph(root):
44
+ p = Principal(tenant="default", actor="t_test", role="designer",
45
+ can_write=True, can_admin=True)
46
+ return MdCGSecure(root, principal=p)
47
+
48
+
49
+ def main():
50
+ print("=" * 68)
51
+ print("md_cg comment_gate 验收(代码符号条件化注释抽样闸门)")
52
+ print("=" * 68)
53
+ tmp = tempfile.mkdtemp(prefix="mdcg_comment_gate_")
54
+ root = os.path.join(tmp, "root")
55
+ code = os.path.join(tmp, "code")
56
+ os.makedirs(code)
57
+ with open(os.path.join(code, "a.py"), "w", encoding="utf-8") as f:
58
+ f.write(ANNOTATED)
59
+ with open(os.path.join(code, "b.py"), "w", encoding="utf-8") as f:
60
+ f.write(PLAIN)
61
+ cg = _mk_graph(root)
62
+ items, errors, stats = refindex.index_dir(code, kind="code_ref",
63
+ ledger=refindex.Ledger(cg.root))
64
+ ids, _sens = refindex.add_items(cg, items, kind="code_ref", root=code)
65
+ cg.flush()
66
+ print("索引条目=%d 节点=%d 错误=%d" % (len(items), len(ids), len(errors)))
67
+
68
+ _check("阈值唯一真源=refine.GATE_MIN_PASS_RATE",
69
+ comment_gate.GATE_MIN_PASS_RATE == refine.GATE_MIN_PASS_RATE,
70
+ str(comment_gate.GATE_MIN_PASS_RATE))
71
+ by_name = {it["name"]: codeindex.node_id(it) for it in items}
72
+ cands, cmeta = comment_gate.candidates(cg)
73
+ # 注:模块级条目同样缺生效条件 → 也是合法候选;故按符号名判定而非计条数
74
+ _check("候选判据机械:缺生效条件者入池、已注释者不入池",
75
+ by_name["no_cond"] in cands and by_name["with_cond"] not in cands,
76
+ "cands=%s no=%s with=%s" % (len(cands), by_name["no_cond"],
77
+ by_name["with_cond"]))
78
+ _check("候选池状态如实上报(pool/candidates 与实取一致)",
79
+ cmeta.get("pool", 0) == len(items) and cmeta.get("candidates") == len(cands),
80
+ str(cmeta))
81
+ p1 = comment_gate.plan(cg, n=20, seed="cmt-1")
82
+ p2 = comment_gate.plan(cg, n=20, seed="cmt-1")
83
+ _check("同 seed 工单确定性(sample 与 sha 一致)",
84
+ p1["sample"] == p2["sample"] and p1["sample_sha"] == p2["sample_sha"],
85
+ str(p1["sample"]))
86
+ _check("工单只读(dry_run=True,不改节点)", p1["dry_run"] is True and p1["readonly"] is True)
87
+ it = next((x for x in p1["items"]
88
+ if (x.get("code_ref") or {}).get("name") == "no_cond"), {})
89
+ ref = (it.get("code_ref") or {})
90
+ _check("工单带源码落点坐标(path/lineno/end)",
91
+ ref.get("path") == "b.py" and ref.get("lineno") and ref.get("end"),
92
+ str(ref))
93
+ _check("工单带落点规则(两窗口,契约 §三.2)",
94
+ "leading" in str(it.get("landing_rule") or "")
95
+ and "body" in str(it.get("landing_rule") or ""),
96
+ str(it.get("landing_rule"))[:80])
97
+ _check("工单缺项口径=缺生效条件",
98
+ it.get("ccg_missing") == ["生效条件"], str(it.get("ccg_missing")))
99
+ _check("SPEC 四项核对清单与 0.90 闸门口径在案",
100
+ len(comment_gate.SPEC["review_items"]) == 4
101
+ and comment_gate.SPEC["gate"]["min_pass_rate"] == 0.90)
102
+
103
+ nid = by_name["no_cond"]
104
+ before = (cg.get(nid) or {}).get("content") or ""
105
+ r = comment_gate.apply(cg, n=20, seed="cmt-1", verdicts=["忠实"],
106
+ actor="t_test", note="自测")
107
+ after = (cg.get(nid) or {}).get("content") or ""
108
+ _check("apply 落留痕且通过率=1.0", r["ok"] and r["gate"]["pass_rate"] == 1.0,
109
+ str(r.get("gate")))
110
+ _check("apply 之后放行(>=0.90)", r["gate"]["expand_allowed"] is True)
111
+ _check("apply 不改节点(内容逐字相同)", before == after and before != "")
112
+ _check("留痕文件已落盘", os.path.exists(os.path.join(root, comment_gate.LOG_NAME)))
113
+ g1 = comment_gate.gate(cg)
114
+ _check("gate 复算通过率=1.0 且放行", g1["pass_rate"] == 1.0 and g1["expand_allowed"] is True,
115
+ str(g1))
116
+ r2 = comment_gate.apply(cg, n=20, seed="cmt-1", verdicts=[False, False, False],
117
+ actor="t_test", batch="low")
118
+ _check("低通过率(0/3)不放行且给原因",
119
+ r2["gate"]["expand_allowed"] is False and "rate" in str(r2["gate"]["reason"]),
120
+ str(r2["gate"]))
121
+ g2 = comment_gate.gate(cg, batch="low")
122
+ _check("gate(batch=low) 复算为不放行", g2["expand_allowed"] is False, str(g2))
123
+ g3 = comment_gate.gate(cg, batch="不存在")
124
+ _check("无批次 → no_batch 不放行", g3["expand_allowed"] is False
125
+ and g3["reason"] == "no_batch", str(g3))
126
+ run1 = comment_gate.run(cg, "comment_gate", n=5)
127
+ _check("run(comment_gate) 走只读工单", run1["dry_run"] is True
128
+ and run1["action"] == "comment_gate")
129
+ from . import mcp_server
130
+ d1 = mcp_server._maintain_call(cg, {"op": "maintain", "action": "comment_gate", "n": 5})
131
+ _check("经 maintain 分派可达(op 面接线)",
132
+ d1.get("action") == "comment_gate" and d1.get("dry_run") is True
133
+ and d1.get("readonly") is True, str(d1.get("action")))
134
+ d2 = mcp_server._maintain_call(cg, {"action": "comment_gate_gate"})
135
+ _check("经 maintain 分派可取闸门(comment_gate_gate)",
136
+ "expand_allowed" in d2, str(sorted(d2.keys()))[:90])
137
+ from .mdcos import MdCGSecure as _S
138
+ from .security import AccessDenied as _AD
139
+ cg_low = _S(root, principal=Principal(tenant="default", actor="t_low",
140
+ role="record", can_write=True,
141
+ can_admin=False))
142
+ denied = False
143
+ try:
144
+ comment_gate.apply(cg_low, n=5, seed="cmt-1", verdicts=["忠实"])
145
+ except _AD:
146
+ denied = True
147
+ except Exception:
148
+ denied = False
149
+ _check("apply 需管理权(闸门自持在模块内,分发面不漏挂)", denied)
150
+ d3 = mcp_server._maintain_call(cg, {"action": "comment_gate_verdict"})
151
+ _check("经 maintain 分派可取闸门(别名 comment_gate_verdict)",
152
+ "expand_allowed" in d3, str(sorted(d3.keys()))[:90])
153
+ run2 = comment_gate.run(cg, "comment_gate_verdict")
154
+ _check("run(comment_gate_verdict) 走闸门", "expand_allowed" in run2)
155
+ raised = False
156
+ try:
157
+ comment_gate.run(cg, "nope")
158
+ except ValueError:
159
+ raised = True
160
+ _check("未知 action fail-closed", raised)
161
+ # ---- 源级候选枚举(绕开重索引代价;不依赖认知图)----
162
+ sp1 = comment_gate.plan_sources(code, n=20, seed="src-1")
163
+ _check("源级枚举可见未注释符号(不依赖认知图)",
164
+ sp1["examined"] >= 1 and sp1["candidates"] >= 1 and sp1["sampled"] >= 1,
165
+ "examined=%s cands=%s sampled=%s" % (sp1["examined"], sp1["candidates"],
166
+ sp1["sampled"]))
167
+ src_names = [it["name"] for it in sp1["items"]]
168
+ _check("源级工单排除已注释符号(no_cond 在、with_cond 不在)",
169
+ "no_cond" in src_names and "with_cond" not in src_names, str(src_names))
170
+ _check("源级工单带源码坐标(path/lineno/end)",
171
+ all((it["code_ref"].get("path") and it["code_ref"].get("lineno")
172
+ and it["code_ref"].get("end")) for it in sp1["items"]))
173
+ _check("源级抽样确定性(同 seed 同工单)",
174
+ comment_gate.plan_sources(code, n=20, seed="src-1")["items"] == sp1["items"])
175
+ _check("源级工单只读且声明模式",
176
+ sp1["dry_run"] is True and sp1["mode"] == "source_level")
177
+ _check("源级枚举经 run 分派可达",
178
+ comment_gate.run(cg, "comment_gate_sources", n=5)["mode"] == "source_level")
179
+ print()
180
+ print("PASS %d / FAIL %d" % (_ok, len(_bad)))
181
+ for b in _bad:
182
+ print(" - " + b)
183
+ return 1 if _bad else 0
184
+
185
+
186
+ if __name__ == "__main__":
187
+ sys.exit(main())
@@ -0,0 +1,76 @@
1
+ # -*- coding: utf-8 -*-
2
+ """cond_compose 行为锚点(在途 WIP 并集解)探针:脚本式,exit code 定成败。
3
+
4
+ 背景:2026-09-19 收口两线时,工作区残留一处 stash-pop 冲突(md_cg/cond_compose.py):
5
+ ours(HEAD)=compose 的「生效条件」注释;theirs(stash)=新增 behavior_anchors()。
6
+ 两侧新增互不重叠 → 并集解(本分支)。该函数当前**全库无调用**,故本探针只把
7
+ 「冲突解正确 + 函数行为与文档一致」钉住,配线与否由使用者裁决。
8
+
9
+ 用法:python -X utf8 -m md_cg.test_cond_compose_anchors
10
+ """
11
+ import os
12
+ import sys
13
+
14
+ sys.path.insert(0, os.path.dirname(os.path.dirname(os.path.abspath(__file__))))
15
+
16
+ from md_cg import cond_compose as cc # noqa: E402
17
+
18
+ passed = 0
19
+ failed = 0
20
+
21
+
22
+ def check(name, cond, detail=""):
23
+ global passed, failed
24
+ if cond:
25
+ passed += 1
26
+ print(" [PASS] " + name)
27
+ else:
28
+ failed += 1
29
+ print(" [FAIL] " + name + " " + detail)
30
+
31
+
32
+ def main():
33
+ # 1) 并集完整性:冲突两侧的东西都在,且文件里没有冲突标记
34
+ src = open(cc.__file__, encoding="utf-8").read()
35
+ check("并集:compose 与 behavior_anchors 同时在",
36
+ hasattr(cc, "compose") and hasattr(cc, "behavior_anchors"))
37
+ check("并集:无冲突标记", "<<<<<<<" not in src and ">>>>>>>" not in src)
38
+ check("并集:compose 的生效条件注释未丢", "调用 compose 时必须提供 rec" in src)
39
+
40
+ # 2) behavior_anchors 行为(按实现口径逐条断言)
41
+ rec = {"name": "f", "doc_head": " 计算 a 的摘要 ",
42
+ "guards": [{"early": True, "cond": "a"},
43
+ {"early": False, "cond": "a"},
44
+ {"early": True, "cond": "a and b"}],
45
+ "returns": ["a.strip()", "LIMIT + 1", "local_only"]}
46
+ doc, guards, rets = cc.behavior_anchors(rec, {"a"})
47
+ check("doc 取 doc_head 并去空白", doc == "计算 a 的摘要", repr(doc))
48
+ # explained_guards 的两道筛:early 必须为真;cond 内标识符必须全在 allowed∪BUILTINS∪self/cls
49
+ # (故 "a" 入选、"a and b" 因 b 不在 allowed 被剔、"a is None" 会因 is 不是 builtins 被剔)
50
+ check("guards 只留 early 且标识符合规者(走 explained_guards)",
51
+ [g.get("cond") for g in guards] == ["a"], str(guards))
52
+ check("returns 只留含 allowed 标识符者", rets == ["a.strip()"], str(rets))
53
+ _d2, _g2, rets2 = cc.behavior_anchors(rec, {"a", "LIMIT"})
54
+ check("allowed 含模块常量时其返回表达式入选(调用方负责传 入参∪常量)",
55
+ rets2 == ["a.strip()", "LIMIT + 1"], str(rets2))
56
+
57
+ # 3) 「只有形参清单、无任何行为锚点」→ 三元组全空(调用方据此可判 BLINDSPOT)
58
+ empty = cc.behavior_anchors({"name": "g", "guards": [], "returns": []}, {"x"})
59
+ check("无形为锚点时返回空三元组", empty == ("", [], []), str(empty))
60
+ check("缺失 doc_head/returns 键不抛异常",
61
+ cc.behavior_anchors({"name": "h"}, {"x"}) == ("", [], []))
62
+
63
+ # 4) 未回归:compose 仍能产出以「。」结尾的条件串
64
+ s = cc.compose({"name": "f", "required": ["a"], "optional": [], "externals": [],
65
+ "guards": [], "returns": ["a.strip()"], "doc_head": "摘要"})
66
+ check("compose 未回归(非空且以「。」结尾)",
67
+ isinstance(s, str) and s.endswith("。") and len(s) > 4, s[:60])
68
+
69
+ print("\ntest_cond_compose_anchors: %d 通过 / %d 失败" % (passed, failed))
70
+ return 0 if failed == 0 else 1
71
+
72
+
73
+ if __name__ == "__main__":
74
+ if hasattr(sys.stdout, "reconfigure"):
75
+ sys.stdout.reconfigure(encoding="utf-8")
76
+ sys.exit(main())
@@ -0,0 +1,82 @@
1
+ # -*- coding: utf-8 -*-
2
+ """condition_anchor 验收:四类裁决 + 边界(self/cls、kwonly、默认值常量、不可判)。
3
+
4
+ 验收口径:本模块只判「锚点是否存在」,不判语义正确性;不可判必须 BLINDSPOT,不得默认通过。
5
+ """
6
+ from __future__ import annotations
7
+
8
+ from . import condition_anchor as ca
9
+
10
+ _ok = 0
11
+ _bad = []
12
+
13
+
14
+ def _check(name, cond, detail=""):
15
+ global _ok
16
+ if cond:
17
+ _ok += 1
18
+ print(" ok %s" % name)
19
+ else:
20
+ _bad.append("%s %s" % (name, detail))
21
+ print(" FAIL %s %s" % (name, detail))
22
+
23
+
24
+ SRC_REQ = "def f(root, patterns=None):" + chr(10) + " return os.walk(root)" + chr(10)
25
+ SRC_KW = "def g(a, *, limit, mode=1):" + chr(10) + " return scan(a, limit, mode)" + chr(10)
26
+ SRC_CLS = "class C:" + chr(10) + " def m(self, x):" + chr(10) + " return x" + chr(10)
27
+ SRC_BARE = "def h():" + chr(10) + " return 1" + chr(10)
28
+ SRC_CONST = "def k(x=1):" + chr(10) + " return x + LIMIT" + chr(10)
29
+ SRC_BROKEN = "def n(:" + chr(10) + " pass" + chr(10)
30
+
31
+
32
+ def main():
33
+ print("=" * 68)
34
+ print("md_cg condition_anchor 验收(候选生效条件的锚点机械判据)")
35
+ print("=" * 68)
36
+ r = ca.judge("root 为可遍历路径", SRC_REQ)
37
+ _check("A1 锚定必需参数 → ANCHORED 且 ok", r["verdict"] == "ANCHORED" and r["ok"] is True, str(r))
38
+ _check("A2 锚点清单含 root(不含 patterns)",
39
+ r["anchors"] == ["root"] and "patterns" in r["optional"], str(r["anchors"]))
40
+ _check("A3 默认值参数归入 optional", r["optional"] == ["patterns"], str(r["optional"]))
41
+ r = ca.judge("limit 为正整数", SRC_KW)
42
+ _check("A4 kwonly 无默认值算必需参数", r["verdict"] == "ANCHORED" and r["anchors"] == ["limit"], str(r))
43
+ r = ca.judge("x 为整数", SRC_CLS)
44
+ _check("A5 class 内方法:self 被跳过、锚定 x", r["verdict"] == "ANCHORED" and r["anchors"] == ["x"], str(r))
45
+ r = ca.judge("LIMIT 已定义", SRC_CONST)
46
+ _check("A6 体内外部引用(常量)可作锚点", r["verdict"] == "ANCHORED" and r["anchors"] == ["LIMIT"], str(r))
47
+ r = ca.judge("该函数总是正确", SRC_REQ)
48
+ _check("A7 无锚点 → WEAK 且 ok=False(不默认通过)",
49
+ r["verdict"] == "WEAK" and r["ok"] is False, str(r))
50
+ r = ca.judge("源文件存在于本地仓", SRC_REQ)
51
+ _check("A8 索引元条件话术 → REJECT_META", r["verdict"] == "REJECT_META" and r["meta_marks"], str(r))
52
+ r = ca.judge("x 为整数", SRC_BARE)
53
+ _check("A9 无参数且无引用 → BLINDSPOT(不猜测)", r["verdict"] == "BLINDSPOT", str(r))
54
+ r = ca.judge("x 为整数", SRC_BROKEN)
55
+ _check("A10 源码不可解析 → BLINDSPOT", r["verdict"] == "BLINDSPOT", str(r))
56
+ r = ca.judge("root 为可遍历路径", SRC_REQ)
57
+ r2 = ca.judge("root 为可遍历路径", SRC_REQ)
58
+ _check("A11 判定确定性(同输入同结果)", r == r2)
59
+ _check("A12 prefix/suffix 仅回显、不参与判定",
60
+ ca.judge("root 为可遍历路径", SRC_REQ, prefix="【1】")["verdict"] == "ANCHORED")
61
+ b = ca.judge_batch([("a", "root 为可遍历路径", SRC_REQ),
62
+ ("b", "该函数总是正确", SRC_REQ),
63
+ ("c", "源文件存在", SRC_REQ)])
64
+ _check("A13 批量统计正确(ANCHORED/WEAK/REJECT_META 各 1)",
65
+ b["stats"].get("ANCHORED") == 1 and b["stats"].get("WEAK") == 1
66
+ and b["stats"].get("REJECT_META") == 1 and b["ok"] == 1, str(b["stats"]))
67
+ _r = ca.judge("tree 为 AST 节点", "class NoInit:" + chr(10) + " x = 1" + chr(10))
68
+ _check("A14 无 __init__ 的类不崩溃并给出裁决",
69
+ _r["verdict"] in ("ANCHORED", "WEAK", "BLINDSPOT"), str(_r))
70
+ _r = ca.judge("x 为整数", "class C:" + chr(10) + " def __init__(self, x):" + chr(10) + " self.x = x" + chr(10))
71
+ _check("A15 有 __init__ 的类按其形参锚定",
72
+ _r["verdict"] == "ANCHORED" and _r["anchors"] == ["x"], str(_r))
73
+ print()
74
+ print("PASS %d / FAIL %d" % (_ok, len(_bad)))
75
+ for x in _bad:
76
+ print(" - " + x)
77
+ return 1 if _bad else 0
78
+
79
+
80
+ if __name__ == "__main__":
81
+ import sys
82
+ sys.exit(main())