@furongjun1999/dsh-memory 0.4.7 → 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 (325) hide show
  1. package/README.md +130 -47
  2. package/codebuddy/CODEBUDDY.md +21 -10
  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/Pi/345/217/257/345/255/246/344/271/240/344/274/230/347/202/271_/347/201/265/346/236/242/345/244/247/350/204/221/346/224/271/350/277/233/344/272/244/346/216/245_20260915.md +144 -0
  7. package/docs/README.md +111 -0
  8. package/docs/discipline/harnesses.yaml +226 -152
  9. package/docs/discipline/templates/full.md.tmpl +61 -58
  10. package/docs/eval//347/254/254/344/270/211/346/226/271/351/252/214/350/257/201/346/212/245/345/221/212_LoCoMo_/347/201/265/346/236/242_.md +127 -0
  11. package/docs/eval//347/254/254/344/270/211/346/226/271/351/252/214/350/257/201/346/212/245/345/221/212_LoCoMo_/347/201/265/346/236/242_.png +0 -0
  12. package/docs/eval//347/254/254/344/270/211/346/226/271/351/252/214/350/257/201/346/212/245/345/221/212_/347/201/265/346/236/242_vs_dejavu_/347/273/237/344/270/200/350/257/204/345/210/206_v7.md +202 -0
  13. package/docs/experiments/linkref_backfill/candidates_20260917.json +726 -0
  14. package/docs/experiments/linkref_backfill/candidates_internal_20260917.json +602 -0
  15. package/docs/experiments/linkref_backfill/candidates_internal_v2.json +603 -0
  16. package/docs/experiments/linkref_backfill/candidates_secret_20260917.json +884 -0
  17. package/docs/experiments/linkref_backfill/candidates_secret_v2.json +789 -0
  18. package/docs/experiments/m4-role-probe/census.py +86 -0
  19. package/docs/experiments/m4-role-probe/probe.py +89 -0
  20. package/docs/experiments/mapped_confidence/bench_mapped_conf.py +216 -0
  21. package/docs/experiments/mapped_confidence/post_check.py +75 -0
  22. package/docs/experiments/mapped_confidence/repro_thirdparty_tol.py +83 -0
  23. package/docs/experiments/mapped_confidence/result_mapped_conf.json +215 -0
  24. 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
  25. 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
  26. 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
  27. 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
  28. 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
  29. 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
  30. package/docs/{ → hive/}/350/234/202/345/267/242/345/267/245/344/275/234/350/256/260/345/277/206_/351/241/271/347/233/256/350/256/241/345/210/222.md +14 -2
  31. 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
  32. package/docs/{README → mdcg/README}/350/257/246/347/273/206/347/211/210_v0.4.5.md +631 -625
  33. package/docs/{ → mdcg/}/344/270/273/344/273/243/347/220/206/345/255/220/344/273/243/347/220/206/350/256/260/345/277/206/346/236/266/346/236/204/350/256/276/350/256/241.md +1 -1
  34. 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
  35. 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
  36. 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 +263 -0
  37. package/docs/{ → mdcg/}/345/215/225/345/205/203/350/207/252/346/210/221/351/224/232/347/202/271_/347/263/273/347/273/237/346/217/220/347/244/272/350/257/215/346/240/207/345/207/206_v0.3.md +1 -1
  38. 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.5.md +236 -0
  39. package/docs/{ → mdcg/}/346/272/220/347/240/201/347/272/247/346/236/266/346/236/204/345/256/241/350/256/241_GPT/346/211/271/350/257/204/345/257/271/347/205/247_v1.0.md +2 -2
  40. package/docs/{ → mdcg/}/347/201/265/346/236/242/344/270/211/345/261/202/346/213/206/345/210/206/350/247/204/345/210/222_v0.1.md +181 -181
  41. 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
  42. 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
  43. package/docs/{ → mdcg/}/347/274/272/345/217/243/345/215/225_P0/346/224/266/345/217/243_v0.1.md +2 -2
  44. package/docs/{ → mdcg/}/350/256/244/347/237/245/345/233/276_G4-G8/347/274/272/345/217/243/350/243/201/345/256/232/345/215/225_v0.1.md +1 -1
  45. 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 +4 -4
  46. package/docs/{ → mdcg/}/350/256/260/345/277/206/346/223/215/344/275/234/347/263/273/347/273/237_MdCGOS/344/270/216MCP/346/216/245/345/205/245_v0.1.md +2 -2
  47. 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
  48. package/docs/plans/GridWorld/346/234/200/345/260/217/351/227/255/347/216/257/350/247/204/346/240/274_v0.1.md +176 -0
  49. package/docs/{ → swarm/}/350/234/202/347/276/244/344/272/222/350/201/224_v0.1.md +3 -3
  50. package/docs/swarm//350/234/202/347/276/244/345/220/214/351/224/231/346/243/200/346/265/213/345/256/236/351/252/214/345/215/217/350/256/256_v0.1.md +242 -0
  51. package/docs/theory//345/215/225/347/272/277/347/250/213/344/270/216/346/263/250/346/204/217/345/212/233/351/233/206/344/270/255_/346/227/240/344/272/211/350/256/256/347/220/206/350/256/272/346/226/207/346/241/243_v1.0.md +129 -0
  52. 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 +134 -0
  53. package/docs/theory//346/246/202/345/277/265/345/210/206/345/261/202/345/257/271/351/275/220/350/241/250_v0.1.md +145 -0
  54. 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 +6 -6
  55. package/docs/{ → theory/}/347/220/206/350/256/272/344/273/223/346/213/206/345/210/206/344/270/216/347/231/275/347/256/261/347/237/245/350/257/206/345/272/223/345/206/205/350/277/201_v0.1.md +1 -1
  56. 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 +221 -0
  57. package/docs/world_model//344/270/226/347/225/214/346/250/241/345/236/213_/347/245/236/347/273/217/347/275/221/347/273/234/345/272/225/345/261/202/346/236/266/346/236/204_v1.0.md +237 -0
  58. package/docs//345/255/230/347/256/227/344/270/200/344/275/223/346/236/266/346/236/204/345/255/246/344/271/240_/345/244/226/351/203/250/347/220/206/350/256/272/345/257/271/347/205/247/344/270/216/350/267/257/347/272/277/344/272/244/346/216/245_20260916.md +98 -0
  59. package/docs//345/255/230/347/256/227/344/270/200/344/275/223/347/245/236/347/273/217/347/275/221/347/273/234/346/236/266/346/236/204_/346/200/273/347/272/262/344/270/216/344/272/244/346/216/245_20260916.md +109 -0
  60. 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 -405
  61. 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
  62. package/docs//347/231/275/347/256/261/345/214/226/347/272/262/351/242/206_/344/270/211/351/241/271/347/233/256/345/255/246/344/271/240/346/200/273/346/236/266/346/236/204/344/270/216Ghidra/344/272/244/346/216/245_20260916.md +104 -0
  63. package/docs//350/256/260/345/277/206/350/257/204/345/256/241/347/263/273/347/273/237_/347/253/213/351/241/271/350/256/276/350/256/241/344/270/216/346/226/275/345/267/245/344/272/244/346/216/245_20260915.md +183 -0
  64. package/dsh/README.md +34 -1
  65. package/dsh/cordis.yml.example +13 -7
  66. package/dsh/hive-mcp-probe.mjs +94 -0
  67. package/dsh/hive-mcp.example.yml +62 -0
  68. package/dsh/update-lingshu.bat +11 -0
  69. package/dsh/update-lingshu.ps1 +337 -0
  70. package/lib/hooks.d.ts +8 -0
  71. package/lib/hooks.js +27 -24
  72. package/lib/index.d.ts +4 -2
  73. package/lib/index.js +29 -6
  74. package/lib/lib/datapath.d.ts +76 -1
  75. package/lib/lib/datapath.js +199 -13
  76. package/lib/lib/mdcg_client.d.ts +6 -3
  77. package/lib/lib/mdcg_client.js +6 -5
  78. package/lib/lib/mutual.js +4 -4
  79. package/lib/lib/prompt_safety.d.ts +48 -0
  80. package/lib/lib/prompt_safety.js +62 -0
  81. package/lib/lib/token_store.js +4 -5
  82. package/md_cg/audit.py +91 -2
  83. package/md_cg/autonomy.py +86 -15
  84. package/md_cg/backfill.py +36 -1
  85. package/md_cg/backfill_bigdomain.py +34 -0
  86. package/md_cg/bench6_arms.py +28 -1
  87. package/md_cg/bench6_common.py +10 -1
  88. package/md_cg/bench6_competitors.py +6 -1
  89. package/md_cg/bench_axis_domain.py +9 -1
  90. package/md_cg/bench_blind_comp.py +7 -1
  91. package/md_cg/bench_en_atoms_public.py +9 -0
  92. package/md_cg/bench_governance.py +348 -0
  93. package/md_cg/bench_lme_zh.py +16 -1
  94. package/md_cg/bench_locomo.py +2 -1
  95. package/md_cg/bench_locomo_zh.py +16 -1
  96. package/md_cg/bench_locomo_zh_public.py +4 -1
  97. package/md_cg/bench_longmem.py +2 -1
  98. package/md_cg/bench_membench.py +37 -6
  99. package/md_cg/bench_p0.py +4 -1
  100. package/md_cg/bench_progressive.py +61 -10
  101. package/md_cg/bench_role_views.py +238 -0
  102. package/md_cg/bench_task_ab.py +8 -1
  103. package/md_cg/bench_task_ab_llm.py +13 -1
  104. package/md_cg/bench_unified_en.py +6 -1
  105. package/md_cg/bench_zh_mad.py +20 -1
  106. package/md_cg/blindspot_tickets.py +123 -0
  107. package/md_cg/branches.py +286 -0
  108. package/md_cg/build_postings.py +73 -0
  109. package/md_cg/ccgc.py +949 -0
  110. package/md_cg/census.py +5 -1
  111. package/md_cg/chain.py +24 -3
  112. package/md_cg/codeindex.py +134 -17
  113. package/md_cg/coldverify.py +265 -0
  114. package/md_cg/comment_gate.py +338 -0
  115. package/md_cg/cond_compose.py +190 -0
  116. package/md_cg/cond_facts.py +155 -0
  117. package/md_cg/cond_template.json +107 -0
  118. package/md_cg/condition_anchor.py +143 -0
  119. package/md_cg/conformance.py +727 -0
  120. package/md_cg/consistency.py +25 -2
  121. package/md_cg/consolidate.py +53 -2
  122. package/md_cg/corpus.py +5 -1
  123. package/md_cg/crosscheck.py +42 -2
  124. package/md_cg/crypto.py +35 -1
  125. package/md_cg/d_meta.py +310 -0
  126. package/md_cg/datapath.py +201 -26
  127. package/md_cg/docindex.py +122 -1
  128. package/md_cg/eval_common.py +35 -6
  129. package/md_cg/evidence.py +27 -1
  130. package/md_cg/evolution.py +21 -1
  131. package/md_cg/export.py +11 -1
  132. package/md_cg/forgetting.py +34 -4
  133. package/md_cg/fsutil.py +81 -2
  134. package/md_cg/hotcache.py +214 -0
  135. package/md_cg/hyperedge.py +251 -0
  136. package/md_cg/identity.py +20 -3
  137. package/md_cg/insight.py +19 -3
  138. package/md_cg/lexicon/build_cedict_en_zh.py +9 -0
  139. package/md_cg/lexicon/build_standard_en.py +171 -168
  140. package/md_cg/lexicon/expand_en_zh.py +6 -0
  141. package/md_cg/lifecycle.py +273 -0
  142. package/md_cg/linkref.py +281 -0
  143. package/md_cg/links.py +29 -1
  144. package/md_cg/mcp_server.py +894 -168
  145. package/md_cg/md_whitebox.py +53 -1
  146. package/md_cg/mdcg.py +1205 -41
  147. package/md_cg/mdcos.py +1060 -76
  148. package/md_cg/metacognition.py +39 -4
  149. package/md_cg/migrate.py +4 -0
  150. package/md_cg/migrate_aeis.py +221 -213
  151. package/md_cg/migrate_roleplay.py +8 -0
  152. package/md_cg/migrate_wisdom_graph.py +14 -1
  153. package/md_cg/mreview/__init__.py +25 -0
  154. package/md_cg/mreview/__main__.py +110 -0
  155. package/md_cg/mreview/bundle.py +178 -0
  156. package/md_cg/mreview/candidates.py +262 -0
  157. package/md_cg/mreview/govern.py +694 -0
  158. package/md_cg/mreview/locate.py +939 -0
  159. package/md_cg/mreview/pipeline.py +729 -0
  160. package/md_cg/mreview/rules/duplication.json +21 -0
  161. package/md_cg/mreview/rules/field_coverage.json +54 -0
  162. package/md_cg/mreview/rules/source_license.json +21 -0
  163. package/md_cg/mreview/rules/template_flow.json +21 -0
  164. package/md_cg/mreview/ruleset.py +253 -0
  165. package/md_cg/nodefile.py +269 -1
  166. package/md_cg/pooling.py +23 -1
  167. package/md_cg/postings.py +298 -0
  168. package/md_cg/predict.py +113 -15
  169. package/md_cg/progressive.py +3 -0
  170. package/md_cg/protect.py +18 -5
  171. package/md_cg/protocol.py +372 -0
  172. package/md_cg/provenance.py +262 -0
  173. package/md_cg/reach.py +453 -0
  174. package/md_cg/refindex.py +88 -4
  175. package/md_cg/refine.py +20 -1
  176. package/md_cg/roleviews.py +89 -0
  177. package/md_cg/routing.py +76 -0
  178. package/md_cg/scrub.py +68 -3
  179. package/md_cg/security.py +26 -1
  180. package/md_cg/self_state.py +65 -2
  181. package/md_cg/selfreport.py +151 -0
  182. package/md_cg/semantic/canonical.py +5 -0
  183. package/md_cg/semantic/en_normalizer.py +364 -295
  184. package/md_cg/semantic/zh_en_atoms.py +139 -136
  185. package/md_cg/signer.py +41 -1
  186. package/md_cg/sources.py +583 -547
  187. package/md_cg/statushdr.py +179 -0
  188. package/md_cg/stg.py +59 -18
  189. package/md_cg/subgraph.py +23 -0
  190. package/md_cg/sustain.py +74 -1
  191. package/md_cg/tasks.py +471 -0
  192. package/md_cg/test_action_derive.py +203 -0
  193. package/md_cg/test_audit_rotate.py +270 -0
  194. package/md_cg/test_autonomy.py +26 -0
  195. package/md_cg/test_bench_governance.py +102 -0
  196. package/md_cg/test_blindspot_tickets.py +166 -0
  197. package/md_cg/test_branches.py +249 -0
  198. package/md_cg/test_ccg_perturb.py +1 -1
  199. package/md_cg/test_ccgc.py +433 -0
  200. package/md_cg/test_codeindex.py +338 -0
  201. package/md_cg/test_comment_gate.py +187 -0
  202. package/md_cg/test_cond_compose_anchors.py +76 -0
  203. package/md_cg/test_condition_anchor.py +82 -0
  204. package/md_cg/test_conformance.py +343 -0
  205. package/md_cg/test_d_meta.py +412 -0
  206. package/md_cg/test_datapath_root.py +188 -0
  207. package/md_cg/test_en_pipeline.py +24 -0
  208. package/md_cg/test_gain_gate.py +47 -1
  209. package/md_cg/test_health_scale.py +173 -0
  210. package/md_cg/test_hot_cold.py +187 -0
  211. package/md_cg/test_hyperedge.py +245 -0
  212. package/md_cg/test_identity_attribution.py +6 -0
  213. package/md_cg/test_index_durability.py +224 -0
  214. package/md_cg/test_lifecycle.py +309 -0
  215. package/md_cg/test_linkref.py +306 -0
  216. package/md_cg/test_md_access_parity.py +15 -3
  217. package/md_cg/test_mr_m1.py +769 -0
  218. package/md_cg/test_mr_m2.py +587 -0
  219. package/md_cg/test_mr_m3.py +710 -0
  220. package/md_cg/test_mr_m4.py +485 -0
  221. package/md_cg/test_p1.py +1 -1
  222. package/md_cg/test_p11_consistency.py +1 -1
  223. package/md_cg/test_p12_metacognition.py +2 -2
  224. package/md_cg/test_p16_self_state.py +1 -1
  225. package/md_cg/test_p26_refindex.py +50 -21
  226. package/md_cg/test_p27_docindex.py +258 -4
  227. package/md_cg/test_p28_refcheck.py +1 -1
  228. package/md_cg/test_p29_session_ingest_export.py +1 -1
  229. package/md_cg/test_p2_mcp.py +7 -1
  230. package/md_cg/test_p31_insight.py +24 -0
  231. package/md_cg/test_p38_contextualize.py +1 -1
  232. package/md_cg/test_p39_vision_evidence.py +1 -1
  233. package/md_cg/test_p40_refine_worklist.py +1 -1
  234. package/md_cg/test_p41_evolve_patrol.py +1 -1
  235. package/md_cg/test_p42_provenance.py +1 -1
  236. package/md_cg/test_p43_pooling.py +41 -13
  237. package/md_cg/test_p44_md_whitebox.py +14 -1
  238. package/md_cg/test_protocol.py +243 -0
  239. package/md_cg/test_reach.py +378 -0
  240. package/md_cg/test_reach_keys.py +201 -0
  241. package/md_cg/test_reach_meta_exits.py +145 -0
  242. package/md_cg/test_read_clip.py +141 -0
  243. package/md_cg/test_retr_s1.py +340 -0
  244. package/md_cg/test_retr_s1b.py +209 -0
  245. package/md_cg/test_retr_s3.py +194 -0
  246. package/md_cg/test_retr_s4.py +163 -0
  247. package/md_cg/test_retr_s5.py +200 -0
  248. package/md_cg/test_retr_s6.py +157 -0
  249. package/md_cg/test_retr_s7.py +385 -0
  250. package/md_cg/test_retr_s8_time.py +316 -0
  251. package/md_cg/test_retr_s9_edges.py +286 -0
  252. package/md_cg/test_retr_s9_entity_ctx.py +175 -0
  253. package/md_cg/test_review_conformance.py +367 -0
  254. package/md_cg/test_role_views.py +354 -0
  255. package/md_cg/test_tasks.py +409 -0
  256. package/md_cg/test_tool_face.py +189 -0
  257. package/md_cg/test_trust.py +361 -0
  258. package/md_cg/test_twophase.py +286 -0
  259. package/md_cg/test_units_poll.py +71 -0
  260. package/md_cg/test_v14_fixes.py +397 -0
  261. package/md_cg/test_validity_filter.py +280 -0
  262. package/md_cg/test_wisdom_md_store.py +7 -3
  263. package/md_cg/test_writepipe.py +214 -0
  264. package/md_cg/theory.py +17 -2
  265. package/md_cg/tokens.py +134 -12
  266. package/md_cg/tool_face.py +261 -0
  267. package/md_cg/trust.py +943 -0
  268. package/md_cg/twophase.py +232 -0
  269. package/md_cg/units.py +665 -0
  270. package/md_cg/vision_evidence.py +25 -2
  271. package/md_cg/weights.py +25 -2
  272. package/md_cg/whitebox.py +33 -2
  273. package/md_cg/whitebox_kb/data/verify_cache.json +21233 -360
  274. package/md_cg/whitebox_kb/data/verify_savings.jsonl +5124 -0
  275. package/md_cg/whitebox_kb/wisdom/audit_log/chain_heat.json +10 -10
  276. package/md_cg/whitebox_kb/wisdom/code_compose.py +113 -6
  277. package/md_cg/whitebox_kb/wisdom/code_solidified.json +1 -1
  278. package/md_cg/whitebox_kb/wisdom/verifier.py +340 -55
  279. package/md_cg/whitebox_kb/wisdom/wisdom-book-cloud.db +0 -0
  280. package/md_cg/writelimit.py +37 -7
  281. package/md_cg/writepipe.py +543 -0
  282. package/package.json +2 -2
  283. package/skills/skills/designer-perspective/scripts/__pycache__/designer.cpython-310.pyc +0 -0
  284. package/skills/skills/designer-perspective/scripts/designer.py +17 -1
  285. package/skills/skills/designer-perspective/tests/selftest.py +3 -1
  286. package/src/hooks.ts +27 -22
  287. package/src/index.ts +33 -6
  288. package/src/lib/datapath.ts +211 -13
  289. package/src/lib/mdcg_client.ts +12 -8
  290. package/src/lib/mutual.ts +411 -411
  291. package/src/lib/prompt_safety.ts +62 -0
  292. package/src/lib/token_store.ts +4 -5
  293. package/zcode/AGENTS.md +21 -10
  294. package/zcode/README.md +4 -0
  295. package/docs//345/212/237/350/203/275/350/260/203/347/224/250/346/230/240/345/260/204/350/241/250_v0.1.md +0 -221
  296. /package/docs/{AGI → eval/AGI}/344/270/203/347/273/264/350/257/204/345/210/206/346/212/245/345/221/212_md_cg_v1.0.md" +0 -0
  297. /package/docs/{AGI → eval/AGI}/344/270/203/347/273/264/350/257/204/345/210/206/346/212/245/345/221/212_md_cg_v2.0.md" +0 -0
  298. /package/docs/{ → eval/}/345/256/236/351/252/214/346/226/271/346/241/210_/345/255/246/344/271/240/351/227/255/347/216/257AB/344/270/216/346/250/252/350/257/204_v1.0.md" +0 -0
  299. /package/docs/{ → eval/}/346/250/252/350/257/204_/345/205/255/345/256/266100/351/242/230/344/270/255/350/213/261/345/217/214/346/237/245_v1.0.md" +0 -0
  300. /package/docs/{guardrail-charter.md → mdcg/guardrail-charter.md} +0 -0
  301. /package/docs/{lingshu_tutorial.html → mdcg/lingshu_tutorial.html} +0 -0
  302. /package/docs/{memory-assessment.html → mdcg/memory-assessment.html} +0 -0
  303. /package/docs/{memory_score.html → mdcg/memory_score.html} +0 -0
  304. /package/docs/{memory_score.png → mdcg/memory_score.png} +0 -0
  305. /package/docs/{release_v0.3.0.md → mdcg/release_v0.3.0.md} +0 -0
  306. /package/docs/{release_v0.4.5.md → mdcg/release_v0.4.5.md} +0 -0
  307. /package/docs/{tool_table_v0.3.0.md → mdcg/tool_table_v0.3.0.md} +0 -0
  308. /package/docs/{ → mdcg/}/344/273/244/347/211/214/344/270/216/350/247/222/350/211/262/346/235/203/350/201/214/345/210/206/347/246/273_v0.1.md" +0 -0
  309. /package/docs/{ → mdcg/}/347/201/265/346/236/24282/345/267/245/345/205/267_/345/212/237/350/203/275/346/225/264/347/220/206/344/270/216/350/277/201/347/247/273/346/230/240/345/260/204_v0.1.md" +0 -0
  310. /package/docs/{ → mdcg/}/347/201/265/346/236/242MCP/345/267/245/345/205/267/346/200/273/350/241/250_v3.4.md" +0 -0
  311. /package/docs/{ → mdcg/}/347/201/265/346/236/242_/350/207/252/346/210/221/345/261/202/345/256/232/344/271/211.md" +0 -0
  312. /package/docs/{ → mdcg/}/350/256/244/347/237/245/345/233/276_MD/347/233/256/345/275/225/346/226/271/346/241/210_v0.1.md" +0 -0
  313. /package/docs/{ → mdcg/}/350/256/244/347/237/245/345/233/276_/346/235/241/344/273/266/347/251/272/351/227/264/345/220/210/346/210/220/344/270/216/347/224/237/346/225/210/346/235/241/344/273/266/345/217/243/345/276/204_v0.1.md" +0 -0
  314. /package/docs/{ → mdcg/}/350/256/244/347/237/245/345/233/276/344/275/234/344/270/272/350/256/260/345/277/206/346/223/215/344/275/234/347/263/273/347/273/237_/350/257/204/344/274/260/344/270/216/350/267/257/347/272/277_v0.1.md" +0 -0
  315. /package/docs/{ → plans/}/345/221/275/345/220/215/346/262/273/347/220/206_/351/241/271/347/233/256/350/256/241/345/210/222.md" +0 -0
  316. /package/docs/{ → plans/}/347/237/245/350/257/206/345/233/276/350/260/261/351/241/271/347/233/256_/344/272/244/346/216/245/346/226/207/346/241/243_20260914.md" +0 -0
  317. /package/docs/{ → swarm/}/350/234/202/347/276/244/345/244/232/346/231/272/350/203/275/344/275/223_/344/275/277/347/224/250/346/212/245/345/221/212_20260913.md" +0 -0
  318. /package/docs/{ → swarm/}/350/234/202/347/276/244/345/244/232/346/231/272/350/203/275/344/275/223_/345/212/237/350/203/275/350/257/264/346/230/216_v0.6.md" +0 -0
  319. /package/docs/{ → swarm/}/350/234/202/347/276/244/347/233/262/345/214/272/346/240/207/350/256/260_v1.0.md" +0 -0
  320. /package/docs/{ → theory/}/344/277/241/346/201/257/345/267/256/344/270/272/344/273/200/344/271/210/345/277/205/347/204/266/345/255/230/345/234/250/344/270/224/350/207/252/347/204/266/346/211/251/345/244/247.md" +0 -0
  321. /package/docs/{ → theory/}/346/231/272/350/203/275/347/232/204/345/205/254/347/220/206/345/214/226/345/237/272/347/237/263.md" +0 -0
  322. /package/docs/{ → theory/}/346/231/272/350/203/275/347/232/204/350/256/244/347/237/245/350/277/207/347/250/213.md" +0 -0
  323. /package/docs/{ → theory/}/346/231/272/350/203/275/350/256/2723.4.md" +0 -0
  324. /package/docs/{ → theory/}/347/231/275/347/256/261/346/231/272/350/203/275/346/230/257/344/273/200/344/271/210/357/274/237.md" +0 -0
  325. /package/docs/{ → theory/}/347/231/275/347/256/261/346/231/272/350/203/275/347/263/273/345/210/227/302/267/347/254/254/344/272/224/347/257/207/357/274/232/350/256/251AI/347/234/237/346/255/243/350/243/205/344/270/212/350/256/260/345/277/206.md" +0 -0
@@ -0,0 +1,338 @@
1
+ # -*- coding: utf-8 -*-
2
+ """代码索引(codeindex)验收 · Phase 0 契约裁决 + 行序压制修复。
3
+
4
+ 对应计划 docs/mdcg/全库代码评审与条件化注释_计划_v0.1.md 的
5
+ codeindex-render-fix / codeindex-tests;契约为
6
+ docs/mdcg/代码评审与条件化注释_契约_v0.1.md。
7
+
8
+ 验收口径(改造前 → 改造后):
9
+ 1. 行序压制:源码里人工写的生效条件行曾被合成行(同名字段、且排在源码注释
10
+ 之前)永久压制——检索侧 mdcos._ccg_field 取首个匹配,人工声明不可见。
11
+ 现在合成区与源码区**分区**、源码区**置首**,人工声明胜出并逐字保留。
12
+ 2. 字段零重名:机械推导的索引元条件不再占用生效条件字段,改由
13
+ nodefile.INDEX_META_MARK 承载;合成区字段名与 CCG 六要素的交集必须是空集
14
+ (机械判据 nodefile.is_ccg_mark)。
15
+ 3. 诚实缺证据:源码未声明生效条件的条目,ccg_completeness 必须
16
+ complete=False 且**恰缺**「生效条件」——不许用索引元条件冒充。这是 Phase 0
17
+ 的**预期代价面**:真实库既有 2930 条代码节点在重索引后由 DEFER 降为
18
+ BLINDSPOT,待环二补注释闸门逐步补回(代价面见契约 §四)。
19
+ 4. extract / condition_space 既有契约不回归;index_dir 确定性排序与截断显式
20
+ 上报维持(index-dir-integrity 属 Phase 1,本文件只建基线护栏)。
21
+ """
22
+ from __future__ import annotations
23
+
24
+ import ast
25
+ import os
26
+ import sys
27
+ import tempfile
28
+ import traceback
29
+
30
+ from . import codeindex, nodefile
31
+ from .mdcos import _ccg_field
32
+
33
+ _ok = 0
34
+ _bad = []
35
+ _skip = 0
36
+
37
+
38
+ def _check(name, cond, detail=""):
39
+ global _ok
40
+ if cond:
41
+ _ok += 1
42
+ print(" ok %s" % name)
43
+ else:
44
+ _bad.append("%s %s" % (name, detail))
45
+ print(" FAIL %s %s" % (name, detail))
46
+
47
+
48
+ PY_SRC = '''"""示例模块。"""
49
+ import os
50
+
51
+
52
+ # 生效条件:入参 path 为已存在的本地文件
53
+ # 子功能:读取文件首行
54
+ def first_line(path):
55
+ """读取首行。"""
56
+ return open(path, encoding="utf-8").readline()
57
+
58
+
59
+ def bare(name):
60
+ """无源码 CCG 注释。"""
61
+ return name
62
+ '''
63
+
64
+ JS_SRC = '''/** 弱提取样本 */
65
+ export function ping(url) {
66
+ return url;
67
+ }
68
+ '''
69
+
70
+ HUMAN_COND = "# 生效条件:入参 path 为已存在的本地文件"
71
+
72
+ # 两窗口样本(裁决 A):leading 在定义行之上,body 在定义行之下/体首语句之前
73
+ BODY_SRC = '''"""两窗口样本。"""
74
+
75
+
76
+ # 生效条件:外层声明(leading 窗口)
77
+ def with_body(seq):
78
+ # 生效条件:入参 seq 为可迭代且元素可比较(body 窗口)
79
+ # 子功能:返回排序副本
80
+ out = sorted(seq)
81
+ return out
82
+
83
+
84
+ def body_trap(seq):
85
+ out = sorted(seq)
86
+ # 实现注释:位于体首语句【之后】→ 不属于声明头窗口,不应被收
87
+ return out
88
+ '''
89
+
90
+
91
+ def _item_of(src, path, name):
92
+ items = codeindex.extract(src, path)
93
+ return next((x for x in items if x["name"] == name), None)
94
+
95
+
96
+ def main():
97
+ print("=" * 68)
98
+ print("md_cg codeindex 验收 · Phase 0(行序压制修复 + 契约裁决)")
99
+ print("=" * 68)
100
+ tmp = tempfile.mkdtemp(prefix="mdcg_codeidx_")
101
+ try:
102
+ # ---------------- ① 契约常量 ----------------
103
+ print()
104
+ print("【1】契约常量:合成区字段名与 CCG 零重名")
105
+ _check("索引元条件字段名不在 CCG 六要素内",
106
+ nodefile.INDEX_META_MARK not in nodefile.CCG_MARKS
107
+ and not nodefile.is_ccg_mark(nodefile.INDEX_META_MARK),
108
+ nodefile.INDEX_META_MARK)
109
+ _check("is_ccg_mark 对六要素逐一为真",
110
+ all(nodefile.is_ccg_mark(m) for m in nodefile.CCG_MARKS))
111
+ _check("is_ccg_mark 对元条件与位置为假",
112
+ not nodefile.is_ccg_mark(nodefile.INDEX_META_MARK)
113
+ and not nodefile.is_ccg_mark("位置"))
114
+
115
+ # ---------------- ② 分区与行序:人工优先 ----------------
116
+ print()
117
+ print("【2】render 三分区:源码区置首,人工声明不被压制")
118
+ it_ann = _item_of(PY_SRC, "demo.py", "first_line")
119
+ _check("extract 命中带注释的函数", bool(it_ann))
120
+ r_ann = codeindex.render(it_ann)
121
+ _check("源码注释逐字保留(不被丢弃)", HUMAN_COND in r_ann)
122
+ r_lines = r_ann.splitlines()
123
+ cond_i = r_lines.index(HUMAN_COND)
124
+ head_i = next(i for i, ln in enumerate(r_lines)
125
+ if ln.startswith("# 功能名:"))
126
+ _check("源码区先于合成区(人工优先的确定性序)", cond_i < head_i,
127
+ "cond@" + str(cond_i) + " head@" + str(head_i))
128
+ _check("检索侧取到人工条件(行序压制已修)",
129
+ _ccg_field(r_ann, "生效条件") == "入参 path 为已存在的本地文件",
130
+ _ccg_field(r_ann, "生效条件"))
131
+ _check("生效条件行恰一条(合成区不再产出该行)",
132
+ sum(1 for ln in r_lines
133
+ if ln.startswith("# 生效条件:")) == 1)
134
+ _check("补了注释 → 五要素齐备(complete=True)",
135
+ nodefile.ccg_completeness(r_ann)["complete"] is True,
136
+ str(nodefile.ccg_completeness(r_ann)["required_present"]))
137
+
138
+ it_bare = _item_of(PY_SRC, "demo.py", "bare")
139
+ r_bare = codeindex.render(it_bare)
140
+ _check("未声明生效条件的条目:合成区不冒充该字段",
141
+ "# 生效条件:" not in r_bare)
142
+ cpl = nodefile.ccg_completeness(r_bare)
143
+ missing = [m for m in nodefile.CCG_REQUIRED
144
+ if m not in cpl["required_present"]]
145
+ _check("未声明 → 恰缺生效条件(诚实缺证据,非整体失效)",
146
+ cpl["complete"] is False and missing == ["生效条件"],
147
+ str(missing))
148
+ _check("合成区其余 5 要素仍齐备",
149
+ all(m in cpl["required_present"] for m in nodefile.CCG_MARKS
150
+ if m != "生效条件"), str(cpl["required_present"]))
151
+
152
+ # ---------------- ③ 索引元信息区:零重名 + 同源 ----------------
153
+ print()
154
+ print("【3】索引元信息区(非 CCG 字段名,与 frontmatter 同源)")
155
+ meta_head = "# " + nodefile.INDEX_META_MARK + ":"
156
+ meta_line = next((ln for ln in r_lines if ln.startswith(meta_head)), "")
157
+ _check("索引元条件独立成行", bool(meta_line), meta_line[:60])
158
+ cs = codeindex.condition_space(it_ann)
159
+ _check("元条件 = condition_space 四槽同源(require_full=False)",
160
+ meta_line == meta_head + nodefile.condition_space_text(
161
+ cs, require_full=False), meta_line[:90])
162
+ _check("元条件行不被误判为旧口径单槽冒充",
163
+ not nodefile.is_legacy_position_condition(meta_line))
164
+ heads = []
165
+ for ln in r_bare.splitlines():
166
+ if not ln.startswith("#"):
167
+ continue
168
+ body = ln.lstrip("#").strip()
169
+ heads.append(body.split(":")[0].split(":")[0].strip())
170
+ used = sorted({h for h in heads if nodefile.is_ccg_mark(h)})
171
+ allowed = sorted(m for m in nodefile.CCG_MARKS if m != "生效条件")
172
+ _check("合成区用到的 CCG 字段名 = 其余五要素(排除生效条件)",
173
+ used == allowed, str(used))
174
+ _check("合成区非 CCG 字段名 = 索引元条件 + 位置",
175
+ sorted(h for h in heads if not nodefile.is_ccg_mark(h))
176
+ == sorted([nodefile.INDEX_META_MARK, "位置"]), str(heads))
177
+
178
+ # ---------------- ④ condition_space 既有契约不回归 ----------------
179
+ print()
180
+ print("【4】condition_space(四槽/全时窗)不回归")
181
+ _check("四槽齐备",
182
+ set(cs) == set(nodefile.CONDITION_SLOTS_REQUIRED),
183
+ str(sorted(cs)))
184
+ _check("时间槽用全时窗哨兵(不把写入时刻伪造成条件)",
185
+ nodefile.is_full_time_window(cs.get("time_window")),
186
+ str(cs.get("time_window")))
187
+ js_it = _item_of(JS_SRC, "sample.js", "ping")
188
+ weak = codeindex.condition_space(js_it)
189
+ _check("弱提取在方法槽诚实降级(不冒充编译器)",
190
+ codeindex.LANG_WEAK in weak["observation_tool"]
191
+ and codeindex.LANG_COMPILER not in weak["observation_tool"],
192
+ weak["observation_tool"])
193
+
194
+ # ---------------- ⑤ extract / 幂等 / 确定性 ----------------
195
+ print()
196
+ print("【5】extract 分派 / 幂等 / node_id / region_hash")
197
+ _check("Python → AST 精确(precise=True / basis=compiler)",
198
+ it_ann["precise"] is True and it_ann["basis"] == "compiler")
199
+ _check("JS → 弱提取(precise=False / basis=other)",
200
+ js_it["precise"] is False and js_it["basis"] == "other")
201
+ raised = False
202
+ try:
203
+ codeindex.extract("x = 1", "foo.xyz")
204
+ except ValueError as exc:
205
+ raised = "无提取器" in str(exc)
206
+ _check("无提取器后缀显式报错(不静默降级成 Python 解析)", raised)
207
+ _check("render 幂等(两次逐字节相同)",
208
+ codeindex.render(it_ann) == r_ann)
209
+ _check("node_id 稳定(path::name 短哈希,重复索引幂等)",
210
+ codeindex.node_id(it_ann) == codeindex.node_id(dict(it_ann)))
211
+ _check("region_hash 为 12 位十六进制(索引/回读共用口径)",
212
+ len(it_ann["hash"]) == 12
213
+ and all(c in "0123456789abcdef" for c in it_ann["hash"]),
214
+ it_ann["hash"])
215
+
216
+ # ---------------- ⑥ index_dir 基线护栏(Phase 1 前只建基线) -------
217
+ print()
218
+ print("【6】index_dir:确定性排序 + 截断显式上报(基线护栏)")
219
+ d = os.path.join(tmp, "pkg")
220
+ os.makedirs(d)
221
+ for fn, body in (("a.py", PY_SRC), ("b.js", JS_SRC)):
222
+ with open(os.path.join(d, fn), "w", encoding="utf-8") as f:
223
+ f.write(body)
224
+ _i1, _er1, s1 = codeindex.index_dir(d)
225
+ _i2, _er2, s2 = codeindex.index_dir(d)
226
+ _check("两次运行条目序逐项一致(walk/文件名确定性排序)",
227
+ [x["name"] for x in _i1] == [x["name"] for x in _i2],
228
+ str([x["name"] for x in _i1]))
229
+ _check("相同输入 stats 一致(幂等)", s1 == s2)
230
+ _check("未越限 → truncated=False", s1["truncated"] is False)
231
+ _check("skipped_suffixes 上报(无提取器后缀可见)",
232
+ isinstance(s1["skipped_suffixes"], list))
233
+ _i3, _er3, s3 = codeindex.index_dir(d, max_files=1)
234
+ _check("越限 → truncated=True 且原因非空(显式上报,不静默)",
235
+ s3["truncated"] is True and bool(s3["truncated_reason"]),
236
+ str(s3.get("truncated_reason")))
237
+ _check("越限时仍返回已索引条目(不丢已有产出)",
238
+ isinstance(_i3, list) and len(_i3) >= 1
239
+ and len(s3["skip_dirs"]) == len(s1["skip_dirs"]),
240
+ "items=" + str(len(_i3)))
241
+ # ---- index-dir-integrity(Phase 1):截断可复算 + 目录序确定 ----
242
+ _check("截断计数可复算:hit_files/indexed_items 就位且与条目数一致",
243
+ s1.get("hit_files", 0) >= 1 and s1.get("indexed_items") == len(_i1),
244
+ "hit=%s items=%s len=%s" % (s1.get("hit_files"),
245
+ s1.get("indexed_items"), len(_i1)))
246
+ _check("越限快照同样带 hit_files/indexed_items(与 files 同源)",
247
+ s3.get("hit_files", 0) >= 1 and s3.get("indexed_items") == len(_i3),
248
+ "hit=%s items=%s len=%s" % (s3.get("hit_files"),
249
+ s3.get("indexed_items"), len(_i3)))
250
+ nested = os.path.join(tmp, "nested")
251
+ for sub in ("z_sub", "a_sub"):
252
+ os.makedirs(os.path.join(nested, sub))
253
+ with open(os.path.join(nested, sub, "x.py"), "w", encoding="utf-8") as f:
254
+ f.write(PY_SRC)
255
+ _n1, _ne1, sn1 = codeindex.index_dir(nested)
256
+ _n2, _ne2, sn2 = codeindex.index_dir(nested)
257
+ _p1 = [x["path"] for x in _n1]
258
+ _p2 = [x["path"] for x in _n2]
259
+ _check("嵌套目录:两次运行条目路径序逐项一致(dirnames 已排序)",
260
+ _p1 == _p2 and len(_p1) > 1, str(_p1)[:120])
261
+ _check("嵌套目录:a_sub 先于 z_sub(与文件系统返回序无关)",
262
+ _p1.index(next(p for p in _p1 if p.startswith("a_sub/")))
263
+ < _p1.index(next(p for p in _p1 if p.startswith("z_sub/"))),
264
+ str(_p1)[:140])
265
+ _check("嵌套目录 stats 幂等(同输入两次一致)", sn1 == sn2)
266
+
267
+ # ---------------- ⑦ 载体两窗口(裁决 A) ----------------
268
+ print()
269
+ print("【7】注释载体两窗口:leading + body(裁决 A · 索引侧收口)")
270
+ _check("codeindex._body_comments 存在(历史悬空引用由此坐实)",
271
+ callable(getattr(codeindex, "_body_comments", None))
272
+ and callable(getattr(codeindex, "_symbol_comments", None)))
273
+ it2 = _item_of(BODY_SRC, "demo2.py", "with_body")
274
+ want_cmts = ["# 生效条件:外层声明(leading 窗口)",
275
+ "# 生效条件:入参 seq 为可迭代且元素可比较(body 窗口)",
276
+ "# 子功能:返回排序副本"]
277
+ _check("两窗口按物理行序合并(leading 在前、body 在后)",
278
+ it2["comments"] == want_cmts, repr(it2["comments"])[:200])
279
+ r2w = codeindex.render(it2)
280
+ _check("body 窗口的 CCG 注释在正文可见(不再是索引盲区)",
281
+ "# 生效条件:入参 seq 为可迭代且元素可比较(body 窗口)" in r2w)
282
+ _check("冲突时靠前者胜出(_ccg_field 取首匹配 = 物理序)",
283
+ _ccg_field(r2w, "生效条件") == "外层声明(leading 窗口)",
284
+ _ccg_field(r2w, "生效条件"))
285
+ _check("补了 body 注释 → 五要素齐备(complete=True)",
286
+ nodefile.ccg_completeness(r2w)["complete"] is True,
287
+ str(nodefile.ccg_completeness(r2w)["required_present"]))
288
+ # 非循环断言:窗口产物**逐字**固定(不依赖 verifier 委托是否成功)
289
+ # 期望值**写死**:体首语句行号不得臆测(上一版写成 lineno+1 即为反例)
290
+ _fnode = next(n for n in ast.parse(BODY_SRC).body
291
+ if isinstance(n, ast.FunctionDef) and n.name == "with_body")
292
+ _check("body 窗口产物逐字固定(期望值写死,非自证)",
293
+ codeindex._body_comments(BODY_SRC.splitlines(), _fnode.lineno,
294
+ _fnode.body[0].lineno) == [
295
+ "# 生效条件:入参 seq 为可迭代且元素可比较(body 窗口)",
296
+ "# 子功能:返回排序副本"],
297
+ repr(codeindex._body_comments(
298
+ BODY_SRC.splitlines(), _fnode.lineno,
299
+ _fnode.body[0].lineno))[:160])
300
+ it3 = _item_of(BODY_SRC, "demo2.py", "body_trap")
301
+ _check("体首语句【之后】的注释不入声明头窗口(边界不越界)",
302
+ it3["comments"] == [] and "实现注释" not in repr(it3["comments"]),
303
+ repr(it3["comments"])[:120])
304
+ # verifier 是否已收敛为「委托唯一真源」——等价断言不可静默跳过
305
+ try:
306
+ from .whitebox_kb.wisdom import verifier as Vmod
307
+ vobj = Vmod.Verifier.__new__(Vmod.Verifier)
308
+ tree = ast.parse(BODY_SRC)
309
+ fnode = next(n for n in tree.body if isinstance(n, ast.FunctionDef)
310
+ and n.name == "with_body")
311
+ src_lines = BODY_SRC.splitlines()
312
+ got, _doc = vobj._ccg_block(fnode, src_lines)
313
+ want = [s.lstrip("#").strip() for s in codeindex._body_comments(
314
+ src_lines, fnode.lineno, fnode.body[0].lineno)]
315
+ _check("verifier 已收敛为委托唯一真源(_ci_body_comments 可达)",
316
+ Vmod._ci_body_comments() is not None)
317
+ _check("verifier 窗口与 codeindex._body_comments 逐字等价",
318
+ got == want, repr([got, want])[:180])
319
+ _check("verifier 窗口只收 body 窗口(不误收 leading)",
320
+ got == want and all("外层声明" not in x for x in got),
321
+ repr(got)[:140])
322
+ except Exception as exc: # noqa: BLE001
323
+ global _skip
324
+ _skip += 1
325
+ print(" SKIP verifier 委托等价断言(模块不可导入):%r" % (exc,))
326
+
327
+ print()
328
+ print("PASS %d / FAIL %d / SKIP %d" % (_ok, len(_bad), _skip))
329
+ for b in _bad:
330
+ print(" - " + b)
331
+ return 1 if _bad else 0
332
+ except Exception: # noqa: BLE001
333
+ traceback.print_exc()
334
+ return 1
335
+
336
+
337
+ if __name__ == "__main__":
338
+ sys.exit(main())
@@ -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())