@furongjun1999/dsh-memory 0.4.11 → 0.5.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 (504) hide show
  1. package/README.md +16 -16
  2. package/codebuddy/CODEBUDDY.md +11 -3
  3. package/codebuddy/README.md +92 -90
  4. package/codebuddy/mcp.json +27 -27
  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 -169
  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 -144
  7. package/docs/README.md +142 -111
  8. package/docs/discipline/harnesses.yaml +244 -226
  9. package/docs/discipline/templates/full.md.tmpl +61 -61
  10. package/docs/discipline/templates/rules.mdc.tmpl +68 -0
  11. package/docs/discipline/templates/skill.md.tmpl +23 -23
  12. package/docs/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 +299 -299
  13. package/docs/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 +239 -239
  14. 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 +174 -174
  15. 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 +223 -223
  16. package/docs/{mdcg → hive}//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 +165 -160
  17. package/docs/hive//344/273/244/347/211/214/350/257/255/344/271/211/344/277/256/346/255/243_/344/273/262/350/243/201/344/275/215_v0.1.md +76 -0
  18. package/docs/{mdcg → hive}//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 -236
  19. 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 -43
  20. 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 +85 -0
  21. 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 -102
  22. 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 +47 -0
  23. 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 -503
  24. 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 +85 -85
  25. package/docs/hive//350/234/202/345/267/242/350/256/276/350/256/241_/347/220/206/350/256/272/345/257/271/351/275/220_v0.1.md +191 -0
  26. package/docs/hive//350/234/202/345/267/242/350/277/255/344/273/243_/345/256/217/350/247/202/344/270/216/347/276/244/344/275/223/350/260/203/345/272/246_v0.1.md +90 -0
  27. package/docs/mdcg/D_meta_/345/267/245/347/250/213/345/214/226/346/226/271/346/241/210_v0.2.md +216 -216
  28. package/docs/mdcg/README/350/257/246/347/273/206/347/211/210_v0.4.10.md +646 -646
  29. package/docs/mdcg/lingshu_tutorial.html +14449 -14449
  30. package/docs/mdcg/release_v0.4.11.md +49 -0
  31. package/docs/mdcg/release_v0.4.5.md +55 -55
  32. package/docs/mdcg/tool_table_v0.3.0.md +117 -117
  33. 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 -600
  34. 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
  35. 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 +275 -275
  36. package/docs/mdcg//345/217/221/345/270/203/351/227/250/347/246/201/351/223/276_v0.1.md +54 -0
  37. 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 +130 -130
  38. 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 +278 -278
  39. 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 -172
  40. package/docs/mdcg//347/274/272/345/217/243/345/215/225_P0/346/224/266/345/217/243_v0.1.md +270 -270
  41. 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 +491 -491
  42. 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 +340 -340
  43. 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 +588 -588
  44. 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 -176
  45. 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 +81 -81
  46. package/docs/swarm//350/234/202/347/276/244/344/272/222/350/201/224_v0.1.md +704 -704
  47. 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 -242
  48. 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 -129
  49. 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 -134
  50. package/docs/theory//346/231/272/350/203/275/350/256/2723.4.md +5260 -5260
  51. 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 -145
  52. 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 +144 -144
  53. 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 +198 -198
  54. 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 -221
  55. 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 -237
  56. package/docs//345/217/221/345/270/203/344/273/266/345/233/236/346/272/257/350/257/264/346/230/216_v0.1.md +82 -82
  57. 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 +28 -2
  58. package/dsh/README.md +82 -82
  59. package/dsh/cordis.yml.example +139 -139
  60. package/dsh/update-lingshu.bat +11 -11
  61. package/lib/hooks.js +36 -2
  62. package/lib/lib/roleplay_web.js +427 -427
  63. package/md_cg/__init__.py +7 -7
  64. package/md_cg/audit.py +368 -368
  65. package/md_cg/autonomy.py +287 -287
  66. package/md_cg/backfill.py +1327 -1327
  67. package/md_cg/backfill_bigdomain.py +34 -34
  68. package/md_cg/bench6_arms.py +410 -410
  69. package/md_cg/bench6_common.py +230 -230
  70. package/md_cg/bench6_competitors.py +212 -212
  71. package/md_cg/bench_axis_domain.py +257 -257
  72. package/md_cg/bench_blind_comp.py +308 -308
  73. package/md_cg/bench_en_atoms_public.py +230 -230
  74. package/md_cg/bench_governance.py +348 -348
  75. package/md_cg/bench_lme_zh.py +410 -410
  76. package/md_cg/bench_locomo.py +121 -121
  77. package/md_cg/bench_locomo_zh.py +450 -450
  78. package/md_cg/bench_locomo_zh_public.py +147 -147
  79. package/md_cg/bench_longmem.py +112 -112
  80. package/md_cg/bench_membench.py +632 -632
  81. package/md_cg/bench_p0.py +149 -149
  82. package/md_cg/bench_progressive.py +287 -287
  83. package/md_cg/bench_role_views.py +238 -238
  84. package/md_cg/bench_task_ab.py +243 -243
  85. package/md_cg/bench_task_ab_llm.py +408 -408
  86. package/md_cg/bench_unified_en.py +204 -204
  87. package/md_cg/bench_zh_mad.py +601 -601
  88. package/md_cg/blindspot_tickets.py +123 -123
  89. package/md_cg/branches.py +285 -285
  90. package/md_cg/build_postings.py +73 -73
  91. package/md_cg/ccgc.py +1005 -948
  92. package/md_cg/census.py +132 -132
  93. package/md_cg/chain.py +300 -300
  94. package/md_cg/codeindex.py +531 -531
  95. package/md_cg/coldverify.py +292 -292
  96. package/md_cg/comment_gate.py +337 -337
  97. package/md_cg/cond_compose.py +190 -190
  98. package/md_cg/cond_facts.py +154 -154
  99. package/md_cg/cond_template.json +106 -106
  100. package/md_cg/condition_anchor.py +142 -142
  101. package/md_cg/conformance.py +726 -726
  102. package/md_cg/consistency.py +717 -717
  103. package/md_cg/consolidate.py +1536 -1439
  104. package/md_cg/corpus.py +110 -110
  105. package/md_cg/crosscheck.py +1097 -1097
  106. package/md_cg/crypto.py +437 -437
  107. package/md_cg/d_meta.py +310 -310
  108. package/md_cg/datapath.py +334 -334
  109. package/md_cg/docindex.py +473 -473
  110. package/md_cg/eval_common.py +575 -575
  111. package/md_cg/evidence.py +580 -580
  112. package/md_cg/evolution.py +477 -477
  113. package/md_cg/export.py +220 -220
  114. package/md_cg/forgetting.py +581 -581
  115. package/md_cg/fsutil.py +329 -329
  116. package/md_cg/hotcache.py +238 -214
  117. package/md_cg/hyperedge.py +251 -251
  118. package/md_cg/identity.py +390 -390
  119. package/md_cg/insight.py +500 -500
  120. package/md_cg/interop.py +199 -0
  121. package/md_cg/lexicon/build_cedict_en_zh.py +329 -329
  122. package/md_cg/lexicon/build_standard_en.py +171 -171
  123. package/md_cg/lexicon/expand_en_zh.py +211 -211
  124. package/md_cg/lifecycle.py +272 -272
  125. package/md_cg/linkref.py +280 -280
  126. package/md_cg/links.py +622 -622
  127. package/md_cg/mcp_server.py +129 -32
  128. package/md_cg/md_whitebox.py +345 -345
  129. package/md_cg/mdcg.py +176 -117
  130. package/md_cg/mdcos.py +79 -13
  131. package/md_cg/metacognition.py +591 -591
  132. package/md_cg/migrate.py +119 -119
  133. package/md_cg/migrate_aeis.py +221 -221
  134. package/md_cg/migrate_roleplay.py +293 -293
  135. package/md_cg/migrate_wisdom_graph.py +360 -360
  136. package/md_cg/mreview/__init__.py +25 -25
  137. package/md_cg/mreview/__main__.py +110 -110
  138. package/md_cg/mreview/bundle.py +178 -178
  139. package/md_cg/mreview/candidates.py +262 -262
  140. package/md_cg/mreview/govern.py +693 -693
  141. package/md_cg/mreview/locate.py +939 -939
  142. package/md_cg/mreview/pipeline.py +728 -728
  143. package/md_cg/mreview/rules/duplication.json +21 -21
  144. package/md_cg/mreview/rules/field_coverage.json +54 -54
  145. package/md_cg/mreview/rules/source_license.json +21 -21
  146. package/md_cg/mreview/rules/template_flow.json +21 -21
  147. package/md_cg/mreview/ruleset.py +252 -252
  148. package/md_cg/nodefile.py +575 -575
  149. package/md_cg/pooling.py +484 -472
  150. package/md_cg/postings.py +298 -298
  151. package/md_cg/predict.py +1100 -1100
  152. package/md_cg/progressive.py +123 -123
  153. package/md_cg/protect.py +272 -272
  154. package/md_cg/protocol/md_cg_gate.proto +33 -33
  155. package/md_cg/protocol.py +372 -372
  156. package/md_cg/provenance.py +582 -582
  157. package/md_cg/reach.py +453 -453
  158. package/md_cg/readcache.py +85 -0
  159. package/md_cg/refindex.py +833 -833
  160. package/md_cg/refine.py +604 -604
  161. package/md_cg/roleviews.py +89 -89
  162. package/md_cg/routing.py +365 -365
  163. package/md_cg/scrub.py +852 -852
  164. package/md_cg/security.py +274 -274
  165. package/md_cg/self_state.py +1029 -1029
  166. package/md_cg/selfreport.py +151 -151
  167. package/md_cg/semantic/__init__.py +10 -10
  168. package/md_cg/semantic/canonical.py +122 -122
  169. package/md_cg/semantic/en_normalizer.py +364 -364
  170. package/md_cg/semantic/en_zh_map.json +28694 -0
  171. package/md_cg/semantic/export_en_zh_map.py +64 -0
  172. package/md_cg/semantic/unify.py +45 -0
  173. package/md_cg/semantic/zh_en_atoms.py +139 -139
  174. package/md_cg/signer.py +562 -562
  175. package/md_cg/sources.py +815 -582
  176. package/md_cg/statushdr.py +179 -179
  177. package/md_cg/stg.py +48 -37
  178. package/md_cg/subgraph.py +729 -729
  179. package/md_cg/sustain.py +1138 -1138
  180. package/md_cg/tasks.py +470 -470
  181. package/md_cg/test_action_derive.py +203 -203
  182. package/md_cg/test_audit_rotate.py +270 -270
  183. package/md_cg/test_autonomy.py +143 -143
  184. package/md_cg/test_bench_governance.py +102 -102
  185. package/md_cg/test_blindspot_tickets.py +166 -166
  186. package/md_cg/test_branches.py +249 -249
  187. package/md_cg/test_ccg_perturb.py +184 -184
  188. package/md_cg/test_ccgc.py +433 -433
  189. package/md_cg/test_census_prune.py +81 -81
  190. package/md_cg/test_cond_compose_anchors.py +76 -76
  191. package/md_cg/test_cond_match.py +165 -165
  192. package/md_cg/test_condition_anchor.py +81 -81
  193. package/md_cg/test_d_meta.py +412 -412
  194. package/md_cg/test_datapath_root.py +199 -199
  195. package/md_cg/test_en_pipeline.py +166 -166
  196. package/md_cg/test_gain_gate.py +212 -212
  197. package/md_cg/test_health_scale.py +173 -173
  198. package/md_cg/test_hive_ingest.py +285 -0
  199. package/md_cg/test_hot_cold.py +215 -215
  200. package/md_cg/test_hyperedge.py +245 -245
  201. package/md_cg/test_i26_empty_first_write.py +116 -0
  202. package/md_cg/test_i27_e041_identity.py +128 -0
  203. package/md_cg/test_i28_hotcache_prodpath.py +122 -0
  204. package/md_cg/test_identity_attribution.py +147 -147
  205. package/md_cg/test_index_durability.py +224 -224
  206. package/md_cg/test_interop.py +93 -0
  207. package/md_cg/test_lifecycle.py +309 -309
  208. package/md_cg/test_linkref.py +306 -306
  209. package/md_cg/test_lock.py +43 -43
  210. package/md_cg/test_md_access_parity.py +255 -255
  211. package/md_cg/test_md_writepath.py +345 -345
  212. package/md_cg/test_mdstore_search_parity.py +160 -0
  213. package/md_cg/test_mr_m2.py +587 -587
  214. package/md_cg/test_mr_m3.py +710 -710
  215. package/md_cg/test_mr_m4.py +485 -485
  216. package/md_cg/test_p0.py +250 -250
  217. package/md_cg/test_p1.py +316 -316
  218. package/md_cg/test_p10_identity.py +173 -173
  219. package/md_cg/test_p11_consistency.py +233 -233
  220. package/md_cg/test_p12_metacognition.py +212 -212
  221. package/md_cg/test_p13_encryption.py +241 -241
  222. package/md_cg/test_p14_sustain.py +249 -249
  223. package/md_cg/test_p15_scrub.py +280 -280
  224. package/md_cg/test_p16_self_state.py +301 -301
  225. package/md_cg/test_p17_predict.py +354 -354
  226. package/md_cg/test_p18_whitebox.py +171 -171
  227. package/md_cg/test_p19_migrate_roleplay.py +149 -149
  228. package/md_cg/test_p20_evolution.py +315 -315
  229. package/md_cg/test_p21_tokens.py +293 -270
  230. package/md_cg/test_p22_theory.py +175 -175
  231. package/md_cg/test_p23_links.py +311 -311
  232. package/md_cg/test_p24_evidence.py +227 -227
  233. package/md_cg/test_p25_weights.py +156 -156
  234. package/md_cg/test_p26_refindex.py +416 -416
  235. package/md_cg/test_p27_docindex.py +765 -765
  236. package/md_cg/test_p28_refcheck.py +305 -305
  237. package/md_cg/test_p29_session_ingest_export.py +354 -333
  238. package/md_cg/test_p3.py +11 -2
  239. package/md_cg/test_p30_maintain.py +330 -330
  240. package/md_cg/test_p31_insight.py +534 -534
  241. package/md_cg/test_p32_backfill.py +298 -298
  242. package/md_cg/test_p33_ccg_wiring.py +293 -293
  243. package/md_cg/test_p34_crosscheck.py +331 -331
  244. package/md_cg/test_p35_conditioned_claim.py +252 -252
  245. package/md_cg/test_p36_kp_align.py +230 -230
  246. package/md_cg/test_p37_condition_space.py +248 -248
  247. package/md_cg/test_p38_concurrent_flush.py +102 -0
  248. package/md_cg/test_p38_contextualize.py +273 -273
  249. package/md_cg/test_p39_verify_flow.py +113 -0
  250. package/md_cg/test_p39_vision_evidence.py +369 -369
  251. package/md_cg/test_p40_refine_worklist.py +241 -241
  252. package/md_cg/test_p41_evolve_patrol.py +224 -224
  253. package/md_cg/test_p42_provenance.py +269 -269
  254. package/md_cg/test_p43_pooling.py +412 -398
  255. package/md_cg/test_p44_md_whitebox.py +231 -231
  256. package/md_cg/test_p45_session_identity.py +219 -219
  257. package/md_cg/test_p46_unit_scope.py +272 -272
  258. package/md_cg/test_p47_session_view.py +281 -0
  259. package/md_cg/test_p4_fuzzy.py +223 -223
  260. package/md_cg/test_p5_semantic.py +226 -226
  261. package/md_cg/test_p6_consolidate.py +440 -387
  262. package/md_cg/test_p7_goals_recent.py +202 -202
  263. package/md_cg/test_p8_subgraph_chain.py +200 -200
  264. package/md_cg/test_p9_forget_protect.py +231 -231
  265. package/md_cg/test_predict_beta.py +135 -135
  266. package/md_cg/test_preflight_failclosed.py +100 -100
  267. package/md_cg/test_progressive.py +146 -146
  268. package/md_cg/test_protocol.py +243 -243
  269. package/md_cg/test_reach.py +378 -378
  270. package/md_cg/test_reach_keys.py +201 -201
  271. package/md_cg/test_read_clip.py +141 -141
  272. package/md_cg/test_readcache_prodpath.py +155 -0
  273. package/md_cg/test_retr_gates_prodpath.py +140 -0
  274. package/md_cg/test_retr_s1.py +340 -340
  275. package/md_cg/test_retr_s1b.py +209 -209
  276. package/md_cg/test_retr_s3.py +194 -194
  277. package/md_cg/test_retr_s4.py +163 -163
  278. package/md_cg/test_retr_s5.py +200 -200
  279. package/md_cg/test_retr_s6.py +157 -157
  280. package/md_cg/test_retr_s7.py +384 -384
  281. package/md_cg/test_retr_s8_time.py +369 -316
  282. package/md_cg/test_retr_s9_edges.py +286 -286
  283. package/md_cg/test_retr_s9_entity_ctx.py +175 -175
  284. package/md_cg/test_review_conformance.py +367 -367
  285. package/md_cg/test_role_views.py +354 -354
  286. package/md_cg/test_sem_noise.py +242 -242
  287. package/md_cg/test_semantic_canonical.py +241 -241
  288. package/md_cg/test_subproc_encoding.py +192 -192
  289. package/md_cg/test_sustain_mutual.py +153 -153
  290. package/md_cg/test_tasks.py +409 -409
  291. package/md_cg/test_tool_face.py +189 -189
  292. package/md_cg/test_transfer.py +180 -180
  293. package/md_cg/test_trust.py +361 -361
  294. package/md_cg/test_twophase.py +286 -286
  295. package/md_cg/test_v14_fixes.py +397 -397
  296. package/md_cg/test_validity_filter.py +280 -280
  297. package/md_cg/test_verify_answer.py +138 -138
  298. package/md_cg/test_wisdom_md_store.py +292 -292
  299. package/md_cg/test_writelimit.py +197 -197
  300. package/md_cg/test_writepipe.py +214 -214
  301. package/md_cg/theory.py +273 -273
  302. package/md_cg/tokens.py +677 -663
  303. package/md_cg/tool_face.py +260 -260
  304. package/md_cg/trust.py +986 -950
  305. package/md_cg/twophase.py +231 -231
  306. package/md_cg/units.py +667 -667
  307. package/md_cg/vision_evidence.py +666 -666
  308. package/md_cg/weights.py +624 -624
  309. package/md_cg/whitebox.py +527 -527
  310. package/md_cg/whitebox_kb/__init__.py +37 -37
  311. package/md_cg/whitebox_kb/aeis_core/__init__.py +42 -42
  312. package/md_cg/whitebox_kb/aeis_core/semantic.py +280 -280
  313. package/md_cg/whitebox_kb/aeis_core/textutil.py +13 -13
  314. package/md_cg/whitebox_kb/engine.py +310 -310
  315. package/md_cg/whitebox_kb/seed_knowledge//346/231/272/350/203/275/350/256/2723.4.md +5260 -5260
  316. package/md_cg/whitebox_kb/wisdom/browser_units.py +2631 -2631
  317. package/md_cg/whitebox_kb/wisdom/causal_discover.py +432 -432
  318. package/md_cg/whitebox_kb/wisdom/chat_engine.py +1506 -1506
  319. package/md_cg/whitebox_kb/wisdom/code_solidified.json +6195 -6195
  320. package/md_cg/whitebox_kb/wisdom/compiler_code_units.py +3033 -3033
  321. package/md_cg/whitebox_kb/wisdom/condition_algebra.py +112 -112
  322. package/md_cg/whitebox_kb/wisdom/condition_frame.py +315 -315
  323. package/md_cg/whitebox_kb/wisdom/condition_kb.py +108 -108
  324. package/md_cg/whitebox_kb/wisdom/conflict_map.json +4445 -4445
  325. package/md_cg/whitebox_kb/wisdom/core/lexer.py +512 -512
  326. package/md_cg/whitebox_kb/wisdom/core/name_checker.py +1023 -1023
  327. package/md_cg/whitebox_kb/wisdom/cspmn.py +258 -258
  328. package/md_cg/whitebox_kb/wisdom/csre.py +264 -264
  329. package/md_cg/whitebox_kb/wisdom/danmaku_audit.py +252 -252
  330. package/md_cg/whitebox_kb/wisdom/distilled_condition_units.json +6417 -6417
  331. package/md_cg/whitebox_kb/wisdom/docs/WB-EVAL-20260902b.json +1950 -1950
  332. package/md_cg/whitebox_kb/wisdom/docs/WB-EVAL-20260902c.json +1296 -1296
  333. package/md_cg/whitebox_kb/wisdom/docs/whitebox_capability_graph_demo.json +59 -59
  334. package/md_cg/whitebox_kb/wisdom/graph_db_units.py +3089 -3089
  335. package/md_cg/whitebox_kb/wisdom/knowledge_points.py +318 -318
  336. package/md_cg/whitebox_kb/wisdom/md_access.py +470 -470
  337. package/md_cg/whitebox_kb/wisdom/md_store.py +276 -251
  338. package/md_cg/whitebox_kb/wisdom/migrate_wisdom.py +476 -476
  339. package/md_cg/whitebox_kb/wisdom/navigate.py +248 -248
  340. package/md_cg/whitebox_kb/wisdom/neural_retrieve.py +224 -224
  341. package/md_cg/whitebox_kb/wisdom/os_units.py +2735 -2735
  342. package/md_cg/whitebox_kb/wisdom/pattern_separation.py +376 -376
  343. package/md_cg/whitebox_kb/wisdom/prereq_map.json +364 -364
  344. package/md_cg/whitebox_kb/wisdom/python_code_units.py +2766 -2766
  345. package/md_cg/whitebox_kb/wisdom/role_solidified.json +7 -7
  346. package/md_cg/whitebox_kb/wisdom/route_memory.py +244 -244
  347. package/md_cg/whitebox_kb/wisdom/scene_reconstruction.py +148 -148
  348. package/md_cg/whitebox_kb/wisdom/snr_report.json +40 -40
  349. package/md_cg/whitebox_kb/wisdom/test_code_compose_domains.py +7541 -7541
  350. package/md_cg/whitebox_kb/wisdom/test_compiler_self_bootstrap.py +354 -354
  351. package/md_cg/whitebox_kb/wisdom/test_ecosystem_assembly.py +158 -158
  352. package/md_cg/whitebox_kb/wisdom/test_ecosystem_demos.py +193 -193
  353. package/md_cg/whitebox_kb/wisdom/test_graph_db.py +292 -292
  354. package/md_cg/whitebox_kb/wisdom/test_python_self_bootstrap.py +160 -160
  355. package/md_cg/whitebox_kb/wisdom/trigger_words_index.json +4366 -4366
  356. package/md_cg/whitebox_kb/wisdom/verifier.py +1297 -1297
  357. package/md_cg/writelimit.py +356 -356
  358. package/md_cg/writepipe.py +550 -542
  359. package/package.json +97 -96
  360. package/skills/plugin.json +54 -54
  361. package/skills/skills/designer-perspective/SKILL.md +158 -158
  362. package/skills/skills/designer-perspective/references/01-observation-position.md +66 -66
  363. package/skills/skills/designer-perspective/references/02-structure-recognition.md +62 -62
  364. package/skills/skills/designer-perspective/references/03-direction-judgment.md +55 -55
  365. package/skills/skills/designer-perspective/references/04-qualification-verdict.md +72 -72
  366. package/skills/skills/designer-perspective/references/05-condition-attribution.md +74 -74
  367. package/skills/skills/designer-perspective/scripts/designer.py +545 -545
  368. package/skills/skills/designer-perspective/tests/cases.jsonl +17 -17
  369. package/skills/skills/designer-perspective/tests/selftest.py +61 -61
  370. package/skills/skills/lingshu-browser/SKILL.md +60 -60
  371. package/skills/skills/lingshu-compiler/SKILL.md +56 -56
  372. package/skills/skills/lingshu-compiler/units/analyze-type-infer/SKILL.md +45 -45
  373. package/skills/skills/lingshu-compiler/units/check-name-real/SKILL.md +45 -45
  374. package/skills/skills/lingshu-compiler/units/compile-assign/SKILL.md +45 -45
  375. package/skills/skills/lingshu-compiler/units/compile-expr-tree/SKILL.md +45 -45
  376. package/skills/skills/lingshu-compiler/units/compile-full-pipeline/SKILL.md +45 -45
  377. package/skills/skills/lingshu-compiler/units/compile-func-def/SKILL.md +45 -45
  378. package/skills/skills/lingshu-compiler/units/compile-if-then/SKILL.md +45 -45
  379. package/skills/skills/lingshu-compiler/units/compile-logic-expr/SKILL.md +45 -45
  380. package/skills/skills/lingshu-compiler/units/compile-recursive/SKILL.md +45 -45
  381. package/skills/skills/lingshu-compiler/units/compile-scope/SKILL.md +45 -45
  382. package/skills/skills/lingshu-compiler/units/compile-type-check/SKILL.md +45 -45
  383. package/skills/skills/lingshu-compiler/units/compile-while/SKILL.md +45 -45
  384. package/skills/skills/lingshu-compiler/units/compiler-0010c4bf/SKILL.md +45 -45
  385. package/skills/skills/lingshu-compiler/units/compiler-0355bffb/SKILL.md +45 -45
  386. package/skills/skills/lingshu-compiler/units/compiler-0361708a/SKILL.md +45 -45
  387. package/skills/skills/lingshu-compiler/units/compiler-054a0414/SKILL.md +45 -45
  388. package/skills/skills/lingshu-compiler/units/compiler-05a1691a/SKILL.md +45 -45
  389. package/skills/skills/lingshu-compiler/units/compiler-05eeed1e/SKILL.md +45 -45
  390. package/skills/skills/lingshu-compiler/units/compiler-0622a1f6/SKILL.md +45 -45
  391. package/skills/skills/lingshu-compiler/units/compiler-08b54217/SKILL.md +45 -45
  392. package/skills/skills/lingshu-compiler/units/compiler-0a62b70c/SKILL.md +45 -45
  393. package/skills/skills/lingshu-compiler/units/compiler-0ab24d00/SKILL.md +45 -45
  394. package/skills/skills/lingshu-compiler/units/compiler-0e093688/SKILL.md +45 -45
  395. package/skills/skills/lingshu-compiler/units/compiler-0e82b966/SKILL.md +45 -45
  396. package/skills/skills/lingshu-compiler/units/compiler-0ee9b9b9/SKILL.md +45 -45
  397. package/skills/skills/lingshu-compiler/units/compiler-0f3787e6/SKILL.md +45 -45
  398. package/skills/skills/lingshu-compiler/units/compiler-1028685f/SKILL.md +45 -45
  399. package/skills/skills/lingshu-compiler/units/compiler-11897630/SKILL.md +45 -45
  400. package/skills/skills/lingshu-compiler/units/compiler-16661b9b/SKILL.md +45 -45
  401. package/skills/skills/lingshu-compiler/units/compiler-1f722303/SKILL.md +45 -45
  402. package/skills/skills/lingshu-compiler/units/compiler-25be1262/SKILL.md +45 -45
  403. package/skills/skills/lingshu-compiler/units/compiler-2a76ba07/SKILL.md +45 -45
  404. package/skills/skills/lingshu-compiler/units/compiler-2dbea54a/SKILL.md +45 -45
  405. package/skills/skills/lingshu-compiler/units/compiler-2df52f16/SKILL.md +45 -45
  406. package/skills/skills/lingshu-compiler/units/compiler-2ec2c9d2/SKILL.md +45 -45
  407. package/skills/skills/lingshu-compiler/units/compiler-2f8c8f39/SKILL.md +45 -45
  408. package/skills/skills/lingshu-compiler/units/compiler-38378ac7/SKILL.md +45 -45
  409. package/skills/skills/lingshu-compiler/units/compiler-39457d2e/SKILL.md +45 -45
  410. package/skills/skills/lingshu-compiler/units/compiler-39fb5926/SKILL.md +45 -45
  411. package/skills/skills/lingshu-compiler/units/compiler-47f4fbfa/SKILL.md +45 -45
  412. package/skills/skills/lingshu-compiler/units/compiler-4a8cd1f1/SKILL.md +45 -45
  413. package/skills/skills/lingshu-compiler/units/compiler-4b230b6b/SKILL.md +45 -45
  414. package/skills/skills/lingshu-compiler/units/compiler-4cbbda95/SKILL.md +45 -45
  415. package/skills/skills/lingshu-compiler/units/compiler-4d5a68ff/SKILL.md +45 -45
  416. package/skills/skills/lingshu-compiler/units/compiler-56dc9bdd/SKILL.md +45 -45
  417. package/skills/skills/lingshu-compiler/units/compiler-57e76ebe/SKILL.md +45 -45
  418. package/skills/skills/lingshu-compiler/units/compiler-61ff016b/SKILL.md +45 -45
  419. package/skills/skills/lingshu-compiler/units/compiler-63eae588/SKILL.md +45 -45
  420. package/skills/skills/lingshu-compiler/units/compiler-64c4224b/SKILL.md +45 -45
  421. package/skills/skills/lingshu-compiler/units/compiler-66377955/SKILL.md +45 -45
  422. package/skills/skills/lingshu-compiler/units/compiler-674ab4f6/SKILL.md +45 -45
  423. package/skills/skills/lingshu-compiler/units/compiler-6af76fd6/SKILL.md +45 -45
  424. package/skills/skills/lingshu-compiler/units/compiler-6d979db2/SKILL.md +45 -45
  425. package/skills/skills/lingshu-compiler/units/compiler-6de326c0/SKILL.md +45 -45
  426. package/skills/skills/lingshu-compiler/units/compiler-6f1c0eea/SKILL.md +45 -45
  427. package/skills/skills/lingshu-compiler/units/compiler-724d6c9b/SKILL.md +45 -45
  428. package/skills/skills/lingshu-compiler/units/compiler-7690177f/SKILL.md +45 -45
  429. package/skills/skills/lingshu-compiler/units/compiler-7b229a7d/SKILL.md +45 -45
  430. package/skills/skills/lingshu-compiler/units/compiler-7f471b3a/SKILL.md +45 -45
  431. package/skills/skills/lingshu-compiler/units/compiler-815cad08/SKILL.md +45 -45
  432. package/skills/skills/lingshu-compiler/units/compiler-83c61634/SKILL.md +45 -45
  433. package/skills/skills/lingshu-compiler/units/compiler-8c798c81/SKILL.md +45 -45
  434. package/skills/skills/lingshu-compiler/units/compiler-8dd747ac/SKILL.md +45 -45
  435. package/skills/skills/lingshu-compiler/units/compiler-90324d0a/SKILL.md +45 -45
  436. package/skills/skills/lingshu-compiler/units/compiler-94b8d72d/SKILL.md +45 -45
  437. package/skills/skills/lingshu-compiler/units/compiler-94f12231/SKILL.md +45 -45
  438. package/skills/skills/lingshu-compiler/units/compiler-95937c16/SKILL.md +45 -45
  439. package/skills/skills/lingshu-compiler/units/compiler-98a5625b/SKILL.md +45 -45
  440. package/skills/skills/lingshu-compiler/units/compiler-98b4c42f/SKILL.md +45 -45
  441. package/skills/skills/lingshu-compiler/units/compiler-98e3894a/SKILL.md +45 -45
  442. package/skills/skills/lingshu-compiler/units/compiler-9bdfe4b8/SKILL.md +45 -45
  443. package/skills/skills/lingshu-compiler/units/compiler-9d9b4e83/SKILL.md +45 -45
  444. package/skills/skills/lingshu-compiler/units/compiler-9f7be5ad/SKILL.md +45 -45
  445. package/skills/skills/lingshu-compiler/units/compiler-a6daf076/SKILL.md +45 -45
  446. package/skills/skills/lingshu-compiler/units/compiler-a7995a0c/SKILL.md +45 -45
  447. package/skills/skills/lingshu-compiler/units/compiler-a8399248/SKILL.md +45 -45
  448. package/skills/skills/lingshu-compiler/units/compiler-aabbd099/SKILL.md +45 -45
  449. package/skills/skills/lingshu-compiler/units/compiler-afe169d8/SKILL.md +45 -45
  450. package/skills/skills/lingshu-compiler/units/compiler-b0678bda/SKILL.md +45 -45
  451. package/skills/skills/lingshu-compiler/units/compiler-b09bd196/SKILL.md +45 -45
  452. package/skills/skills/lingshu-compiler/units/compiler-b1396e23/SKILL.md +45 -45
  453. package/skills/skills/lingshu-compiler/units/compiler-b9b31ce0/SKILL.md +45 -45
  454. package/skills/skills/lingshu-compiler/units/compiler-c10264a7/SKILL.md +45 -45
  455. package/skills/skills/lingshu-compiler/units/compiler-cb1e8e4b/SKILL.md +45 -45
  456. package/skills/skills/lingshu-compiler/units/compiler-ccafd438/SKILL.md +45 -45
  457. package/skills/skills/lingshu-compiler/units/compiler-cda9c262/SKILL.md +45 -45
  458. package/skills/skills/lingshu-compiler/units/compiler-ce648068/SKILL.md +45 -45
  459. package/skills/skills/lingshu-compiler/units/compiler-cf5776a4/SKILL.md +45 -45
  460. package/skills/skills/lingshu-compiler/units/compiler-d974e5d3/SKILL.md +45 -45
  461. package/skills/skills/lingshu-compiler/units/compiler-e3979fd3/SKILL.md +45 -45
  462. package/skills/skills/lingshu-compiler/units/compiler-eb1cf2b5/SKILL.md +45 -45
  463. package/skills/skills/lingshu-compiler/units/compiler-ecb30d5b/SKILL.md +45 -45
  464. package/skills/skills/lingshu-compiler/units/compiler-f8c8b24b/SKILL.md +45 -45
  465. package/skills/skills/lingshu-compiler/units/compiler-f99fedbe/SKILL.md +45 -45
  466. package/skills/skills/lingshu-compiler/units/compiler-fa8ff5f7/SKILL.md +45 -45
  467. package/skills/skills/lingshu-compiler/units/compiler-fe1b058d/SKILL.md +45 -45
  468. package/skills/skills/lingshu-compiler/units/lex-chinese-program/SKILL.md +45 -45
  469. package/skills/skills/lingshu-compiler/units/lex-dao-de-jing/SKILL.md +45 -45
  470. package/skills/skills/lingshu-compiler/units/lex-nine-chapters/SKILL.md +45 -45
  471. package/skills/skills/lingshu-compiler/units/vm-arithmetic/SKILL.md +45 -45
  472. package/skills/skills/lingshu-compiler/units/vm-array-ops/SKILL.md +45 -45
  473. package/skills/skills/lingshu-compiler/units/vm-closure-call/SKILL.md +45 -45
  474. package/skills/skills/lingshu-compiler/units/vm-closure-create/SKILL.md +45 -45
  475. package/skills/skills/lingshu-compiler/units/vm-compare/SKILL.md +45 -45
  476. package/skills/skills/lingshu-compiler/units/vm-cond-jump/SKILL.md +45 -45
  477. package/skills/skills/lingshu-compiler/units/vm-cond-space/SKILL.md +45 -45
  478. package/skills/skills/lingshu-compiler/units/vm-exception/SKILL.md +45 -45
  479. package/skills/skills/lingshu-compiler/units/vm-func-call/SKILL.md +45 -45
  480. package/skills/skills/lingshu-compiler/units/vm-loop-run/SKILL.md +45 -45
  481. package/skills/skills/lingshu-compiler/units/vm-profiling/SKILL.md +45 -45
  482. package/skills/skills/lingshu-compiler/units/vm-refcount/SKILL.md +45 -45
  483. package/skills/skills/lingshu-compiler/units/vm-run-loop/SKILL.md +45 -45
  484. package/skills/skills/lingshu-compiler/units/vm-short-circuit/SKILL.md +45 -45
  485. package/skills/skills/lingshu-compiler/units/vm-stack-guard/SKILL.md +45 -45
  486. package/skills/skills/lingshu-compiler/units/vm-stack-ops/SKILL.md +45 -45
  487. package/skills/skills/lingshu-compiler/units/vm-trust-accum/SKILL.md +45 -45
  488. package/skills/skills/lingshu-graph/SKILL.md +63 -63
  489. package/skills/skills/lingshu-net/SKILL.md +48 -48
  490. package/skills/skills/lingshu-os/SKILL.md +64 -64
  491. package/skills/skills/lingshu-pylang/SKILL.md +71 -71
  492. package/src/bridge.ts +401 -401
  493. package/src/hooks.ts +38 -2
  494. package/src/lib/datapath.ts +326 -326
  495. package/src/lib/mdcg_client.ts +413 -413
  496. package/src/lib/mutual.ts +428 -428
  497. package/src/lib/prompt_safety.ts +62 -62
  498. package/src/lib/python_path.ts +71 -71
  499. package/src/lib/roleplay_web.ts +932 -932
  500. package/src/lib/token_store.ts +192 -192
  501. package/src/tools.ts +212 -212
  502. package/zcode/AGENTS.md +11 -3
  503. package/zcode/README.md +41 -41
  504. /package/docs/{mdcg → hive}//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" +0 -0
@@ -1,433 +1,433 @@
1
- # -*- coding: utf-8 -*-
2
- """ccgc 验收:对话记录 → CCG 六要素编译器(V1-V20)。
3
-
4
- 运行:python -m md_cg.test_ccgc
5
-
6
- 三条判据在实现层为何是**机械可判定**的(不依赖自觉):
7
- ① 「LLM 不得自己验证自己」——候选结构里没有签章字段,且 attest 机械比对
8
- `verifier != compiled_by`(E041);link 再挡一次(双闸)。
9
- ② 「幻觉」——名实门 E010/E011:每个写入值必须是源文本字面子串,零灰区。
10
- ③ 「缺参数」——是编译错误(E001-E004)而非 DEFER,`success = (errors == [])`。
11
-
12
- V16-V20 覆盖**跨调用形态**(三次独立 MCP 调用传不动对象,只能落盘):
13
- 候选与签章绑定在 `_ccgc_pending/`(hash 防篡改)+ 复核通道三态 + 蜂巢契约
14
- 端到端(假执行器模拟 serve,无网络无密钥也能确定性验收「通道与签章」)。
15
- """
16
- from __future__ import annotations
17
-
18
- import json
19
- import os
20
- import shutil
21
- import sys
22
- import tempfile
23
- import threading
24
- import time
25
-
26
- from . import audit, backfill, ccgc, nodefile, units
27
- from .mdcos import MdCGOS
28
-
29
- PASS = FAIL = 0
30
- FAILS = []
31
-
32
- DIALOG = ("文件摄取分派:按扩展名把文件路由到对应摄取器"
33
- "。该方法使用扩展名映射表进行路由"
34
- "。此功能在本地文件系统中生效"
35
- "。仅对本地可读文件生效"
36
- "。2026-09-16"
37
- "。通过回放测试验证"
38
- "。二进制文件不适用")
39
-
40
- SLOTS = {
41
- "observation_position": {"value": "此功能在本地文件系统中生效"},
42
- "observation_tool": {"value": "该方法使用扩展名映射表进行路由"},
43
- "time_window": {"value": [0.0, 9999999999.0]},
44
- "existence_constraint": {"value": "仅对本地可读文件生效"},
45
- }
46
-
47
- MARKS = {
48
- "功能名": {"value": "文件摄取分派:按扩展名把文件路由到对应摄取器"},
49
- "子功能": {"value": "按扩展名把文件路由到对应摄取器"},
50
- "执行": {"value": "使用扩展名映射表进行路由"},
51
- "验证方式": {"value": "回放测试", "basis": "test"},
52
- "不适用条件": {"value": "二进制文件不适用"},
53
- }
54
-
55
-
56
- def ok(cond, label):
57
- global PASS, FAIL
58
- if cond:
59
- PASS += 1
60
- else:
61
- FAIL += 1
62
- FAILS.append(label)
63
- print(" FAIL " + label)
64
-
65
-
66
- def _has(errs, code):
67
- return any(str(e).startswith(code) for e in (errs or []))
68
-
69
-
70
- def _seed(root):
71
- cg = MdCGOS(root)
72
- cg.add("tgt", "# 功能名:待编译节点\n\n占位正文。\n", layer="knowledge")
73
- cg.flush()
74
- cg.rebuild_index()
75
- return cg
76
-
77
-
78
- def _fake_serve(jobs, stop, seen):
79
- """假蜂巢执行器:读 spec.json 写 result.json(契约与 hive 的 LLM 委托型一致)。
80
-
81
- 用线程模拟 serve 侧的单元执行,使**复核通道与签章搬运**在无网络无密钥下
82
- 可确定性验收——被测的是通道契约,不是模型质量。seen 记录 spec 形态供断言。
83
- """
84
- while not stop.is_set():
85
- try:
86
- names = sorted(os.listdir(jobs))
87
- except OSError:
88
- names = []
89
- for jid in names:
90
- d = os.path.join(jobs, jid)
91
- sp = os.path.join(d, units.SPEC_FILE)
92
- rp = os.path.join(d, units.RESULT_FILE)
93
- if not jid.startswith("h") or not os.path.isfile(sp) or os.path.exists(rp):
94
- continue
95
- try:
96
- with open(sp, encoding="utf-8") as f:
97
- spec = json.load(f)
98
- except (OSError, ValueError):
99
- continue
100
- prompt = str(spec.get("user_prompt") or spec.get("prompt") or "")
101
- seen.update({"role": spec.get("role"), "model": spec.get("model"),
102
- "prompt_len": len(prompt),
103
- "prompt_has_dialog": "文件摄取分派" in prompt})
104
- payload = {"verdict": seen.get("verdict") or "accept",
105
- "reason": "假单元复核:候选与对话原文一致",
106
- "slot_corrections": {}}
107
- try:
108
- with open(rp, "w", encoding="utf-8") as f:
109
- json.dump({"ok": True, "model": spec.get("model"),
110
- "content": json.dumps(payload, ensure_ascii=False)},
111
- f, ensure_ascii=False)
112
- except OSError:
113
- continue
114
- time.sleep(0.05)
115
-
116
-
117
- def _import_mcp():
118
- """延迟导入工具面(避免测试顶部把 server 依赖一并拉起)。"""
119
- try:
120
- from . import mcp_server
121
- return mcp_server
122
- except Exception: # noqa: BLE001
123
- return None
124
-
125
-
126
- def main():
127
- global PASS, FAIL
128
- tmp = tempfile.mkdtemp(prefix="mdcg_ccgc_")
129
- try:
130
- root = os.path.join(tmp, "root")
131
- os.makedirs(root, exist_ok=True)
132
- cg = _seed(root)
133
-
134
- # ---------- V1 缺参即编译错误(裁定 B) ----------
135
- r = ccgc.compile_dialog("", "tgt", "agent:a1")
136
- ok((not r.success) and _has(r.errors, "E001"), "V1a 缺 dialog → E001")
137
- r = ccgc.compile_dialog(DIALOG, "", "agent:a1")
138
- ok((not r.success) and _has(r.errors, "E002"), "V1b 缺 node_id → E002")
139
- r = ccgc.compile_dialog(DIALOG, "tgt", "")
140
- ok((not r.success) and _has(r.errors, "E003"), "V1c 缺 actor → E003")
141
- r = ccgc.compile_dialog(DIALOG, "nope", "agent:a1", cg=cg)
142
- ok((not r.success) and _has(r.errors, "E002"), "V1d 节点不存在 → E002")
143
- ok(bool(r.verdict) and r.verdict.get("authority") == "VERIFICATION_UNIT",
144
- "V1e 终裁 authority=VERIFICATION_UNIT")
145
-
146
- # ---------- V2 名实门:幻觉在编译期被机械检出 ----------
147
- bad_slots = dict(SLOTS)
148
- bad_slots["observation_tool"] = {"value": "该方法使用神经网络进行路由",
149
- "span": "该方法使用神经网络进行路由"}
150
- r_bad = ccgc.compile_dialog(DIALOG, "tgt", "agent:a1",
151
- slots=bad_slots, marks=MARKS, cg=cg)
152
- ok((not r_bad.success) and _has(r_bad.errors, "E011"), "V2a 捏造值 → E011")
153
- ok(len(r_bad.ungrounded) >= 1, "V2b 未过门项进入 ungrounded 台账")
154
-
155
- bad2 = dict(SLOTS)
156
- bad2["observation_position"] = {"value": "此功能在本地文件系统中生效",
157
- "span": "不存在的引用文本"}
158
- r2 = ccgc.compile_dialog(DIALOG, "tgt", "agent:a1",
159
- slots=bad2, marks=MARKS, cg=cg)
160
- ok((not r2.success) and _has(r2.errors, "E010"), "V2c 引用定位失败 → E010")
161
-
162
- class EvilParser(object):
163
- """冒充 LLM 通道:给出看起来合理但源文本里没有的值。"""
164
-
165
- def candidates(self, dialog, ctx):
166
- return {"marks": dict(MARKS), "slots": dict(bad_slots)}
167
-
168
- r3 = ccgc.compile_dialog(DIALOG, "tgt", "agent:a1",
169
- parser=EvilParser(), cg=cg)
170
- ok((not r3.success) and _has(r3.errors, "E011"),
171
- "V2d 外部 parser 幻觉同样被 E011 拦截(结构级阻断)")
172
-
173
- # ---------- V3 四槽强制 ----------
174
- r4 = ccgc.compile_dialog(DIALOG, "tgt", "agent:a1",
175
- slots={"observation_position": SLOTS["observation_position"]},
176
- marks=MARKS, cg=cg)
177
- ok((not r4.success) and _has(r4.errors, "E020"), "V3a 四槽不全 → E020")
178
-
179
- # ---------- V4/V5 唯一合成入口 + 六要素齐备 ----------
180
- plain_slots = {k: v.get("value") for k, v in SLOTS.items()}
181
- r = ccgc.compile_dialog(DIALOG, "tgt", "agent:a1",
182
- slots=SLOTS, marks=MARKS, cg=cg)
183
- ok(r.success, "V4a 完整入参编译成功")
184
- ok(r.lines.get("生效条件") == nodefile.condition_space_text(plain_slots),
185
- "V4b 生效条件 == nodefile.condition_space_text(唯一入口)")
186
- ok(set(r.lines) == set(nodefile.CCG_MARKS), "V5a 六要素齐备")
187
- ok(r.sources.get("verification_basis") == "test", "V5b 验证基底 test")
188
-
189
- # ---------- V7 自证拒绝(裁定 A 核心) ----------
190
- a_self = ccgc.attest("tgt", ccgc.ACCEPT, "agent:a1", "agent:a1", cg=cg)
191
- ok((not a_self.ok) and "E041" in a_self.error, "V7a 验证方==编译方 → E041")
192
- a_defer = ccgc.attest("tgt", ccgc.DEFER, "designer", "agent:a1", cg=cg)
193
- ok((not a_defer.ok) and "E042" in a_defer.error, "V7b DEFER 不构成签章")
194
- a_ok = ccgc.attest("tgt", ccgc.ACCEPT, "designer", "agent:a1",
195
- evidence="设计者核对原文一致", cg=cg)
196
- ok(a_ok.ok and bool(a_ok.token), "V7c 编外验证方 ACCEPT → 有效签章")
197
-
198
- # ---------- V8 无章不写 ----------
199
- l0 = ccgc.link(r, None, cg=cg, apply=True)
200
- ok((not l0.ok) and any("E040" in e for e in l0.errors), "V8a 无签章 → E040 拒绝")
201
- l1 = ccgc.link(r, a_self, cg=cg, apply=True)
202
- ok(not l1.ok, "V8b 自证签章 → link 拒绝")
203
- l2 = ccgc.link(r, a_ok, cg=cg, apply=False)
204
- ok(l2.ok and l2.dry_run and l2.written == 0, "V8c dry-run 不写入")
205
- _fm_b, c_before = cg._read(cg.index["nodes"]["tgt"])
206
- ok(not nodefile.ccg_completeness(c_before)["complete"], "V5c link 前六要素不全")
207
-
208
- # ---------- link 落库 ----------
209
- l3 = ccgc.link(r, a_ok, cg=cg, apply=True)
210
- ok(l3.ok and l3.written == 6, "V8d 签章通过 → 写入六行")
211
- fm_after, c_after = cg._read(cg.index["nodes"]["tgt"])
212
- ok(nodefile.ccg_completeness(c_after)["complete"],
213
- "V5d link 后六要素齐备(可判定性提升)")
214
- ok(fm_after.get("condition_space") == plain_slots, "V4c condition_space 落 frontmatter")
215
- ok(fm_after.get("verification_basis") == "test", "V5e verification_basis 落盘")
216
-
217
- # ---------- V6 未制造条件污染 ----------
218
- rep = backfill.verify_conditions(cg)
219
- ok(rep.get("legacy_position") == 0, "V6a 弱等价残留 legacy_position == 0")
220
- ok(rep.get("from_synthesis", 0) >= 1, "V6b 生效条件来源=合成")
221
-
222
- # ---------- V9 缺验证器恒 DEFER(能力外置) ----------
223
- v = audit.audit("ccg_marks", {"node": "tgt"}, {})
224
- ok(v.get("state") == "DEFER", "V9a 未注入验证器 → DEFER(不假装通过)")
225
- ok(audit.kinds()["ccg_marks"]["basis"] == "test", "V9b ccg_marks 基底建议=test")
226
-
227
- # ---------- V11 用后续验证修正生效条件 ----------
228
- rc = ccgc.recalibrate("tgt", {"existence_constraint": "仅对本地可读文件生效"},
229
- "agent:a1", "agent:a1", cg=cg, apply=False)
230
- ok(any("E041" in e for e in rc.errors), "V11a 修正方==编译方 → E041")
231
- rc = ccgc.recalibrate("tgt", {"生效条件": "手写条件"}, "designer", "agent:a1",
232
- cg=cg, apply=False)
233
- ok(any("E043" in e for e in rc.errors), "V11b 非四槽键 → E043(无第二通路)")
234
- rc = ccgc.recalibrate("tgt", {"observation_tool": "该方法使用扩展名映射表进行路由"},
235
- "designer", "agent:a1", evidence="实测复核:方法槽无误",
236
- cg=cg, apply=True)
237
- ok(rc.ok, "V11c 编外验证方修正获准")
238
- _fm_r, c_r = cg._read(cg.index["nodes"]["tgt"])
239
- ok(nodefile.ccg_completeness(c_r)["complete"], "V11d 修正后仍齐备")
240
- logs = ccgc._read_jsonl(ccgc._log_path(cg))
241
- ok(any(x.get("action") == "ccgc_recalibrate" and x.get("slots_before") is not None
242
- and x.get("slots_after") is not None for x in logs),
243
- "V11e 修正留痕含 before/after(可溯源)")
244
- ok(any(x.get("action") == "ccgc_attest" for x in logs), "V11f 签章留痕可查")
245
-
246
- # ---------- V13 内生规则解析器:诚实下界 ----------
247
- r_rule = ccgc.compile_dialog(DIALOG, "tgt", "agent:a1", cg=cg)
248
- ok(any("下界能力" in w for w in r_rule.warnings), "V13a 未注入解析器时如实声明下界")
249
- bad_spans = [s for arr in r_rule.spans.values() for s in arr
250
- if s and s not in DIALOG]
251
- ok(not bad_spans, "V13b 内生解析器引用全部 grounded")
252
-
253
- # ---------- V14 产物无占位残留 ----------
254
- ok(not any(nodefile.is_placeholder_text(x) for x in r.lines.values()),
255
- "V14 产物无占位残留")
256
-
257
- # ---------- V15 裁定 B 术语落地:单一真源 + 六要素一一对应 ----------
258
- ok(ccgc.CONTRACT_ROLES is nodefile.CCG_CONTRACT_ROLES,
259
- "V15a 术语真源唯一(ccgc 引用 nodefile,不另定义一份)")
260
- ok(tuple(nodefile.CCG_CONTRACT_ROLES) == tuple(nodefile.CCG_MARKS),
261
- "V15b 契约角色与六要素一一对应(顺序一致)")
262
- ok(nodefile.CCG_CONTRACT_ROLES["生效条件"] == "前置条件 precondition",
263
- "V15c 生效条件角色 = precondition(裁定 B)")
264
-
265
- # ---------- V16 pending:候选与签章绑定(跨 MCP 三次独立调用形态) ----------
266
- p_path = ccgc.pending_path(cg, "tgt")
267
- ok(bool(p_path) and ccgc.PENDING_DIR in p_path, "V16a pending 落 LAYERS 之外的冷区")
268
- sv = ccgc.save_pending(cg, r)
269
- ok(bool(sv.get("ok")) and os.path.isfile(sv["path"]) and bool(sv.get("hash")),
270
- "V16b 候选落盘并留内容摘要")
271
- got = ccgc.load_pending(cg, "tgt")
272
- ok(bool(got.get("ok")) and bool(got.get("hash_ok")), "V16c 读回摘要一致(原件未被改写)")
273
- ok(got["compiled"].lines == r.lines, "V16d 读回六行 == 编译产物(无损搬运)")
274
- with open(sv["path"], encoding="utf-8") as f:
275
- rec = json.load(f)
276
- rec["compiled"]["lines"]["功能名"] = "被篡改的功能名"
277
- with open(sv["path"], "w", encoding="utf-8") as f:
278
- json.dump(rec, f, ensure_ascii=False)
279
- lx = ccgc.link_pending(cg, "tgt", apply=True)
280
- ok((not lx.ok) and any("hash" in e for e in lx.errors),
281
- "V16e 候选被改写 → hash 不符,拒绝写入(签章只忠于原件)")
282
- sv = ccgc.save_pending(cg, r, a_ok)
283
- lz = ccgc.link_pending(cg, "tgt", apply=True, actor="agent:a1")
284
- ok(lz.ok and lz.written == 6, "V16f 读回原件+签章 → 落库成功")
285
- ok(not os.path.isfile(sv["path"]), "V16g 落库成功即清 pending(暂存非存档)")
286
- ok(not any(ccgc.PENDING_DIR in str(k) for k in (cg.index.get("nodes") or {})),
287
- "V16h pending 不进索引(冷区对检索隐身)")
288
-
289
- # ---------- V17 闸门:只认编外裁决,绝不假装通过 ----------
290
- v = audit.audit("ccg_marks", {"node_id": "tgt", "unit_verdict": "ACCEPT",
291
- "verifier": "hive:reflect:h1",
292
- "evidence": "假单元复核:与原文一致"}, {})
293
- ok(v.get("state") == "ACCEPT", "V17a 编外裁决+依据 → ACCEPT")
294
- v = audit.audit("ccg_marks", {"node_id": "tgt", "unit_verdict": "ACCEPT",
295
- "verifier": "hive:reflect:h1"}, {})
296
- ok(v.get("state") == "DEFER", "V17b ACCEPT 但无依据 → DEFER(无依据不通过)")
297
- v = audit.audit("ccg_marks", {"node_id": "tgt", "unit_verdict": "ACCEPT",
298
- "verifier": "agent:a1", "evidence": "我自己验的"},
299
- {"compiled_by": "agent:a1"})
300
- ok(v.get("state") == "REJECT", "V17c 自证 → REJECT(E041 在闸门层再挡一次)")
301
- v = audit.audit("ccg_marks", {"node_id": "tgt", "unit_verdict": "ACCEPT",
302
- "evidence": "无验证方"}, {})
303
- ok(v.get("state") == "DEFER", "V17d 有裁决缺验证方标识 → DEFER")
304
- v = audit.audit("ccg_marks", {"node_id": "tgt"}, {})
305
- d = v.get("detail") or {}
306
- ok(v.get("state") == "DEFER" and bool(d.get("next")) and d.get("channel_state") in units.STATES,
307
- "V17e 无裁决 → DEFER 且给出下一步通道(不阻塞写路径)")
308
- v = audit.audit("ccg_marks", {}, {})
309
- ok(v.get("state") == "DEFER", "V17f 缺 node_id → DEFER")
310
-
311
- # ---------- V18 复核通道:三态如实 + 来源标识结构上非编译者 ----------
312
- ok(units.transport_name(units.HIVE, units.REFLECT, "h1") == "hive:reflect:h1",
313
- "V18a 蜂巢来源标识 = hive:<role>:<job>")
314
- ok(units.transport_name(units.HIVE, units.REFLECT, "h1") != "agent:a1",
315
- "V18b 来源标识结构上不可能等于编译者(裁定 A 不被误伤)")
316
- u = units.verdict_of('前置说明\n```json\n{"verdict":"accept","reason":"一致"}\n```')
317
- ok(u["verdict"] == units.ACCEPT and bool(u["parsed"]), "V18c 围栏 JSON 可解析 → ACCEPT")
318
- u = units.verdict_of("我无法判断这件事")
319
- ok(u["verdict"] == units.DEFER and not u["parsed"], "V18d 解析不出 → DEFER(不猜测)")
320
- u = units.verdict_of({"verdict": "drop", "reason": "与原文不符",
321
- "slot_corrections": {"observation_tool": "x"}})
322
- ok(u["verdict"] == units.REJECT and bool(u["slot_corrections"]),
323
- "V18e drop → REJECT(四槽修正随裁决带回)")
324
- aa = units.to_attest_args({"verdict": units.ACCEPT, "reason": "一致"}, state=units.HIVE,
325
- role=units.REFLECT, job_id="h1",
326
- compiled_by=units.transport_name(units.HIVE, units.REFLECT, "h1"))
327
- ok(aa.get("self_verify") is True, "V18f 万一自证 → 显式标记(供上层拒绝)")
328
- aa = units.to_attest_args({"verdict": units.ACCEPT, "reason": "一致"}, state=units.HIVE,
329
- role=units.REFLECT, job_id="h1", compiled_by="agent:a1")
330
- ok(not aa.get("self_verify") and aa["verifier"].startswith("hive:reflect:"),
331
- "V18g 非自证:verifier 取蜂巢来源标识(不设自证标记)")
332
- pr = units.probe(jobs=os.path.join(tmp, "nojobs"))
333
- ok(pr["state"] == units.CONFIGURE and units.ENV_MODEL in pr["hint"],
334
- "V18h 蜂巢不可用 → 返回配置指引(不自动拉起、不假装可用)")
335
- pr = units.probe(jobs=os.path.join(tmp, "nojobs"), allow_degrade=True)
336
- ok(pr["state"] == units.SUBAGENT, "V18i 显式 allow_degrade → 子代理降级(不冒充 hive)")
337
-
338
- # ---------- V19/V20 端到端:假蜂巢 → 编外裁决 → 签章 → 落库 ----------
339
- jobs = os.path.join(tmp, "jobs")
340
- os.makedirs(jobs, exist_ok=True)
341
- # 假 serve 是**本进程内的线程**,故「该 pid 是本程序」如实为真——把本程序
342
- # 口径指向本进程映像名即可(v14 缺陷 E 修复后 units 判活含**身份层**:
343
- # 旧写法心跳 pid=本进程却让 EXE 口径指向 hive.exe,身份层判假 → 通道不可用,
344
- # 那不是被测缺陷而是测试自身要与新口径对齐)。
345
- _old_exe = os.environ.get(units.ENV_EXE)
346
- os.environ[units.ENV_EXE] = sys.executable
347
- with open(os.path.join(jobs, units.SERVE_FILE), "w", encoding="utf-8") as f:
348
- json.dump({"ts": int(time.time() * 1000), "pid": os.getpid()}, f)
349
- seen = {}
350
- stop = threading.Event()
351
- th = threading.Thread(target=_fake_serve, args=(jobs, stop, seen), daemon=True)
352
- th.start()
353
- _old_model = os.environ.get(units.ENV_MODEL)
354
- os.environ[units.ENV_MODEL] = "fake-unit-model"
355
- try:
356
- pr = units.probe(jobs=jobs)
357
- ok(pr["state"] == units.HIVE, "V19a 心跳新鲜+模型已配 → HIVE 可派发")
358
- rv = units.review(digest=r, dialog=DIALOG, role=units.REFLECT, node_id="tgt",
359
- jobs=jobs, blocking=True, wait_s=30, cg=cg, actor="agent:a1")
360
- ok(rv["state"] == units.HIVE and bool(rv.get("unit")), "V19b 派发并取回编外裁决")
361
- ok((rv["unit"] or {}).get("verdict") == units.ACCEPT, "V19c 单元裁决解析为 ACCEPT")
362
- ok(seen.get("role") == units.REFLECT and seen.get("model") == "fake-unit-model"
363
- and seen.get("prompt_has_dialog"),
364
- "V19d spec 形态合蜂巢契约(role/model/复核包正文)")
365
- ok(str((rv.get("attest") or {}).get("verifier") or "").startswith("hive:reflect:"),
366
- "V19e 签章方 = 蜂巢单元标识(结构上非编译者)")
367
- at = ccgc.attest("tgt", rv["attest"]["verdict"], rv["attest"]["verifier"],
368
- "agent:a1", evidence=rv["attest"]["evidence"] or "单元复核",
369
- cg=cg)
370
- ok(at.ok, "V19f 蜂巢裁决可直接签章(E041 不被误伤)")
371
- logs = ccgc._read_jsonl(os.path.join(str(cg.root), units.LOG_NAME))
372
- ok(any(x.get("action") == "review" and x.get("job_id") for x in logs),
373
- "V19g 派发留痕(job_id 可追溯)")
374
-
375
- # --- V20 MCP 工具面:compile → review → attest/link 三段式 ---
376
- mcp = _import_mcp()
377
- ok(mcp is not None, "V20a 工具面可加载")
378
- c1 = mcp._ccg_call(cg, {"ccg": {"action": "catalog"}})
379
- ok(c1["ok"] and "compile" in c1["actions"] and "E041" in c1["errors"],
380
- "V20b catalog 自描述(动作清单 + 错误码)")
381
- c2 = mcp._ccg_call(cg, {"ccg": {"action": "compile", "node_id": "tgt",
382
- "dialog": DIALOG, "marks": MARKS, "slots": SLOTS}})
383
- ok(c2["ok"] and c2["compiled"]["success"] and c2["pending"]["ok"],
384
- "V20c compile 成功并落 pending(不当场写库)")
385
- ok("E041" in c2["hint"], "V20d hint 指向编外复核(裁定 A 对调用方可见)")
386
- c3 = mcp._ccg_call(cg, {"ccg": {"action": "attest", "node_id": "tgt",
387
- "verdict": "ACCEPT", "verifier": c2["compiled_by"],
388
- "compiled_by": c2["compiled_by"],
389
- "evidence": "我自己验的"}})
390
- ok((not c3["ok"]) and "E041" in str(c3["attest"]["error"]),
391
- "V20e MCP 面自证 → E041(机械拒绝,不靠自觉)")
392
- c4 = mcp._ccg_call(cg, {"ccg": {"action": "link", "node_id": "tgt", "apply": True}})
393
- ok(not c4["ok"], "V20f 自证章不构成准入 → link 拒绝")
394
- c5 = mcp._ccg_call(cg, {"ccg": {"action": "review", "node_id": "tgt",
395
- "jobs": jobs, "blocking": True, "wait_s": 30}})
396
- ok(c5["state"] == units.HIVE and c5["verdict"] == "ACCEPT" and c5["passed"] is True,
397
- "V20g review 取回裁决:ok/verdict/passed 三者分离")
398
- ok(bool((c5.get("attest") or {}).get("ok")), "V20h 拿到裁决即自动签章")
399
- c7 = mcp._ccg_call(cg, {"ccg": {"action": "review", "node_id": "tgt",
400
- "jobs": jobs, "blocking": False}})
401
- ok(c7["state"] == units.HIVE and c7["verdict"] is None and c7["passed"] is False,
402
- "V20j 非阻塞:派发成功但裁决未回(verdict=None,不冒充通过)")
403
- c6 = mcp._ccg_call(cg, {"ccg": {"action": "link", "node_id": "tgt", "apply": True}})
404
- ok(c6["ok"] and c6["link"]["written"] == 6, "V20i link 落库(三段式闭环)")
405
- c10 = mcp._ccg_call(cg, {"ccg": {"action": "link", "node_id": "tgt", "apply": True}})
406
- ok(not c10["ok"], "V20m 落库后 pending 已清 → 再 link 明确报错(暂存非存档)")
407
- c8 = mcp._ccg_call(cg, {"ccg": {"action": "units", "jobs": jobs, "doctor": True}})
408
- ok(c8["ok"] and c8["action"] == "units", "V20k units/doctor 走三级链体检")
409
- c9 = mcp._ccg_call(cg, {"ccg": {"action": "nope"}})
410
- ok(not c9["ok"], "V20l 未知 action → 明确报错(不静默降级)")
411
- finally:
412
- stop.set()
413
- th.join(timeout=3)
414
- if _old_model is None:
415
- os.environ.pop(units.ENV_MODEL, None)
416
- else:
417
- os.environ[units.ENV_MODEL] = _old_model
418
- if _old_exe is None:
419
- os.environ.pop(units.ENV_EXE, None)
420
- else:
421
- os.environ[units.ENV_EXE] = _old_exe
422
-
423
- finally:
424
- print()
425
- print("ccgc: PASS=%d FAIL=%d" % (PASS, FAIL))
426
- if FAILS:
427
- print("FAILS: " + "; ".join(FAILS))
428
- shutil.rmtree(tmp, ignore_errors=True)
429
- return 1 if FAIL else 0
430
-
431
-
432
- if __name__ == "__main__":
433
- sys.exit(main())
1
+ # -*- coding: utf-8 -*-
2
+ """ccgc 验收:对话记录 → CCG 六要素编译器(V1-V20)。
3
+
4
+ 运行:python -m md_cg.test_ccgc
5
+
6
+ 三条判据在实现层为何是**机械可判定**的(不依赖自觉):
7
+ ① 「LLM 不得自己验证自己」——候选结构里没有签章字段,且 attest 机械比对
8
+ `verifier != compiled_by`(E041);link 再挡一次(双闸)。
9
+ ② 「幻觉」——名实门 E010/E011:每个写入值必须是源文本字面子串,零灰区。
10
+ ③ 「缺参数」——是编译错误(E001-E004)而非 DEFER,`success = (errors == [])`。
11
+
12
+ V16-V20 覆盖**跨调用形态**(三次独立 MCP 调用传不动对象,只能落盘):
13
+ 候选与签章绑定在 `_ccgc_pending/`(hash 防篡改)+ 复核通道三态 + 蜂巢契约
14
+ 端到端(假执行器模拟 serve,无网络无密钥也能确定性验收「通道与签章」)。
15
+ """
16
+ from __future__ import annotations
17
+
18
+ import json
19
+ import os
20
+ import shutil
21
+ import sys
22
+ import tempfile
23
+ import threading
24
+ import time
25
+
26
+ from . import audit, backfill, ccgc, nodefile, units
27
+ from .mdcos import MdCGOS
28
+
29
+ PASS = FAIL = 0
30
+ FAILS = []
31
+
32
+ DIALOG = ("文件摄取分派:按扩展名把文件路由到对应摄取器"
33
+ "。该方法使用扩展名映射表进行路由"
34
+ "。此功能在本地文件系统中生效"
35
+ "。仅对本地可读文件生效"
36
+ "。2026-09-16"
37
+ "。通过回放测试验证"
38
+ "。二进制文件不适用")
39
+
40
+ SLOTS = {
41
+ "observation_position": {"value": "此功能在本地文件系统中生效"},
42
+ "observation_tool": {"value": "该方法使用扩展名映射表进行路由"},
43
+ "time_window": {"value": [0.0, 9999999999.0]},
44
+ "existence_constraint": {"value": "仅对本地可读文件生效"},
45
+ }
46
+
47
+ MARKS = {
48
+ "功能名": {"value": "文件摄取分派:按扩展名把文件路由到对应摄取器"},
49
+ "子功能": {"value": "按扩展名把文件路由到对应摄取器"},
50
+ "执行": {"value": "使用扩展名映射表进行路由"},
51
+ "验证方式": {"value": "回放测试", "basis": "test"},
52
+ "不适用条件": {"value": "二进制文件不适用"},
53
+ }
54
+
55
+
56
+ def ok(cond, label):
57
+ global PASS, FAIL
58
+ if cond:
59
+ PASS += 1
60
+ else:
61
+ FAIL += 1
62
+ FAILS.append(label)
63
+ print(" FAIL " + label)
64
+
65
+
66
+ def _has(errs, code):
67
+ return any(str(e).startswith(code) for e in (errs or []))
68
+
69
+
70
+ def _seed(root):
71
+ cg = MdCGOS(root)
72
+ cg.add("tgt", "# 功能名:待编译节点\n\n占位正文。\n", layer="knowledge")
73
+ cg.flush()
74
+ cg.rebuild_index()
75
+ return cg
76
+
77
+
78
+ def _fake_serve(jobs, stop, seen):
79
+ """假蜂巢执行器:读 spec.json 写 result.json(契约与 hive 的 LLM 委托型一致)。
80
+
81
+ 用线程模拟 serve 侧的单元执行,使**复核通道与签章搬运**在无网络无密钥下
82
+ 可确定性验收——被测的是通道契约,不是模型质量。seen 记录 spec 形态供断言。
83
+ """
84
+ while not stop.is_set():
85
+ try:
86
+ names = sorted(os.listdir(jobs))
87
+ except OSError:
88
+ names = []
89
+ for jid in names:
90
+ d = os.path.join(jobs, jid)
91
+ sp = os.path.join(d, units.SPEC_FILE)
92
+ rp = os.path.join(d, units.RESULT_FILE)
93
+ if not jid.startswith("h") or not os.path.isfile(sp) or os.path.exists(rp):
94
+ continue
95
+ try:
96
+ with open(sp, encoding="utf-8") as f:
97
+ spec = json.load(f)
98
+ except (OSError, ValueError):
99
+ continue
100
+ prompt = str(spec.get("user_prompt") or spec.get("prompt") or "")
101
+ seen.update({"role": spec.get("role"), "model": spec.get("model"),
102
+ "prompt_len": len(prompt),
103
+ "prompt_has_dialog": "文件摄取分派" in prompt})
104
+ payload = {"verdict": seen.get("verdict") or "accept",
105
+ "reason": "假单元复核:候选与对话原文一致",
106
+ "slot_corrections": {}}
107
+ try:
108
+ with open(rp, "w", encoding="utf-8") as f:
109
+ json.dump({"ok": True, "model": spec.get("model"),
110
+ "content": json.dumps(payload, ensure_ascii=False)},
111
+ f, ensure_ascii=False)
112
+ except OSError:
113
+ continue
114
+ time.sleep(0.05)
115
+
116
+
117
+ def _import_mcp():
118
+ """延迟导入工具面(避免测试顶部把 server 依赖一并拉起)。"""
119
+ try:
120
+ from . import mcp_server
121
+ return mcp_server
122
+ except Exception: # noqa: BLE001
123
+ return None
124
+
125
+
126
+ def main():
127
+ global PASS, FAIL
128
+ tmp = tempfile.mkdtemp(prefix="mdcg_ccgc_")
129
+ try:
130
+ root = os.path.join(tmp, "root")
131
+ os.makedirs(root, exist_ok=True)
132
+ cg = _seed(root)
133
+
134
+ # ---------- V1 缺参即编译错误(裁定 B) ----------
135
+ r = ccgc.compile_dialog("", "tgt", "agent:a1")
136
+ ok((not r.success) and _has(r.errors, "E001"), "V1a 缺 dialog → E001")
137
+ r = ccgc.compile_dialog(DIALOG, "", "agent:a1")
138
+ ok((not r.success) and _has(r.errors, "E002"), "V1b 缺 node_id → E002")
139
+ r = ccgc.compile_dialog(DIALOG, "tgt", "")
140
+ ok((not r.success) and _has(r.errors, "E003"), "V1c 缺 actor → E003")
141
+ r = ccgc.compile_dialog(DIALOG, "nope", "agent:a1", cg=cg)
142
+ ok((not r.success) and _has(r.errors, "E002"), "V1d 节点不存在 → E002")
143
+ ok(bool(r.verdict) and r.verdict.get("authority") == "VERIFICATION_UNIT",
144
+ "V1e 终裁 authority=VERIFICATION_UNIT")
145
+
146
+ # ---------- V2 名实门:幻觉在编译期被机械检出 ----------
147
+ bad_slots = dict(SLOTS)
148
+ bad_slots["observation_tool"] = {"value": "该方法使用神经网络进行路由",
149
+ "span": "该方法使用神经网络进行路由"}
150
+ r_bad = ccgc.compile_dialog(DIALOG, "tgt", "agent:a1",
151
+ slots=bad_slots, marks=MARKS, cg=cg)
152
+ ok((not r_bad.success) and _has(r_bad.errors, "E011"), "V2a 捏造值 → E011")
153
+ ok(len(r_bad.ungrounded) >= 1, "V2b 未过门项进入 ungrounded 台账")
154
+
155
+ bad2 = dict(SLOTS)
156
+ bad2["observation_position"] = {"value": "此功能在本地文件系统中生效",
157
+ "span": "不存在的引用文本"}
158
+ r2 = ccgc.compile_dialog(DIALOG, "tgt", "agent:a1",
159
+ slots=bad2, marks=MARKS, cg=cg)
160
+ ok((not r2.success) and _has(r2.errors, "E010"), "V2c 引用定位失败 → E010")
161
+
162
+ class EvilParser(object):
163
+ """冒充 LLM 通道:给出看起来合理但源文本里没有的值。"""
164
+
165
+ def candidates(self, dialog, ctx):
166
+ return {"marks": dict(MARKS), "slots": dict(bad_slots)}
167
+
168
+ r3 = ccgc.compile_dialog(DIALOG, "tgt", "agent:a1",
169
+ parser=EvilParser(), cg=cg)
170
+ ok((not r3.success) and _has(r3.errors, "E011"),
171
+ "V2d 外部 parser 幻觉同样被 E011 拦截(结构级阻断)")
172
+
173
+ # ---------- V3 四槽强制 ----------
174
+ r4 = ccgc.compile_dialog(DIALOG, "tgt", "agent:a1",
175
+ slots={"observation_position": SLOTS["observation_position"]},
176
+ marks=MARKS, cg=cg)
177
+ ok((not r4.success) and _has(r4.errors, "E020"), "V3a 四槽不全 → E020")
178
+
179
+ # ---------- V4/V5 唯一合成入口 + 六要素齐备 ----------
180
+ plain_slots = {k: v.get("value") for k, v in SLOTS.items()}
181
+ r = ccgc.compile_dialog(DIALOG, "tgt", "agent:a1",
182
+ slots=SLOTS, marks=MARKS, cg=cg)
183
+ ok(r.success, "V4a 完整入参编译成功")
184
+ ok(r.lines.get("生效条件") == nodefile.condition_space_text(plain_slots),
185
+ "V4b 生效条件 == nodefile.condition_space_text(唯一入口)")
186
+ ok(set(r.lines) == set(nodefile.CCG_MARKS), "V5a 六要素齐备")
187
+ ok(r.sources.get("verification_basis") == "test", "V5b 验证基底 test")
188
+
189
+ # ---------- V7 自证拒绝(裁定 A 核心) ----------
190
+ a_self = ccgc.attest("tgt", ccgc.ACCEPT, "agent:a1", "agent:a1", cg=cg)
191
+ ok((not a_self.ok) and "E041" in a_self.error, "V7a 验证方==编译方 → E041")
192
+ a_defer = ccgc.attest("tgt", ccgc.DEFER, "designer", "agent:a1", cg=cg)
193
+ ok((not a_defer.ok) and "E042" in a_defer.error, "V7b DEFER 不构成签章")
194
+ a_ok = ccgc.attest("tgt", ccgc.ACCEPT, "designer", "agent:a1",
195
+ evidence="设计者核对原文一致", cg=cg)
196
+ ok(a_ok.ok and bool(a_ok.token), "V7c 编外验证方 ACCEPT → 有效签章")
197
+
198
+ # ---------- V8 无章不写 ----------
199
+ l0 = ccgc.link(r, None, cg=cg, apply=True)
200
+ ok((not l0.ok) and any("E040" in e for e in l0.errors), "V8a 无签章 → E040 拒绝")
201
+ l1 = ccgc.link(r, a_self, cg=cg, apply=True)
202
+ ok(not l1.ok, "V8b 自证签章 → link 拒绝")
203
+ l2 = ccgc.link(r, a_ok, cg=cg, apply=False)
204
+ ok(l2.ok and l2.dry_run and l2.written == 0, "V8c dry-run 不写入")
205
+ _fm_b, c_before = cg._read(cg.index["nodes"]["tgt"])
206
+ ok(not nodefile.ccg_completeness(c_before)["complete"], "V5c link 前六要素不全")
207
+
208
+ # ---------- link 落库 ----------
209
+ l3 = ccgc.link(r, a_ok, cg=cg, apply=True)
210
+ ok(l3.ok and l3.written == 6, "V8d 签章通过 → 写入六行")
211
+ fm_after, c_after = cg._read(cg.index["nodes"]["tgt"])
212
+ ok(nodefile.ccg_completeness(c_after)["complete"],
213
+ "V5d link 后六要素齐备(可判定性提升)")
214
+ ok(fm_after.get("condition_space") == plain_slots, "V4c condition_space 落 frontmatter")
215
+ ok(fm_after.get("verification_basis") == "test", "V5e verification_basis 落盘")
216
+
217
+ # ---------- V6 未制造条件污染 ----------
218
+ rep = backfill.verify_conditions(cg)
219
+ ok(rep.get("legacy_position") == 0, "V6a 弱等价残留 legacy_position == 0")
220
+ ok(rep.get("from_synthesis", 0) >= 1, "V6b 生效条件来源=合成")
221
+
222
+ # ---------- V9 缺验证器恒 DEFER(能力外置) ----------
223
+ v = audit.audit("ccg_marks", {"node": "tgt"}, {})
224
+ ok(v.get("state") == "DEFER", "V9a 未注入验证器 → DEFER(不假装通过)")
225
+ ok(audit.kinds()["ccg_marks"]["basis"] == "test", "V9b ccg_marks 基底建议=test")
226
+
227
+ # ---------- V11 用后续验证修正生效条件 ----------
228
+ rc = ccgc.recalibrate("tgt", {"existence_constraint": "仅对本地可读文件生效"},
229
+ "agent:a1", "agent:a1", cg=cg, apply=False)
230
+ ok(any("E041" in e for e in rc.errors), "V11a 修正方==编译方 → E041")
231
+ rc = ccgc.recalibrate("tgt", {"生效条件": "手写条件"}, "designer", "agent:a1",
232
+ cg=cg, apply=False)
233
+ ok(any("E043" in e for e in rc.errors), "V11b 非四槽键 → E043(无第二通路)")
234
+ rc = ccgc.recalibrate("tgt", {"observation_tool": "该方法使用扩展名映射表进行路由"},
235
+ "designer", "agent:a1", evidence="实测复核:方法槽无误",
236
+ cg=cg, apply=True)
237
+ ok(rc.ok, "V11c 编外验证方修正获准")
238
+ _fm_r, c_r = cg._read(cg.index["nodes"]["tgt"])
239
+ ok(nodefile.ccg_completeness(c_r)["complete"], "V11d 修正后仍齐备")
240
+ logs = ccgc._read_jsonl(ccgc._log_path(cg))
241
+ ok(any(x.get("action") == "ccgc_recalibrate" and x.get("slots_before") is not None
242
+ and x.get("slots_after") is not None for x in logs),
243
+ "V11e 修正留痕含 before/after(可溯源)")
244
+ ok(any(x.get("action") == "ccgc_attest" for x in logs), "V11f 签章留痕可查")
245
+
246
+ # ---------- V13 内生规则解析器:诚实下界 ----------
247
+ r_rule = ccgc.compile_dialog(DIALOG, "tgt", "agent:a1", cg=cg)
248
+ ok(any("下界能力" in w for w in r_rule.warnings), "V13a 未注入解析器时如实声明下界")
249
+ bad_spans = [s for arr in r_rule.spans.values() for s in arr
250
+ if s and s not in DIALOG]
251
+ ok(not bad_spans, "V13b 内生解析器引用全部 grounded")
252
+
253
+ # ---------- V14 产物无占位残留 ----------
254
+ ok(not any(nodefile.is_placeholder_text(x) for x in r.lines.values()),
255
+ "V14 产物无占位残留")
256
+
257
+ # ---------- V15 裁定 B 术语落地:单一真源 + 六要素一一对应 ----------
258
+ ok(ccgc.CONTRACT_ROLES is nodefile.CCG_CONTRACT_ROLES,
259
+ "V15a 术语真源唯一(ccgc 引用 nodefile,不另定义一份)")
260
+ ok(tuple(nodefile.CCG_CONTRACT_ROLES) == tuple(nodefile.CCG_MARKS),
261
+ "V15b 契约角色与六要素一一对应(顺序一致)")
262
+ ok(nodefile.CCG_CONTRACT_ROLES["生效条件"] == "前置条件 precondition",
263
+ "V15c 生效条件角色 = precondition(裁定 B)")
264
+
265
+ # ---------- V16 pending:候选与签章绑定(跨 MCP 三次独立调用形态) ----------
266
+ p_path = ccgc.pending_path(cg, "tgt")
267
+ ok(bool(p_path) and ccgc.PENDING_DIR in p_path, "V16a pending 落 LAYERS 之外的冷区")
268
+ sv = ccgc.save_pending(cg, r)
269
+ ok(bool(sv.get("ok")) and os.path.isfile(sv["path"]) and bool(sv.get("hash")),
270
+ "V16b 候选落盘并留内容摘要")
271
+ got = ccgc.load_pending(cg, "tgt")
272
+ ok(bool(got.get("ok")) and bool(got.get("hash_ok")), "V16c 读回摘要一致(原件未被改写)")
273
+ ok(got["compiled"].lines == r.lines, "V16d 读回六行 == 编译产物(无损搬运)")
274
+ with open(sv["path"], encoding="utf-8") as f:
275
+ rec = json.load(f)
276
+ rec["compiled"]["lines"]["功能名"] = "被篡改的功能名"
277
+ with open(sv["path"], "w", encoding="utf-8") as f:
278
+ json.dump(rec, f, ensure_ascii=False)
279
+ lx = ccgc.link_pending(cg, "tgt", apply=True)
280
+ ok((not lx.ok) and any("hash" in e for e in lx.errors),
281
+ "V16e 候选被改写 → hash 不符,拒绝写入(签章只忠于原件)")
282
+ sv = ccgc.save_pending(cg, r, a_ok)
283
+ lz = ccgc.link_pending(cg, "tgt", apply=True, actor="agent:a1")
284
+ ok(lz.ok and lz.written == 6, "V16f 读回原件+签章 → 落库成功")
285
+ ok(not os.path.isfile(sv["path"]), "V16g 落库成功即清 pending(暂存非存档)")
286
+ ok(not any(ccgc.PENDING_DIR in str(k) for k in (cg.index.get("nodes") or {})),
287
+ "V16h pending 不进索引(冷区对检索隐身)")
288
+
289
+ # ---------- V17 闸门:只认编外裁决,绝不假装通过 ----------
290
+ v = audit.audit("ccg_marks", {"node_id": "tgt", "unit_verdict": "ACCEPT",
291
+ "verifier": "hive:reflect:h1",
292
+ "evidence": "假单元复核:与原文一致"}, {})
293
+ ok(v.get("state") == "ACCEPT", "V17a 编外裁决+依据 → ACCEPT")
294
+ v = audit.audit("ccg_marks", {"node_id": "tgt", "unit_verdict": "ACCEPT",
295
+ "verifier": "hive:reflect:h1"}, {})
296
+ ok(v.get("state") == "DEFER", "V17b ACCEPT 但无依据 → DEFER(无依据不通过)")
297
+ v = audit.audit("ccg_marks", {"node_id": "tgt", "unit_verdict": "ACCEPT",
298
+ "verifier": "agent:a1", "evidence": "我自己验的"},
299
+ {"compiled_by": "agent:a1"})
300
+ ok(v.get("state") == "REJECT", "V17c 自证 → REJECT(E041 在闸门层再挡一次)")
301
+ v = audit.audit("ccg_marks", {"node_id": "tgt", "unit_verdict": "ACCEPT",
302
+ "evidence": "无验证方"}, {})
303
+ ok(v.get("state") == "DEFER", "V17d 有裁决缺验证方标识 → DEFER")
304
+ v = audit.audit("ccg_marks", {"node_id": "tgt"}, {})
305
+ d = v.get("detail") or {}
306
+ ok(v.get("state") == "DEFER" and bool(d.get("next")) and d.get("channel_state") in units.STATES,
307
+ "V17e 无裁决 → DEFER 且给出下一步通道(不阻塞写路径)")
308
+ v = audit.audit("ccg_marks", {}, {})
309
+ ok(v.get("state") == "DEFER", "V17f 缺 node_id → DEFER")
310
+
311
+ # ---------- V18 复核通道:三态如实 + 来源标识结构上非编译者 ----------
312
+ ok(units.transport_name(units.HIVE, units.REFLECT, "h1") == "hive:reflect:h1",
313
+ "V18a 蜂巢来源标识 = hive:<role>:<job>")
314
+ ok(units.transport_name(units.HIVE, units.REFLECT, "h1") != "agent:a1",
315
+ "V18b 来源标识结构上不可能等于编译者(裁定 A 不被误伤)")
316
+ u = units.verdict_of('前置说明\n```json\n{"verdict":"accept","reason":"一致"}\n```')
317
+ ok(u["verdict"] == units.ACCEPT and bool(u["parsed"]), "V18c 围栏 JSON 可解析 → ACCEPT")
318
+ u = units.verdict_of("我无法判断这件事")
319
+ ok(u["verdict"] == units.DEFER and not u["parsed"], "V18d 解析不出 → DEFER(不猜测)")
320
+ u = units.verdict_of({"verdict": "drop", "reason": "与原文不符",
321
+ "slot_corrections": {"observation_tool": "x"}})
322
+ ok(u["verdict"] == units.REJECT and bool(u["slot_corrections"]),
323
+ "V18e drop → REJECT(四槽修正随裁决带回)")
324
+ aa = units.to_attest_args({"verdict": units.ACCEPT, "reason": "一致"}, state=units.HIVE,
325
+ role=units.REFLECT, job_id="h1",
326
+ compiled_by=units.transport_name(units.HIVE, units.REFLECT, "h1"))
327
+ ok(aa.get("self_verify") is True, "V18f 万一自证 → 显式标记(供上层拒绝)")
328
+ aa = units.to_attest_args({"verdict": units.ACCEPT, "reason": "一致"}, state=units.HIVE,
329
+ role=units.REFLECT, job_id="h1", compiled_by="agent:a1")
330
+ ok(not aa.get("self_verify") and aa["verifier"].startswith("hive:reflect:"),
331
+ "V18g 非自证:verifier 取蜂巢来源标识(不设自证标记)")
332
+ pr = units.probe(jobs=os.path.join(tmp, "nojobs"))
333
+ ok(pr["state"] == units.CONFIGURE and units.ENV_MODEL in pr["hint"],
334
+ "V18h 蜂巢不可用 → 返回配置指引(不自动拉起、不假装可用)")
335
+ pr = units.probe(jobs=os.path.join(tmp, "nojobs"), allow_degrade=True)
336
+ ok(pr["state"] == units.SUBAGENT, "V18i 显式 allow_degrade → 子代理降级(不冒充 hive)")
337
+
338
+ # ---------- V19/V20 端到端:假蜂巢 → 编外裁决 → 签章 → 落库 ----------
339
+ jobs = os.path.join(tmp, "jobs")
340
+ os.makedirs(jobs, exist_ok=True)
341
+ # 假 serve 是**本进程内的线程**,故「该 pid 是本程序」如实为真——把本程序
342
+ # 口径指向本进程映像名即可(v14 缺陷 E 修复后 units 判活含**身份层**:
343
+ # 旧写法心跳 pid=本进程却让 EXE 口径指向 hive.exe,身份层判假 → 通道不可用,
344
+ # 那不是被测缺陷而是测试自身要与新口径对齐)。
345
+ _old_exe = os.environ.get(units.ENV_EXE)
346
+ os.environ[units.ENV_EXE] = sys.executable
347
+ with open(os.path.join(jobs, units.SERVE_FILE), "w", encoding="utf-8") as f:
348
+ json.dump({"ts": int(time.time() * 1000), "pid": os.getpid()}, f)
349
+ seen = {}
350
+ stop = threading.Event()
351
+ th = threading.Thread(target=_fake_serve, args=(jobs, stop, seen), daemon=True)
352
+ th.start()
353
+ _old_model = os.environ.get(units.ENV_MODEL)
354
+ os.environ[units.ENV_MODEL] = "fake-unit-model"
355
+ try:
356
+ pr = units.probe(jobs=jobs)
357
+ ok(pr["state"] == units.HIVE, "V19a 心跳新鲜+模型已配 → HIVE 可派发")
358
+ rv = units.review(digest=r, dialog=DIALOG, role=units.REFLECT, node_id="tgt",
359
+ jobs=jobs, blocking=True, wait_s=30, cg=cg, actor="agent:a1")
360
+ ok(rv["state"] == units.HIVE and bool(rv.get("unit")), "V19b 派发并取回编外裁决")
361
+ ok((rv["unit"] or {}).get("verdict") == units.ACCEPT, "V19c 单元裁决解析为 ACCEPT")
362
+ ok(seen.get("role") == units.REFLECT and seen.get("model") == "fake-unit-model"
363
+ and seen.get("prompt_has_dialog"),
364
+ "V19d spec 形态合蜂巢契约(role/model/复核包正文)")
365
+ ok(str((rv.get("attest") or {}).get("verifier") or "").startswith("hive:reflect:"),
366
+ "V19e 签章方 = 蜂巢单元标识(结构上非编译者)")
367
+ at = ccgc.attest("tgt", rv["attest"]["verdict"], rv["attest"]["verifier"],
368
+ "agent:a1", evidence=rv["attest"]["evidence"] or "单元复核",
369
+ cg=cg)
370
+ ok(at.ok, "V19f 蜂巢裁决可直接签章(E041 不被误伤)")
371
+ logs = ccgc._read_jsonl(os.path.join(str(cg.root), units.LOG_NAME))
372
+ ok(any(x.get("action") == "review" and x.get("job_id") for x in logs),
373
+ "V19g 派发留痕(job_id 可追溯)")
374
+
375
+ # --- V20 MCP 工具面:compile → review → attest/link 三段式 ---
376
+ mcp = _import_mcp()
377
+ ok(mcp is not None, "V20a 工具面可加载")
378
+ c1 = mcp._ccg_call(cg, {"ccg": {"action": "catalog"}})
379
+ ok(c1["ok"] and "compile" in c1["actions"] and "E041" in c1["errors"],
380
+ "V20b catalog 自描述(动作清单 + 错误码)")
381
+ c2 = mcp._ccg_call(cg, {"ccg": {"action": "compile", "node_id": "tgt",
382
+ "dialog": DIALOG, "marks": MARKS, "slots": SLOTS}})
383
+ ok(c2["ok"] and c2["compiled"]["success"] and c2["pending"]["ok"],
384
+ "V20c compile 成功并落 pending(不当场写库)")
385
+ ok("E041" in c2["hint"], "V20d hint 指向编外复核(裁定 A 对调用方可见)")
386
+ c3 = mcp._ccg_call(cg, {"ccg": {"action": "attest", "node_id": "tgt",
387
+ "verdict": "ACCEPT", "verifier": c2["compiled_by"],
388
+ "compiled_by": c2["compiled_by"],
389
+ "evidence": "我自己验的"}})
390
+ ok((not c3["ok"]) and "E041" in str(c3["attest"]["error"]),
391
+ "V20e MCP 面自证 → E041(机械拒绝,不靠自觉)")
392
+ c4 = mcp._ccg_call(cg, {"ccg": {"action": "link", "node_id": "tgt", "apply": True}})
393
+ ok(not c4["ok"], "V20f 自证章不构成准入 → link 拒绝")
394
+ c5 = mcp._ccg_call(cg, {"ccg": {"action": "review", "node_id": "tgt",
395
+ "jobs": jobs, "blocking": True, "wait_s": 30}})
396
+ ok(c5["state"] == units.HIVE and c5["verdict"] == "ACCEPT" and c5["passed"] is True,
397
+ "V20g review 取回裁决:ok/verdict/passed 三者分离")
398
+ ok(bool((c5.get("attest") or {}).get("ok")), "V20h 拿到裁决即自动签章")
399
+ c7 = mcp._ccg_call(cg, {"ccg": {"action": "review", "node_id": "tgt",
400
+ "jobs": jobs, "blocking": False}})
401
+ ok(c7["state"] == units.HIVE and c7["verdict"] is None and c7["passed"] is False,
402
+ "V20j 非阻塞:派发成功但裁决未回(verdict=None,不冒充通过)")
403
+ c6 = mcp._ccg_call(cg, {"ccg": {"action": "link", "node_id": "tgt", "apply": True}})
404
+ ok(c6["ok"] and c6["link"]["written"] == 6, "V20i link 落库(三段式闭环)")
405
+ c10 = mcp._ccg_call(cg, {"ccg": {"action": "link", "node_id": "tgt", "apply": True}})
406
+ ok(not c10["ok"], "V20m 落库后 pending 已清 → 再 link 明确报错(暂存非存档)")
407
+ c8 = mcp._ccg_call(cg, {"ccg": {"action": "units", "jobs": jobs, "doctor": True}})
408
+ ok(c8["ok"] and c8["action"] == "units", "V20k units/doctor 走三级链体检")
409
+ c9 = mcp._ccg_call(cg, {"ccg": {"action": "nope"}})
410
+ ok(not c9["ok"], "V20l 未知 action → 明确报错(不静默降级)")
411
+ finally:
412
+ stop.set()
413
+ th.join(timeout=3)
414
+ if _old_model is None:
415
+ os.environ.pop(units.ENV_MODEL, None)
416
+ else:
417
+ os.environ[units.ENV_MODEL] = _old_model
418
+ if _old_exe is None:
419
+ os.environ.pop(units.ENV_EXE, None)
420
+ else:
421
+ os.environ[units.ENV_EXE] = _old_exe
422
+
423
+ finally:
424
+ print()
425
+ print("ccgc: PASS=%d FAIL=%d" % (PASS, FAIL))
426
+ if FAILS:
427
+ print("FAILS: " + "; ".join(FAILS))
428
+ shutil.rmtree(tmp, ignore_errors=True)
429
+ return 1 if FAIL else 0
430
+
431
+
432
+ if __name__ == "__main__":
433
+ sys.exit(main())