@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,718 +1,718 @@
1
- # -*- coding: utf-8 -*-
2
- """md_cg · 节点间自动冲突检测(三级决策:情绪 → 反思 → 递归反思)
3
-
4
- 理论出处(本仓原文,非外部知识):
5
-
6
- · **情绪 = 信息差的二阶变化 d²D/dt²**(`docs/theory/智能的公理化基石.md` §十一,:412-510)
7
- 工程端对应 `emotional_bias`(approaching / avoiding / stable),并且原文明确:
8
- 「情绪通道**独立、不参与信任计算**」。故本模块 L0 只做**流程调度**,
9
- 绝不改动 confidence / 资格判定——避免把情绪混进事实判断。
10
-
11
- · **反题 = 预测与事实冲突**(同文档 :529,条件论七操作之一)
12
- —— L1 一次冲突检测的理论名:新信息与既有条件的「反题」关系。
13
-
14
- · **递归必须受约束**(同文档 :273):
15
- 「递归必须受到深度、查询次数、节点数、循环检测和信息增益门槛约束。
16
- 若递归没有减少候选空间,就不应继续搜索。」
17
- —— L2 递归反思的硬约束(本模块按此实现,而非无限展开)。
18
-
19
- · **四态路由** ACCEPT / REJECT / DEFER / BLINDSPOT(同文档 :721;
20
- `md_cg/mdcg.py` 四态定义)—— L1 的输出语义。
21
-
22
- · **知识飞轮:误差 → 补条件 → 结构更新**(同文档 :725;`mdcg.py:1001`
23
- `flywheel_step`)—— 冲突**自动**落 unresolved,误差是结构更新的输入。
24
-
25
- · **纪律四要素同构**(`docs/工作纪律_认知图条目_v1.1.json`;
26
- `consolidate.py` CCG 四要素)—— 「不能违反纪律」= 新内容不得命中纪律节点的
27
- `negative.reject`(不适用条件)。纪律节点用 tag/前缀识别,不硬编码具体条目。
28
-
29
- 三级决策(顺序即语义,越靠前越廉价):
30
-
31
- L0 情绪 :二阶信号,快速方向调整(approaching / stable / avoiding)——不裁决资格
32
- L1 反思 :一次条件级冲突检测(自否定 / 纪律违反 / 条件互斥)→ 四态
33
- L2 递归反思:L1 未决 → 沿关系链递归找「区分条件」;受深度/节点数/循环/增益门槛约束
34
-
35
- 冲突自动触发飞轮:verdict ∈ {REJECT, DEFER, BLINDSPOT} 且 auto_flywheel →
36
- `cg.flywheel_step({query, expected_state:"ACCEPT", actual_state:verdict, missing})`
37
-
38
- 留痕 `_consistency.jsonl`(append-only):每条判定可审计「为什么冲突 / 为什么放行」。
39
-
40
- 诚实边界:本模块是**条件级(结构化)**冲突检测,不是语义蕴含证明。它判断的是
41
- 「声明的适用/不适用条件是否互相覆盖」,而非「两句话在逻辑上是否矛盾」。
42
- 无法建立可比对路径时返回 BLINDSPOT,不假装确定。
43
- """
44
- from __future__ import annotations
45
-
46
- import json
47
- import os
48
- import time
49
-
50
- from .mdcg import expand_query_terms_weighted
51
-
52
- # --------------------------------------------------------------------------
53
- # 常量(全部可审计、可调)
54
- # --------------------------------------------------------------------------
55
-
56
- LOG_FILE = "_consistency.jsonl"
57
-
58
- MAX_SCAN = 200 # 单次检测最多比对的既有节点数(防 O(N) 爆炸)
59
- MAX_DEPTH = 3 # L2 递归深度上限(对齐 :273)
60
- MAX_NODES = 60 # L2 递归展开节点上限(对齐 :273)
61
- MIN_GAIN = 0.15 # 信息增益门槛:候选空间减少比例低于此值即停(对齐 :273)
62
-
63
- CLASH_HIGH = 0.6 # 条件互相覆盖阈值 → 明确互斥
64
- CLASH_LOW = 0.35 # 条件部分覆盖阈值 → 待定
65
- SELF_NEGATION = 0.5 # 自否定阈值:负条件被自身正文强命中
66
-
67
- # —— 第二类关系(同条件空间 · 结论槽取值分歧)阈值;均由探针实测标定 ——
68
- # run_probe_samecond.py 实测:同条件 same_cond=1.0 / 异条件空间 0.328 → 0.75 可分
69
- SAME_COND_HIGH = 0.75 # 同侧条件重合 → 判定「同一条件空间」
70
- # 实测结论槽(子功能):同槽 1.0 / 同主语异属性 0.14 / 异主题 0.0 → 0.6 可分
71
- SLOT_HIGH = 0.6 # 结论槽(功能名/子功能)重合 → 判定「同一件事」
72
- # 实测:逐字重复 1.0 / 同槽不同值 0.61 / 同值异措辞 0.74 → 0.95 只排除逐字重复
73
- CONCLUSION_SAME = 0.95 # 正文几乎逐字相同 → 属「重复」(该合并),不算冲突
74
-
75
- EMO_AVOID = 0.70 # 冲突强度 ≥ 此值 → avoiding
76
- EMO_APPROACH = 0.30 # 冲突强度 ≤ 此值 → approaching
77
-
78
- # 纪律节点识别(tag 或 id 前缀;不硬编码具体纪律条目)
79
- DISCIPLINE_TAGS = ("discipline", "纪律", "work_discipline", "rule", "规则", "戒律")
80
-
81
- VERDICTS = ("ACCEPT", "REJECT", "DEFER", "BLINDSPOT")
82
-
83
-
84
- # 生效条件:以 verdict 与 reason 构造异常(消息 `[{verdict}] {reason}`),conflicts 传假值(None/空容器等,源码 `conflicts or []`)时 self.conflicts 为 [],传真值时原样保留;
85
- class ConsistencyError(Exception):
86
- """硬冲突:写入被拒(自否定 / 违反纪律)。"""
87
-
88
- # 生效条件:verdict 与 reason 必传并赋给同名属性、拼成异常消息 `[{verdict}] {reason}`;conflicts 为假值(None/空容器等,源码 `conflicts or []`)时 self.conflicts 回落到 [],为真值时原样保留;
89
- def __init__(self, verdict, reason, conflicts=None):
90
- self.verdict = verdict
91
- self.reason = reason
92
- self.conflicts = conflicts or []
93
- super().__init__(f"[{verdict}] {reason}")
94
-
95
-
96
- # --------------------------------------------------------------------------
97
- # 原语:延迟导入 mdcos(避免 mdcg ← mdcos ← consistency 的循环导入)
98
- # --------------------------------------------------------------------------
99
-
100
- # 生效条件:无 required 形参,任一调用返回 ( _ccg_field, _declared_conditions, _neg_hit, _weighted_coverage ) 四元组;
101
- def _prims():
102
- """取 md_cg 已有的条件匹配原语(条件论「反题」的既有实现)。"""
103
- from .mdcos import (_ccg_field, _declared_conditions, _neg_hit,
104
- _weighted_coverage)
105
- return _ccg_field, _declared_conditions, _neg_hit, _weighted_coverage
106
-
107
-
108
- # 生效条件:xs 为可迭代对象时,逐项 str(x).strip() 后仅当结果非空且未出现过才加入 out 并返回 out;xs 为 None/False/0 时在 for 处迭代失败(TypeError);
109
- def _dedup(xs):
110
- out = []
111
- for x in xs:
112
- s = str(x).strip()
113
- if s and s not in out:
114
- out.append(s)
115
- return out
116
-
117
-
118
- # 生效条件:fm 给出时,遍历 fm.get("edges")(缺键或假值按空列表)中元素,dict 元素按 to→target→node→id 取首个真值、非 dict 元素直接作候选,候选真值时 str(t) 加入 out 并返回;
119
- def _edge_targets(fm):
120
- """节点声明的出边目标(兼容 dict / str 两种形态)。"""
121
- out = []
122
- for e in (fm.get("edges") or []):
123
- if isinstance(e, dict):
124
- t = e.get("to") or e.get("target") or e.get("node") or e.get("id")
125
- else:
126
- t = e
127
- if t:
128
- out.append(str(t))
129
- return out
130
-
131
-
132
- # 生效条件:fm 与 node_id 给出时,若 fm.get("tags")(缺键/假值按空)小写后与 DISCIPLINE_TAGS 有交集,或 str(node_id) 以 "discipline_" 或 "work_discipline" 开头,返回 True;否则返回 False;
133
- def _is_discipline(fm, node_id):
134
- tags = {str(t).lower() for t in (fm.get("tags") or [])}
135
- if tags & set(DISCIPLINE_TAGS):
136
- return True
137
- return str(node_id).startswith(("discipline_", "work_discipline"))
138
-
139
-
140
- # --------------------------------------------------------------------------
141
- # 模式分离的支持件(maintain.separate 复用;也供 insight.reconstruct 取线索)
142
- # --------------------------------------------------------------------------
143
-
144
- #: 分离边的关系名:两个节点「看起来像,但条件不同,互为不同情境」
145
- SEPARATION_REL = "distinct_from"
146
-
147
-
148
- # 生效条件:fm 给出时,仅处理 fm.get("edges")(缺键/假值按空)中的 dict 元素,relation_type 或 relation(缺省空串)小写等于 SEPARATION_REL 时,按 target→to→id 取首个真值且未重复则加入 out;
149
- def separation_targets(fm):
150
- """节点已声明的分离对象(`distinct_from` 出边),用于幂等与去重。"""
151
- out = []
152
- for e in (fm.get("edges") or []):
153
- if not isinstance(e, dict):
154
- continue
155
- rel = str(e.get("relation_type") or e.get("relation") or "").strip().lower()
156
- if rel != SEPARATION_REL:
157
- continue
158
- t = e.get("target") or e.get("to") or e.get("id")
159
- if t and str(t) not in out:
160
- out.append(str(t))
161
- return out
162
-
163
-
164
- # 生效条件:fm 与 content 给出时,以 content(假值按空串)、fm.get("condition_space")、fm.get("non_applicable_conditions") 解析,返回去重后的 (set(pos), set(neg));
165
- def condition_terms(fm, content):
166
- """节点声明的(正条件, 负条件)词面集合——分离判定与重构取线索共用。"""
167
- pos, neg = _new_terms(content or "", fm.get("condition_space"),
168
- fm.get("non_applicable_conditions"))
169
- return set(pos), set(neg)
170
-
171
-
172
- # 生效条件:pos_a、neg_a、pos_b、neg_b 给出的条件词面小写化后,两侧并集均空时返回 overlap 0.0、distinct False;否则计算交集/并集比并返回 distinct 为 overlap <= CLASH_LOW;
173
- def condition_distinct(pos_a, neg_a, pos_b, neg_b):
174
- """两组条件是否「实质不同」:任一侧条件词面几乎不重合即为不同情境。
175
-
176
- 返回 {'overlap': 覆盖率, 'distinct': bool}。overlap 高 = 条件相同(是重复,
177
- 该合并);overlap 低 = 条件不同(该分离,避免混为一体)。
178
- """
179
- a = {str(x).lower() for x in (set(pos_a) | set(neg_a))}
180
- b = {str(x).lower() for x in (set(pos_b) | set(neg_b))}
181
- if not a and not b:
182
- return {"overlap": 0.0, "distinct": False,
183
- "note": "双方均未声明条件:无从判定分离(不假装确定)"}
184
- union = a | b
185
- overlap = (len(a & b) / float(len(union))) if union else 0.0
186
- return {"overlap": round(overlap, 4), "distinct": overlap <= CLASH_LOW}
187
-
188
-
189
- # 生效条件:content、condition_space、non_applicable_conditions 给出时,content 的 `生效条件` 字段与 condition_space 中键不以 `__` 开头且不为 `time_window` 的值并入 pos(list/tuple/set 展平,其他非 None/"" 值 str 化),non_applicable_conditions 各项及 content 的 `不适用条件` 字段值并入 neg,最后 _dedup 返回;
190
- def _new_terms(content, condition_space, non_applicable_conditions):
191
- """新节点声明的(正条件, 负条件)——与既有节点同口径解析。"""
192
- _ccg_field, _declared, _neg_hit, _cov = _prims()
193
- pos, neg = [], []
194
- v = _ccg_field(content or "", "生效条件")
195
- if v:
196
- pos.append(v)
197
- for k, val in (condition_space or {}).items():
198
- if str(k).startswith("__") or k == "time_window":
199
- continue
200
- if isinstance(val, (list, tuple, set)):
201
- pos.extend(str(x) for x in val)
202
- elif val not in (None, ""):
203
- pos.append(str(val))
204
- neg.extend(str(x) for x in (non_applicable_conditions or []))
205
- v2 = _ccg_field(content or "", "不适用条件")
206
- if v2:
207
- neg.append(v2)
208
- return _dedup(pos), _dedup(neg)
209
-
210
-
211
- # 生效条件:content 与 neg_texts 给出时,neg_texts 中任一短语去掉「不得/禁止/严禁/不能/不可/不要/勿」前缀且长度 >=2 后作为子串出现在 content(假值按空串)中则返回 True,否则 False;
212
- def _ban_hit(content, neg_texts):
213
- """纪律禁令命中:去掉「不得/禁止/…」前缀后,短语是否**整体出现**在正文中。
214
-
215
- 比词袋匹配更严格——纪律条目通常是精确的禁令短语,用子串命中可避免
216
- 「生产」这类子词把无关内容误判为违纪(假阳性会毁掉纪律的可信度)。
217
- """
218
- for x in (neg_texts or []):
219
- s = str(x).strip()
220
- for p in ("不得", "禁止", "严禁", "不能", "不可", "不要", "勿"):
221
- if s.startswith(p):
222
- s = s[len(p):].strip()
223
- break
224
- if len(s) >= 2 and s in (content or ""):
225
- return True
226
- return False
227
-
228
-
229
- # 生效条件:content 为真时按行过滤,跳过 strip 后以 "#" 开头且含全角或半角冒号的行,其余原行以换行连接返回;content 假值按空串返回 "";
230
- def _body_text(content):
231
- """去掉 CCG 声明行(`# 字段:值`)后的正文。
232
-
233
- 自否定看的是「正文/生效条件是否与不适用条件矛盾」,不能把节点自己声明的
234
- `# 不适用条件:X` 当成 X 出现在正文里——否则**每个**声明了不适用条件的
235
- 正常节点都会被误判为自相矛盾(真实 CCG 条目普遍带该字段)。
236
- """
237
- out = []
238
- for line in (content or "").splitlines():
239
- s = line.strip()
240
- if s.startswith("#") and (":" in s or ":" in s):
241
- continue
242
- out.append(line)
243
- return "\n".join(out)
244
-
245
-
246
- # 生效条件:content 给出时(假值按空串)解析 CCG 的 `# 功能名` 与 `# 子功能` 字段并返回两者;
247
- def _slot_text(content):
248
- """结论槽:CCG 声明的 `# 功能名` / `# 子功能`(结构字段,非正文词面)。
249
-
250
- 为什么需要它:L1-c 要判「两条记忆是不是在讲同一件事」,但**词面覆盖率测不了**
251
- ——探针实测「同属性不同值」0.612 vs「异属性」0.623(负样本反超),
252
- 因为两者与旧正文的通用词重合度相当。CCG 的槽位字段才是「在讲哪件事」的
253
- 结构化代理,与 L1-b 用 condition_space 判「在什么条件下」同构。
254
-
255
- 字段缺失 → 返回空串 → L1-c 不触发(保守:无从比对时不假装确定)。
256
- """
257
- _ccg_field, _declared, _neg_hit, _cov = _prims()
258
- return (_ccg_field(content or "", "功能名"),
259
- _ccg_field(content or "", "子功能"))
260
-
261
-
262
- # --------------------------------------------------------------------------
263
- # L0 情绪通道(信息差二阶变化)
264
- # --------------------------------------------------------------------------
265
-
266
- # 生效条件:conflict_strength 被夹取到 [0,1](假值按 0.0),prev_strength 为 None 时 d2=0.0,否则 d2=c-夹取后的 prev_strength;按 c>=EMO_AVOID 或 d2>0.2 返回 avoiding,或 c<=EMO_APPROACH 且 d2<=0 返回 approaching,否则 stable;
267
- def emotional_bias(conflict_strength, prev_strength=None):
268
- """L0:把冲突强度映射为情绪倾向(approaching / stable / avoiding)。
269
-
270
- 对齐 `智能的公理化基石.md` §十一:情绪是**信息差的二阶变化** d²D/dt²。
271
- 这里的工程代理:
272
- · 一阶 d1 = conflict_strength(新信息与既有结构的相斥程度)
273
- · 二阶 d2 = 本次 d1 − 上次 d1(用留痕里的上一条强度作基线)
274
- · d2 > 0 → 信息差在**扩大**(越来越不顺)→ avoiding
275
- · d2 < 0 → 信息差在**收敛**(越来越顺) → approaching
276
-
277
- 重要(原文强制):情绪通道**独立、不参与信任/资格计算**,
278
- 只影响「是否升级到递归反思」的调度决策。
279
- """
280
- c = max(0.0, min(1.0, float(conflict_strength or 0.0)))
281
- if prev_strength is None:
282
- d2 = 0.0
283
- else:
284
- d2 = c - max(0.0, min(1.0, float(prev_strength)))
285
- if c >= EMO_AVOID or d2 > 0.2:
286
- bias = "avoiding"
287
- elif c <= EMO_APPROACH and d2 <= 0:
288
- bias = "approaching"
289
- else:
290
- bias = "stable"
291
- return {"bias": bias, "conflict_strength": round(c, 4),
292
- "d2": round(d2, 4),
293
- "note": "情绪通道独立,不参与信任/资格计算(智能论 §十一)"}
294
-
295
-
296
- # 生效条件:cg 给出时,若 cg.root 下 LOG_FILE 可读,则逐行解析 JSON 并取 .get("conflict_strength"),返回最后一条可解析记录的该键值(缺键或值为 None 则为 None);路径不可用或 OSError 返回 None;
297
- def _last_strength(cg):
298
- """上一条留痕的冲突强度(二阶差分的基线)。流式读,不载全量。"""
299
- p = os.path.join(cg.root, LOG_FILE)
300
- if not os.path.exists(p):
301
- return None
302
- last = None
303
- try:
304
- with open(p, "r", encoding="utf-8") as f:
305
- for line in f:
306
- line = line.strip()
307
- if not line:
308
- continue
309
- try:
310
- last = json.loads(line).get("conflict_strength")
311
- except (ValueError, TypeError):
312
- pass
313
- except OSError:
314
- return None
315
- return last
316
-
317
-
318
- # --------------------------------------------------------------------------
319
- # L2 递归反思(受深度 / 节点数 / 循环 / 增益门槛约束)
320
- # --------------------------------------------------------------------------
321
-
322
- # 生效条件:以 cg 节点图、seeds 中非空项为初始 frontier、tw_pos/tw_neg 词权,在 d=1..int(max_depth) 每轮先判 frontier 空返回 frontier_exhausted,再逐 nid 处理时若 nodes_visited > max_nodes 先返回 node_budget(可先于同层 discriminators),否则处理完该层后有 discriminators(非 seed_set 节点声明条件与 tw_pos/tw_neg 覆盖 >= CLASH_HIGH)返回 resolved,否则 last_gain < min_gain 返回 gain_below_threshold,循环耗尽返回 depth_exceeded;seeds 假值时 frontier 空,在 d=1 进入循环后由首判返回 frontier_exhausted(depth=0);
323
- def _recursive_reflect(cg, seeds, tw_pos, tw_neg, max_depth=MAX_DEPTH,
324
- max_nodes=MAX_NODES, min_gain=MIN_GAIN):
325
- """递归反思:沿关系链找「区分条件」,每层检查信息增益。
326
-
327
- 收敛条件(任一):
328
- · 找到区分节点(其负条件排除新节点 / 其正条件与新负条件互斥)→ resolved
329
- · 增益 < min_gain(候选空间没变少,继续搜没意义,对齐 :273)→ 停
330
- · 超深度 / 超节点预算 / 循环检测命中 → 停
331
- """
332
- _ccg_field, _declared, _neg_hit, _cov = _prims()
333
- seed_set = {s for s in (seeds or []) if s}
334
- visited, frontier, trace = set(), [s for s in (seeds or []) if s], []
335
- nodes_visited, last_gain = 0, 0.0
336
- for d in range(1, int(max_depth) + 1):
337
- if not frontier:
338
- return {"resolved_by": [], "depth": d - 1, "nodes_visited": nodes_visited,
339
- "gain": last_gain, "stopped_by": "frontier_exhausted",
340
- "trace": trace}
341
- nxt, discriminators = [], []
342
- for nid in frontier:
343
- if nid in visited:
344
- continue
345
- visited.add(nid)
346
- nodes_visited += 1
347
- if nodes_visited > max_nodes:
348
- return {"resolved_by": [], "depth": d,
349
- "nodes_visited": nodes_visited, "gain": last_gain,
350
- "stopped_by": "node_budget", "trace": trace}
351
- node = cg.get(nid) or {}
352
- fm = node.get("frontmatter") or {}
353
- body = node.get("content") or ""
354
- e_pos, e_neg = _declared(fm, body)
355
- # 冲突源(seed)自身不是区分条件:它与新节点的关系正是待分辨的
356
- # 冲突本身,把它当作「已分辨」会制造假的 resolved(增益虚高 1.0)。
357
- if nid not in seed_set:
358
- if e_neg and tw_pos and _cov(tw_pos, " ".join(e_neg)) >= CLASH_HIGH:
359
- discriminators.append(nid)
360
- elif e_pos and tw_neg and _cov(tw_neg, " ".join(e_pos)) >= CLASH_HIGH:
361
- discriminators.append(nid)
362
- nxt.extend(_edge_targets(fm))
363
- if discriminators:
364
- return {"resolved_by": discriminators, "depth": d,
365
- "nodes_visited": nodes_visited, "gain": 1.0,
366
- "stopped_by": "resolved", "trace": trace}
367
- fresh = [x for x in dict.fromkeys(nxt) if x not in visited]
368
- last_gain = len(fresh) / float(max(1, len(frontier)))
369
- trace.append({"depth": d, "frontier": len(frontier),
370
- "fresh": len(fresh), "gain": round(last_gain, 4)})
371
- if last_gain < min_gain:
372
- return {"resolved_by": [], "depth": d, "nodes_visited": nodes_visited,
373
- "gain": round(last_gain, 4),
374
- "stopped_by": "gain_below_threshold", "trace": trace}
375
- frontier = fresh
376
- return {"resolved_by": [], "depth": int(max_depth),
377
- "nodes_visited": nodes_visited, "gain": round(last_gain, 4),
378
- "stopped_by": "depth_exceeded", "trace": trace}
379
-
380
-
381
- # --------------------------------------------------------------------------
382
- # 主入口:三级决策
383
- # --------------------------------------------------------------------------
384
-
385
- # 生效条件:以 cg.index.nodes 为既有节点、content(假值按 "")经 _new_terms 得 pos/neg 并算 tw_pos/tw_neg,按循环中 hard(自否定或纪律命中)→ divergences(同条件槽且 concl < CONCLUSION_SAME)→ strength ≥ CLASH_HIGH → strength ≥ CLASH_LOW → comparable==0 且 (pos or neg) → 否则 ACCEPT 的顺序定 verdict;DEFER 且 int(depth)>0 且 emo["bias"] != "approaching" 时调 _recursive_reflect 补 recursion,auto_flywheel 且 verdict∈{REJECT,DEFER,BLINDSPOT} 时加 unresolved_id,最后 log 并返回 rec;
386
- def check(cg, content, layer=None, condition_space=None,
387
- non_applicable_conditions=None, tags=None, exclude=None,
388
- limit=MAX_SCAN, depth=MAX_DEPTH, auto_flywheel=False,
389
- query=None):
390
- """节点间自动冲突检测(L0 情绪 → L1 反思 → L2 递归反思)。
391
-
392
- 返回完整判据(可审计):
393
- verdict / reason / conflict_strength / emotional / conflicts[] /
394
- recursion{} / missing[] / unresolved_id(若触发飞轮)
395
-
396
- verdict:
397
- ACCEPT 无冲突,或新节点未声明条件(无从冲突)
398
- REJECT 硬冲突:自否定 / 违反纪律
399
- DEFER 条件互斥但可能可分辨(交给 L2 递归或飞轮)
400
- BLINDSPOT 有条件声明,但既有节点全无声明 → 无法建立比对路径(不假装确定)
401
- """
402
- _ccg_field, _declared, _neg_hit, _cov = _prims()
403
- content = content or ""
404
- pos, neg = _new_terms(content, condition_space, non_applicable_conditions)
405
- tw_pos = expand_query_terms_weighted(" ".join(pos)) if pos else {}
406
- tw_neg = expand_query_terms_weighted(" ".join(neg)) if neg else {}
407
- # 结论文本词权(结论比对专用):**去 CCG 声明行**。模板行(`# 功能名` /
408
- # `# 子功能` 等)在两条节点间逐字相同,若混入会稀释结论覆盖率——实测
409
- # 逐字重复仅 0.32、同槽不同值 0.61,与异属性(0.62)不可分。去模板才可判。
410
- tw_content = (expand_query_terms_weighted(_body_text(content))
411
- if content else {})
412
- # 结论槽(CCG 结构字段)——「是否同一件事」的代理,见 _slot_text 说明
413
- n_fn, n_sb = _slot_text(content)
414
-
415
- conflicts, hard, divergences = [], [], []
416
- strength, scanned, comparable = 0.0, 0, 0
417
-
418
- # ---- L1-a 自否定:自己的负条件排除自己的生效条件/正文 ----
419
- body = _body_text(content)
420
- if neg and (_ban_hit(" ".join(pos), neg) or _ban_hit(body, neg)):
421
- hard.append({"type": "self_negation", "with": None,
422
- "detail": "不适用条件命中自身生效条件/正文:条件自相矛盾",
423
- "score": 1.0})
424
- strength = 1.0
425
- elif neg and _cov(tw_neg, body) >= SELF_NEGATION:
426
- hard.append({"type": "self_negation", "with": None,
427
- "detail": "负条件与正文强相关:条件与结论互斥",
428
- "score": round(_cov(tw_neg, body), 4)})
429
- strength = max(strength, round(_cov(tw_neg, body), 4))
430
-
431
- # ---- L1-b 与既有节点的条件级比对(反题) ----
432
- nodes = ((getattr(cg, "index", None) or {}).get("nodes") or {})
433
- seeds = []
434
- for nid, e in nodes.items():
435
- if exclude and nid == exclude:
436
- continue
437
- if layer and e.get("layer") != layer:
438
- continue
439
- if scanned >= int(limit):
440
- break
441
- scanned += 1
442
- node = cg.get(nid) or {}
443
- fm = node.get("frontmatter") or {}
444
- body = node.get("content") or ""
445
- e_pos, e_neg = _declared(fm, body)
446
- if not e_pos and not e_neg:
447
- continue
448
- comparable += 1
449
- # 纪律违反:**正文行为**命中纪律节点的不适用条件(negative.reject)
450
- # —— 这是「不能违反纪律」,与「条件互斥」是两回事:前者看做了什么,
451
- # 后者看声明的条件是否互相覆盖。
452
- if _is_discipline(fm, nid) and e_neg and _ban_hit(content, e_neg):
453
- hard.append({"type": "discipline", "with": nid,
454
- "with_layer": e.get("layer"),
455
- "detail": "命中纪律节点的不适用条件(negative.reject)",
456
- "score": 1.0})
457
- seeds.append(nid)
458
- strength = 1.0
459
- continue
460
- c1 = _cov(tw_pos, " ".join(e_neg)) if (tw_pos and e_neg) else 0.0
461
- c2 = _cov(tw_neg, " ".join(e_pos)) if (tw_neg and e_pos) else 0.0
462
- c = max(c1, c2)
463
- # ---- L1-c 同侧比对:第二类关系(同条件空间 · 结论槽取值分歧) ----
464
- # 与 L1-b 是**两类不同关系**:L1-b 判「条件互斥」(反题),L1-c 判
465
- # 「同条件 + 同结论槽 + 取值不同」(矛盾)。后者在词面不可判——探针实测
466
- # 「同属性不同值」正文覆盖率 0.612 反而低于「异属性」0.623,故改用
467
- # CCG 槽位字段代理「是否同一件事」。
468
- # 注:必须是独立 if 而非 else——同条件时 c=0,若并入 L1-b 分支会被
469
- # `c < CLASH_LOW: continue` 提前跳过,L1-c 永不执行。
470
- c3 = _cov(tw_pos, " ".join(e_pos)) if (tw_pos and e_pos) else 0.0
471
- c4 = _cov(tw_neg, " ".join(e_neg)) if (tw_neg and e_neg) else 0.0
472
- same_cond = max(c3, c4)
473
- if same_cond >= SAME_COND_HIGH:
474
- e_fn, e_sb = _slot_text(body)
475
- slot = max(
476
- _cov(expand_query_terms_weighted(n_fn), e_fn)
477
- if (n_fn and e_fn) else 0.0,
478
- _cov(expand_query_terms_weighted(n_sb), e_sb)
479
- if (n_sb and e_sb) else 0.0)
480
- if slot >= SLOT_HIGH:
481
- # 同口径比对(正文↔正文);tw_content 已去模板行,见上文
482
- concl = _cov(tw_content, _body_text(body)) if tw_content else 0.0
483
- if concl < CONCLUSION_SAME:
484
- divergences.append({
485
- "type": "same_condition_divergence", "with": nid,
486
- "with_layer": e.get("layer"),
487
- "detail": ("适用条件与结论槽均重合但取值不同:"
488
- "可能是更正(应覆盖旧值)或分歧(应补区分条件)"),
489
- "same_condition": round(same_cond, 4),
490
- "slot_overlap": round(slot, 4),
491
- "conclusion_overlap": round(concl, 4),
492
- "slot": (n_fn or n_sb)[:40]})
493
- if c < CLASH_LOW:
494
- continue
495
- conflicts.append({
496
- "type": "condition_clash", "with": nid,
497
- "with_layer": e.get("layer"),
498
- "detail": ("新节点适用条件落在既有节点不适用区"
499
- if c1 >= c2 else "新节点不适用条件覆盖既有节点适用区"),
500
- "score": round(c, 4),
501
- "pos_side": _dedup(pos)[:6], "neg_side": _dedup(neg)[:6]})
502
- seeds.append(nid)
503
- strength = max(strength, c)
504
-
505
- # ---- L0 情绪(独立通道,只调度不裁决) ----
506
- emo = emotional_bias(strength, _last_strength(cg))
507
-
508
- # ---- L1 四态判定 ----
509
- recursion = None
510
- missing = []
511
- allc = hard + conflicts + divergences
512
- if hard:
513
- verdict = "REJECT"
514
- reason = ";".join(h["detail"] for h in hard)
515
- elif divergences:
516
- verdict = "DEFER"
517
- reason = "同条件空间下结论槽取值不一致:需裁决是更正还是分支"
518
- # 两类关系可能同时成立(同条件分歧 vs 某节点 / 条件互斥 vs 另节点)——
519
- # 若只报 L1-c,跨侧互斥的线索会被掩盖,飞轮收到的缺口就不完整。
520
- if conflicts:
521
- reason += f';另有 {len(conflicts)} 处条件互斥(见 conflicts[])'
522
- elif strength >= CLASH_HIGH:
523
- verdict = "DEFER"
524
- reason = "条件互斥:需补区分条件后才能判定"
525
- elif strength >= CLASH_LOW:
526
- verdict = "DEFER"
527
- reason = "条件部分覆盖:待确认是否互斥"
528
- elif comparable == 0 and (pos or neg):
529
- verdict = "BLINDSPOT"
530
- reason = "既有节点均未声明条件:无法建立比对路径"
531
- else:
532
- verdict = "ACCEPT"
533
- reason = "无冲突"
534
-
535
- # ---- L2 递归反思(仅对 DEFER,且情绪未指向 approaching 的快速放行) ----
536
- if verdict == "DEFER" and int(depth) > 0 and emo["bias"] != "approaching":
537
- recursion = _recursive_reflect(cg, seeds, tw_pos, tw_neg,
538
- max_depth=int(depth))
539
- if recursion["stopped_by"] == "resolved":
540
- # 找到区分条件 → 冲突可分辨,降级为待定(不直接放行,留人工/飞轮)
541
- reason = f'{reason};已找到区分条件 {recursion["resolved_by"][:3]}'
542
- else:
543
- missing.append({
544
- "need": "区分条件",
545
- "why": f'递归反思停止于 {recursion["stopped_by"]}'
546
- f'(深度 {recursion["depth"]},增益 {recursion["gain"]})',
547
- "conflicts": [c["with"] for c in allc if c.get("with")][:5]})
548
-
549
- # 同条件取值分歧:L2 递归提供不了「区分条件」(条件本就相同),故缺口是
550
- # 「取值裁决」而非「补条件」。必须显式落 missing——否则 strength=0 →
551
- # 情绪 approaching → L2 被跳过 → missing 为空 → 飞轮收不到任何信号。
552
- if divergences and not missing:
553
- missing.append({
554
- "need": "取值裁决(同条件·同结论槽存在多条不同取值)",
555
- "why": "适用条件与结论槽均重合而正文取值不同:"
556
- "需确认是「更正」(应覆盖旧值)还是「分支」(应补区分条件)",
557
- "conflicts": [c["with"] for c in allc if c.get("with")][:5]})
558
-
559
- rec = {"t": time.time(), "layer": layer, "verdict": verdict,
560
- "reason": reason, "conflict_strength": round(strength, 4),
561
- "emotional": emo, "conflicts": allc, "recursion": recursion,
562
- "missing": missing, "scanned": scanned, "comparable": comparable,
563
- "pos": pos[:6], "neg": neg[:6],
564
- "actor": getattr(cg, "actor", "unknown")}
565
-
566
- # ---- 冲突自动触发飞轮(误差 → 补条件 → 结构更新) ----
567
- if auto_flywheel and verdict in ("REJECT", "DEFER", "BLINDSPOT"):
568
- rec["unresolved_id"] = _fire_flywheel(cg, query or content, verdict,
569
- reason, missing, allc)
570
- log(cg, rec)
571
- return rec
572
-
573
-
574
- # 生效条件:missing 为假值(None/空容器/空串)返回 "";否则逐项仅取 m.get("need") 真值者,格式化为 `need(why)`(why 缺键用 "",值为 None 则格式化 "None"),以 ";" 连接;
575
- def _missing_text(missing):
576
- """结构化缺口 → 一行文本(作为飞轮的 known_clues)。
577
-
578
- 修断链:原先 `missing=reason` 把「人话」塞进 missing 字段,而判定器产出的
579
- [{need, why, conflicts}] 落在 detail 里被 flywheel_step 忽略——上游产出了
580
- 结构,却送不到下游。
581
- """
582
- if not missing:
583
- return ""
584
- return ";".join(f'{m.get("need", "")}({m.get("why", "")})'
585
- for m in missing if m.get("need"))
586
-
587
-
588
- # 生效条件:cg 提供可调用 flywheel_step 时,以 query(假值按空串)前 200 字符、verdict、missing 文本(空则 reason)、conflicts 非 None 则作 detail 否则 missing 调用;结果 dict 的 unresolved_id 真值时返回它,否则回落 id;无 flywheel_step 或异常返回 None;
589
- def _fire_flywheel(cg, query, verdict, reason, missing, conflicts=None):
590
- """把冲突作为「误差」投给知识飞轮,返回 unresolved 条目 id(失败不阻塞写入)。
591
-
592
- conflicts:冲突现场(含 type / with / same_condition 等数值),供下游生成
593
- `# 现场:`;missing 只描述「缺什么」,不带现场,故两者都要送。
594
- """
595
- step = getattr(cg, "flywheel_step", None)
596
- if step is None:
597
- return None
598
- try:
599
- r = step({"query": (query or "")[:200], "expected_state": "ACCEPT",
600
- "actual_state": verdict,
601
- "missing": _missing_text(missing) or reason,
602
- "detail": conflicts if conflicts is not None else missing})
603
- if isinstance(r, dict):
604
- return r.get("unresolved_id") or r.get("id")
605
- except Exception:
606
- return None
607
- return None
608
-
609
-
610
- # --------------------------------------------------------------------------
611
- # 留痕 / 统计 / 自描述
612
- # --------------------------------------------------------------------------
613
-
614
- # 生效条件:cg 与 rec 给出时,将 rec 序列化为 JSON 行追加到 cg.root 下 LOG_FILE,OSError 被吞掉,返回 rec;
615
- def log(cg, rec):
616
- """append-only 留痕:每条判定可审计。"""
617
- p = os.path.join(cg.root, LOG_FILE)
618
- try:
619
- with open(p, "a", encoding="utf-8") as f:
620
- f.write(json.dumps(rec, ensure_ascii=False) + "\n")
621
- except OSError:
622
- pass
623
- return rec
624
-
625
-
626
- # 生效条件:cg 给出时,若 cg.root 下 LOG_FILE 可读,则逐行解析 JSON(空行/解析失败跳过);limit 真值时返回 out[-int(limit):][::-1](int(limit)=0 时为全部倒序),limit 为假值(0/None/"")时返回 out[::-1];路径不可用或 OSError 返回 [];
627
- def history(cg, limit=100):
628
- """最近冲突判定留痕(倒序)。"""
629
- p = os.path.join(cg.root, LOG_FILE)
630
- if not os.path.exists(p):
631
- return []
632
- out = []
633
- try:
634
- with open(p, "r", encoding="utf-8") as f:
635
- for line in f:
636
- line = line.strip()
637
- if not line:
638
- continue
639
- try:
640
- out.append(json.loads(line))
641
- except (ValueError, TypeError):
642
- pass
643
- except OSError:
644
- return []
645
- return out[-int(limit):][::-1] if limit else out[::-1]
646
-
647
-
648
- # 生效条件:逐行 json.loads 计数(不可解析行跳过、OSError 忽略、路径缺失则计数为 0),每行 total 加 1 并按 r.get("verdict")(缺键即 None 键)与 emotional.bias 为真值时的 b 累加,返回 {'records','by_verdict','by_bias','max_scan','max_depth','min_gain'},后三者取模块常量 MAX_SCAN/MAX_DEPTH/MIN_GAIN;
649
- def summary(cg):
650
- """冲突面汇总(流式计数,供 health 审计)。"""
651
- p = os.path.join(cg.root, LOG_FILE)
652
- by_verdict, by_bias, total = {}, {}, 0
653
- if os.path.exists(p):
654
- try:
655
- with open(p, "r", encoding="utf-8") as f:
656
- for line in f:
657
- line = line.strip()
658
- if not line:
659
- continue
660
- try:
661
- r = json.loads(line)
662
- except (ValueError, TypeError):
663
- continue
664
- total += 1
665
- v = r.get("verdict")
666
- by_verdict[v] = by_verdict.get(v, 0) + 1
667
- b = (r.get("emotional") or {}).get("bias")
668
- if b:
669
- by_bias[b] = by_bias.get(b, 0) + 1
670
- except OSError:
671
- pass
672
- return {"records": total, "by_verdict": by_verdict, "by_bias": by_bias,
673
- "max_scan": MAX_SCAN, "max_depth": MAX_DEPTH,
674
- "min_gain": MIN_GAIN}
675
-
676
-
677
- # 生效条件:无 required 形参,调用即返回引用 EMO_AVOID/EMO_APPROACH、VERDICTS、CLASH_HIGH/CLASH_LOW、SAME_COND_HIGH/SLOT_HIGH/CONCLUSION_SAME、MAX_DEPTH/MAX_NODES/MIN_GAIN 等模块级常量的自描述字典;
678
- def catalog():
679
- """自描述:三级决策 + 四态 + 递归约束(供 MCP / 文档对照验证)。"""
680
- return {
681
- "levels": {
682
- "L0_emotion": {
683
- "theory": "情绪 = 信息差二阶变化 d²D/dt²(智能论 §十一)",
684
- "outputs": ["approaching", "stable", "avoiding"],
685
- "constraint": "独立通道,不参与信任/资格计算,只做流程调度",
686
- "thresholds": {"avoid": EMO_AVOID, "approach": EMO_APPROACH},
687
- },
688
- "L1_reflect": {
689
- "theory": "反题 = 预测与事实冲突(条件论七操作)",
690
- "checks": ["self_negation", "discipline", "condition_clash",
691
- "same_condition_divergence"],
692
- "relations": {
693
- "condition_clash": "跨侧比对(新正↔旧负 / 新负↔旧正)= 条件互斥(反题)",
694
- "same_condition_divergence": "同侧比对(新正↔旧正 / 新负↔旧负)"
695
- "+ CCG 结论槽 = 同条件空间内的取值分歧(矛盾)",
696
- },
697
- "verdicts": list(VERDICTS),
698
- "thresholds": {"high": CLASH_HIGH, "low": CLASH_LOW,
699
- "same_condition": SAME_COND_HIGH, "slot": SLOT_HIGH,
700
- "conclusion_same": CONCLUSION_SAME},
701
- },
702
- "L2_recursive_reflect": {
703
- "theory": "递归受深度/节点数/循环/信息增益门槛约束(智能论 :273)",
704
- "max_depth": MAX_DEPTH, "max_nodes": MAX_NODES,
705
- "min_gain": MIN_GAIN,
706
- "stop_reasons": ["resolved", "gain_below_threshold",
707
- "depth_exceeded", "node_budget",
708
- "frontier_exhausted"],
709
- },
710
- },
711
- "auto_flywheel": {
712
- "theory": "知识飞轮:误差 → 补条件 → 结构更新(智能论 :725)",
713
- "triggers_on": ["REJECT", "DEFER", "BLINDSPOT"],
714
- },
715
- "discipline_detection": {"tags": list(DISCIPLINE_TAGS),
716
- "id_prefixes": ["discipline_", "work_discipline"]},
717
- "honest_boundary": "条件级(结构化)冲突检测,非语义蕴含证明;无法比对时 BLINDSPOT",
1
+ # -*- coding: utf-8 -*-
2
+ """md_cg · 节点间自动冲突检测(三级决策:情绪 → 反思 → 递归反思)
3
+
4
+ 理论出处(本仓原文,非外部知识):
5
+
6
+ · **情绪 = 信息差的二阶变化 d²D/dt²**(`docs/theory/智能的公理化基石.md` §十一,:412-510)
7
+ 工程端对应 `emotional_bias`(approaching / avoiding / stable),并且原文明确:
8
+ 「情绪通道**独立、不参与信任计算**」。故本模块 L0 只做**流程调度**,
9
+ 绝不改动 confidence / 资格判定——避免把情绪混进事实判断。
10
+
11
+ · **反题 = 预测与事实冲突**(同文档 :529,条件论七操作之一)
12
+ —— L1 一次冲突检测的理论名:新信息与既有条件的「反题」关系。
13
+
14
+ · **递归必须受约束**(同文档 :273):
15
+ 「递归必须受到深度、查询次数、节点数、循环检测和信息增益门槛约束。
16
+ 若递归没有减少候选空间,就不应继续搜索。」
17
+ —— L2 递归反思的硬约束(本模块按此实现,而非无限展开)。
18
+
19
+ · **四态路由** ACCEPT / REJECT / DEFER / BLINDSPOT(同文档 :721;
20
+ `md_cg/mdcg.py` 四态定义)—— L1 的输出语义。
21
+
22
+ · **知识飞轮:误差 → 补条件 → 结构更新**(同文档 :725;`mdcg.py:1001`
23
+ `flywheel_step`)—— 冲突**自动**落 unresolved,误差是结构更新的输入。
24
+
25
+ · **纪律四要素同构**(`docs/工作纪律_认知图条目_v1.1.json`;
26
+ `consolidate.py` CCG 四要素)—— 「不能违反纪律」= 新内容不得命中纪律节点的
27
+ `negative.reject`(不适用条件)。纪律节点用 tag/前缀识别,不硬编码具体条目。
28
+
29
+ 三级决策(顺序即语义,越靠前越廉价):
30
+
31
+ L0 情绪 :二阶信号,快速方向调整(approaching / stable / avoiding)——不裁决资格
32
+ L1 反思 :一次条件级冲突检测(自否定 / 纪律违反 / 条件互斥)→ 四态
33
+ L2 递归反思:L1 未决 → 沿关系链递归找「区分条件」;受深度/节点数/循环/增益门槛约束
34
+
35
+ 冲突自动触发飞轮:verdict ∈ {REJECT, DEFER, BLINDSPOT} 且 auto_flywheel →
36
+ `cg.flywheel_step({query, expected_state:"ACCEPT", actual_state:verdict, missing})`
37
+
38
+ 留痕 `_consistency.jsonl`(append-only):每条判定可审计「为什么冲突 / 为什么放行」。
39
+
40
+ 诚实边界:本模块是**条件级(结构化)**冲突检测,不是语义蕴含证明。它判断的是
41
+ 「声明的适用/不适用条件是否互相覆盖」,而非「两句话在逻辑上是否矛盾」。
42
+ 无法建立可比对路径时返回 BLINDSPOT,不假装确定。
43
+ """
44
+ from __future__ import annotations
45
+
46
+ import json
47
+ import os
48
+ import time
49
+
50
+ from .mdcg import expand_query_terms_weighted
51
+
52
+ # --------------------------------------------------------------------------
53
+ # 常量(全部可审计、可调)
54
+ # --------------------------------------------------------------------------
55
+
56
+ LOG_FILE = "_consistency.jsonl"
57
+
58
+ MAX_SCAN = 200 # 单次检测最多比对的既有节点数(防 O(N) 爆炸)
59
+ MAX_DEPTH = 3 # L2 递归深度上限(对齐 :273)
60
+ MAX_NODES = 60 # L2 递归展开节点上限(对齐 :273)
61
+ MIN_GAIN = 0.15 # 信息增益门槛:候选空间减少比例低于此值即停(对齐 :273)
62
+
63
+ CLASH_HIGH = 0.6 # 条件互相覆盖阈值 → 明确互斥
64
+ CLASH_LOW = 0.35 # 条件部分覆盖阈值 → 待定
65
+ SELF_NEGATION = 0.5 # 自否定阈值:负条件被自身正文强命中
66
+
67
+ # —— 第二类关系(同条件空间 · 结论槽取值分歧)阈值;均由探针实测标定 ——
68
+ # run_probe_samecond.py 实测:同条件 same_cond=1.0 / 异条件空间 0.328 → 0.75 可分
69
+ SAME_COND_HIGH = 0.75 # 同侧条件重合 → 判定「同一条件空间」
70
+ # 实测结论槽(子功能):同槽 1.0 / 同主语异属性 0.14 / 异主题 0.0 → 0.6 可分
71
+ SLOT_HIGH = 0.6 # 结论槽(功能名/子功能)重合 → 判定「同一件事」
72
+ # 实测:逐字重复 1.0 / 同槽不同值 0.61 / 同值异措辞 0.74 → 0.95 只排除逐字重复
73
+ CONCLUSION_SAME = 0.95 # 正文几乎逐字相同 → 属「重复」(该合并),不算冲突
74
+
75
+ EMO_AVOID = 0.70 # 冲突强度 ≥ 此值 → avoiding
76
+ EMO_APPROACH = 0.30 # 冲突强度 ≤ 此值 → approaching
77
+
78
+ # 纪律节点识别(tag 或 id 前缀;不硬编码具体纪律条目)
79
+ DISCIPLINE_TAGS = ("discipline", "纪律", "work_discipline", "rule", "规则", "戒律")
80
+
81
+ VERDICTS = ("ACCEPT", "REJECT", "DEFER", "BLINDSPOT")
82
+
83
+
84
+ # 生效条件:以 verdict 与 reason 构造异常(消息 `[{verdict}] {reason}`),conflicts 传假值(None/空容器等,源码 `conflicts or []`)时 self.conflicts 为 [],传真值时原样保留;
85
+ class ConsistencyError(Exception):
86
+ """硬冲突:写入被拒(自否定 / 违反纪律)。"""
87
+
88
+ # 生效条件:verdict 与 reason 必传并赋给同名属性、拼成异常消息 `[{verdict}] {reason}`;conflicts 为假值(None/空容器等,源码 `conflicts or []`)时 self.conflicts 回落到 [],为真值时原样保留;
89
+ def __init__(self, verdict, reason, conflicts=None):
90
+ self.verdict = verdict
91
+ self.reason = reason
92
+ self.conflicts = conflicts or []
93
+ super().__init__(f"[{verdict}] {reason}")
94
+
95
+
96
+ # --------------------------------------------------------------------------
97
+ # 原语:延迟导入 mdcos(避免 mdcg ← mdcos ← consistency 的循环导入)
98
+ # --------------------------------------------------------------------------
99
+
100
+ # 生效条件:无 required 形参,任一调用返回 ( _ccg_field, _declared_conditions, _neg_hit, _weighted_coverage ) 四元组;
101
+ def _prims():
102
+ """取 md_cg 已有的条件匹配原语(条件论「反题」的既有实现)。"""
103
+ from .mdcos import (_ccg_field, _declared_conditions, _neg_hit,
104
+ _weighted_coverage)
105
+ return _ccg_field, _declared_conditions, _neg_hit, _weighted_coverage
106
+
107
+
108
+ # 生效条件:xs 为可迭代对象时,逐项 str(x).strip() 后仅当结果非空且未出现过才加入 out 并返回 out;xs 为 None/False/0 时在 for 处迭代失败(TypeError);
109
+ def _dedup(xs):
110
+ out = []
111
+ for x in xs:
112
+ s = str(x).strip()
113
+ if s and s not in out:
114
+ out.append(s)
115
+ return out
116
+
117
+
118
+ # 生效条件:fm 给出时,遍历 fm.get("edges")(缺键或假值按空列表)中元素,dict 元素按 to→target→node→id 取首个真值、非 dict 元素直接作候选,候选真值时 str(t) 加入 out 并返回;
119
+ def _edge_targets(fm):
120
+ """节点声明的出边目标(兼容 dict / str 两种形态)。"""
121
+ out = []
122
+ for e in (fm.get("edges") or []):
123
+ if isinstance(e, dict):
124
+ t = e.get("to") or e.get("target") or e.get("node") or e.get("id")
125
+ else:
126
+ t = e
127
+ if t:
128
+ out.append(str(t))
129
+ return out
130
+
131
+
132
+ # 生效条件:fm 与 node_id 给出时,若 fm.get("tags")(缺键/假值按空)小写后与 DISCIPLINE_TAGS 有交集,或 str(node_id) 以 "discipline_" 或 "work_discipline" 开头,返回 True;否则返回 False;
133
+ def _is_discipline(fm, node_id):
134
+ tags = {str(t).lower() for t in (fm.get("tags") or [])}
135
+ if tags & set(DISCIPLINE_TAGS):
136
+ return True
137
+ return str(node_id).startswith(("discipline_", "work_discipline"))
138
+
139
+
140
+ # --------------------------------------------------------------------------
141
+ # 模式分离的支持件(maintain.separate 复用;也供 insight.reconstruct 取线索)
142
+ # --------------------------------------------------------------------------
143
+
144
+ #: 分离边的关系名:两个节点「看起来像,但条件不同,互为不同情境」
145
+ SEPARATION_REL = "distinct_from"
146
+
147
+
148
+ # 生效条件:fm 给出时,仅处理 fm.get("edges")(缺键/假值按空)中的 dict 元素,relation_type 或 relation(缺省空串)小写等于 SEPARATION_REL 时,按 target→to→id 取首个真值且未重复则加入 out;
149
+ def separation_targets(fm):
150
+ """节点已声明的分离对象(`distinct_from` 出边),用于幂等与去重。"""
151
+ out = []
152
+ for e in (fm.get("edges") or []):
153
+ if not isinstance(e, dict):
154
+ continue
155
+ rel = str(e.get("relation_type") or e.get("relation") or "").strip().lower()
156
+ if rel != SEPARATION_REL:
157
+ continue
158
+ t = e.get("target") or e.get("to") or e.get("id")
159
+ if t and str(t) not in out:
160
+ out.append(str(t))
161
+ return out
162
+
163
+
164
+ # 生效条件:fm 与 content 给出时,以 content(假值按空串)、fm.get("condition_space")、fm.get("non_applicable_conditions") 解析,返回去重后的 (set(pos), set(neg));
165
+ def condition_terms(fm, content):
166
+ """节点声明的(正条件, 负条件)词面集合——分离判定与重构取线索共用。"""
167
+ pos, neg = _new_terms(content or "", fm.get("condition_space"),
168
+ fm.get("non_applicable_conditions"))
169
+ return set(pos), set(neg)
170
+
171
+
172
+ # 生效条件:pos_a、neg_a、pos_b、neg_b 给出的条件词面小写化后,两侧并集均空时返回 overlap 0.0、distinct False;否则计算交集/并集比并返回 distinct 为 overlap <= CLASH_LOW;
173
+ def condition_distinct(pos_a, neg_a, pos_b, neg_b):
174
+ """两组条件是否「实质不同」:任一侧条件词面几乎不重合即为不同情境。
175
+
176
+ 返回 {'overlap': 覆盖率, 'distinct': bool}。overlap 高 = 条件相同(是重复,
177
+ 该合并);overlap 低 = 条件不同(该分离,避免混为一体)。
178
+ """
179
+ a = {str(x).lower() for x in (set(pos_a) | set(neg_a))}
180
+ b = {str(x).lower() for x in (set(pos_b) | set(neg_b))}
181
+ if not a and not b:
182
+ return {"overlap": 0.0, "distinct": False,
183
+ "note": "双方均未声明条件:无从判定分离(不假装确定)"}
184
+ union = a | b
185
+ overlap = (len(a & b) / float(len(union))) if union else 0.0
186
+ return {"overlap": round(overlap, 4), "distinct": overlap <= CLASH_LOW}
187
+
188
+
189
+ # 生效条件:content、condition_space、non_applicable_conditions 给出时,content 的 `生效条件` 字段与 condition_space 中键不以 `__` 开头且不为 `time_window` 的值并入 pos(list/tuple/set 展平,其他非 None/"" 值 str 化),non_applicable_conditions 各项及 content 的 `不适用条件` 字段值并入 neg,最后 _dedup 返回;
190
+ def _new_terms(content, condition_space, non_applicable_conditions):
191
+ """新节点声明的(正条件, 负条件)——与既有节点同口径解析。"""
192
+ _ccg_field, _declared, _neg_hit, _cov = _prims()
193
+ pos, neg = [], []
194
+ v = _ccg_field(content or "", "生效条件")
195
+ if v:
196
+ pos.append(v)
197
+ for k, val in (condition_space or {}).items():
198
+ if str(k).startswith("__") or k == "time_window":
199
+ continue
200
+ if isinstance(val, (list, tuple, set)):
201
+ pos.extend(str(x) for x in val)
202
+ elif val not in (None, ""):
203
+ pos.append(str(val))
204
+ neg.extend(str(x) for x in (non_applicable_conditions or []))
205
+ v2 = _ccg_field(content or "", "不适用条件")
206
+ if v2:
207
+ neg.append(v2)
208
+ return _dedup(pos), _dedup(neg)
209
+
210
+
211
+ # 生效条件:content 与 neg_texts 给出时,neg_texts 中任一短语去掉「不得/禁止/严禁/不能/不可/不要/勿」前缀且长度 >=2 后作为子串出现在 content(假值按空串)中则返回 True,否则 False;
212
+ def _ban_hit(content, neg_texts):
213
+ """纪律禁令命中:去掉「不得/禁止/…」前缀后,短语是否**整体出现**在正文中。
214
+
215
+ 比词袋匹配更严格——纪律条目通常是精确的禁令短语,用子串命中可避免
216
+ 「生产」这类子词把无关内容误判为违纪(假阳性会毁掉纪律的可信度)。
217
+ """
218
+ for x in (neg_texts or []):
219
+ s = str(x).strip()
220
+ for p in ("不得", "禁止", "严禁", "不能", "不可", "不要", "勿"):
221
+ if s.startswith(p):
222
+ s = s[len(p):].strip()
223
+ break
224
+ if len(s) >= 2 and s in (content or ""):
225
+ return True
226
+ return False
227
+
228
+
229
+ # 生效条件:content 为真时按行过滤,跳过 strip 后以 "#" 开头且含全角或半角冒号的行,其余原行以换行连接返回;content 假值按空串返回 "";
230
+ def _body_text(content):
231
+ """去掉 CCG 声明行(`# 字段:值`)后的正文。
232
+
233
+ 自否定看的是「正文/生效条件是否与不适用条件矛盾」,不能把节点自己声明的
234
+ `# 不适用条件:X` 当成 X 出现在正文里——否则**每个**声明了不适用条件的
235
+ 正常节点都会被误判为自相矛盾(真实 CCG 条目普遍带该字段)。
236
+ """
237
+ out = []
238
+ for line in (content or "").splitlines():
239
+ s = line.strip()
240
+ if s.startswith("#") and (":" in s or ":" in s):
241
+ continue
242
+ out.append(line)
243
+ return "\n".join(out)
244
+
245
+
246
+ # 生效条件:content 给出时(假值按空串)解析 CCG 的 `# 功能名` 与 `# 子功能` 字段并返回两者;
247
+ def _slot_text(content):
248
+ """结论槽:CCG 声明的 `# 功能名` / `# 子功能`(结构字段,非正文词面)。
249
+
250
+ 为什么需要它:L1-c 要判「两条记忆是不是在讲同一件事」,但**词面覆盖率测不了**
251
+ ——探针实测「同属性不同值」0.612 vs「异属性」0.623(负样本反超),
252
+ 因为两者与旧正文的通用词重合度相当。CCG 的槽位字段才是「在讲哪件事」的
253
+ 结构化代理,与 L1-b 用 condition_space 判「在什么条件下」同构。
254
+
255
+ 字段缺失 → 返回空串 → L1-c 不触发(保守:无从比对时不假装确定)。
256
+ """
257
+ _ccg_field, _declared, _neg_hit, _cov = _prims()
258
+ return (_ccg_field(content or "", "功能名"),
259
+ _ccg_field(content or "", "子功能"))
260
+
261
+
262
+ # --------------------------------------------------------------------------
263
+ # L0 情绪通道(信息差二阶变化)
264
+ # --------------------------------------------------------------------------
265
+
266
+ # 生效条件:conflict_strength 被夹取到 [0,1](假值按 0.0),prev_strength 为 None 时 d2=0.0,否则 d2=c-夹取后的 prev_strength;按 c>=EMO_AVOID 或 d2>0.2 返回 avoiding,或 c<=EMO_APPROACH 且 d2<=0 返回 approaching,否则 stable;
267
+ def emotional_bias(conflict_strength, prev_strength=None):
268
+ """L0:把冲突强度映射为情绪倾向(approaching / stable / avoiding)。
269
+
270
+ 对齐 `智能的公理化基石.md` §十一:情绪是**信息差的二阶变化** d²D/dt²。
271
+ 这里的工程代理:
272
+ · 一阶 d1 = conflict_strength(新信息与既有结构的相斥程度)
273
+ · 二阶 d2 = 本次 d1 − 上次 d1(用留痕里的上一条强度作基线)
274
+ · d2 > 0 → 信息差在**扩大**(越来越不顺)→ avoiding
275
+ · d2 < 0 → 信息差在**收敛**(越来越顺) → approaching
276
+
277
+ 重要(原文强制):情绪通道**独立、不参与信任/资格计算**,
278
+ 只影响「是否升级到递归反思」的调度决策。
279
+ """
280
+ c = max(0.0, min(1.0, float(conflict_strength or 0.0)))
281
+ if prev_strength is None:
282
+ d2 = 0.0
283
+ else:
284
+ d2 = c - max(0.0, min(1.0, float(prev_strength)))
285
+ if c >= EMO_AVOID or d2 > 0.2:
286
+ bias = "avoiding"
287
+ elif c <= EMO_APPROACH and d2 <= 0:
288
+ bias = "approaching"
289
+ else:
290
+ bias = "stable"
291
+ return {"bias": bias, "conflict_strength": round(c, 4),
292
+ "d2": round(d2, 4),
293
+ "note": "情绪通道独立,不参与信任/资格计算(智能论 §十一)"}
294
+
295
+
296
+ # 生效条件:cg 给出时,若 cg.root 下 LOG_FILE 可读,则逐行解析 JSON 并取 .get("conflict_strength"),返回最后一条可解析记录的该键值(缺键或值为 None 则为 None);路径不可用或 OSError 返回 None;
297
+ def _last_strength(cg):
298
+ """上一条留痕的冲突强度(二阶差分的基线)。流式读,不载全量。"""
299
+ p = os.path.join(cg.root, LOG_FILE)
300
+ if not os.path.exists(p):
301
+ return None
302
+ last = None
303
+ try:
304
+ with open(p, "r", encoding="utf-8") as f:
305
+ for line in f:
306
+ line = line.strip()
307
+ if not line:
308
+ continue
309
+ try:
310
+ last = json.loads(line).get("conflict_strength")
311
+ except (ValueError, TypeError):
312
+ pass
313
+ except OSError:
314
+ return None
315
+ return last
316
+
317
+
318
+ # --------------------------------------------------------------------------
319
+ # L2 递归反思(受深度 / 节点数 / 循环 / 增益门槛约束)
320
+ # --------------------------------------------------------------------------
321
+
322
+ # 生效条件:以 cg 节点图、seeds 中非空项为初始 frontier、tw_pos/tw_neg 词权,在 d=1..int(max_depth) 每轮先判 frontier 空返回 frontier_exhausted,再逐 nid 处理时若 nodes_visited > max_nodes 先返回 node_budget(可先于同层 discriminators),否则处理完该层后有 discriminators(非 seed_set 节点声明条件与 tw_pos/tw_neg 覆盖 >= CLASH_HIGH)返回 resolved,否则 last_gain < min_gain 返回 gain_below_threshold,循环耗尽返回 depth_exceeded;seeds 假值时 frontier 空,在 d=1 进入循环后由首判返回 frontier_exhausted(depth=0);
323
+ def _recursive_reflect(cg, seeds, tw_pos, tw_neg, max_depth=MAX_DEPTH,
324
+ max_nodes=MAX_NODES, min_gain=MIN_GAIN):
325
+ """递归反思:沿关系链找「区分条件」,每层检查信息增益。
326
+
327
+ 收敛条件(任一):
328
+ · 找到区分节点(其负条件排除新节点 / 其正条件与新负条件互斥)→ resolved
329
+ · 增益 < min_gain(候选空间没变少,继续搜没意义,对齐 :273)→ 停
330
+ · 超深度 / 超节点预算 / 循环检测命中 → 停
331
+ """
332
+ _ccg_field, _declared, _neg_hit, _cov = _prims()
333
+ seed_set = {s for s in (seeds or []) if s}
334
+ visited, frontier, trace = set(), [s for s in (seeds or []) if s], []
335
+ nodes_visited, last_gain = 0, 0.0
336
+ for d in range(1, int(max_depth) + 1):
337
+ if not frontier:
338
+ return {"resolved_by": [], "depth": d - 1, "nodes_visited": nodes_visited,
339
+ "gain": last_gain, "stopped_by": "frontier_exhausted",
340
+ "trace": trace}
341
+ nxt, discriminators = [], []
342
+ for nid in frontier:
343
+ if nid in visited:
344
+ continue
345
+ visited.add(nid)
346
+ nodes_visited += 1
347
+ if nodes_visited > max_nodes:
348
+ return {"resolved_by": [], "depth": d,
349
+ "nodes_visited": nodes_visited, "gain": last_gain,
350
+ "stopped_by": "node_budget", "trace": trace}
351
+ node = cg.get(nid) or {}
352
+ fm = node.get("frontmatter") or {}
353
+ body = node.get("content") or ""
354
+ e_pos, e_neg = _declared(fm, body)
355
+ # 冲突源(seed)自身不是区分条件:它与新节点的关系正是待分辨的
356
+ # 冲突本身,把它当作「已分辨」会制造假的 resolved(增益虚高 1.0)。
357
+ if nid not in seed_set:
358
+ if e_neg and tw_pos and _cov(tw_pos, " ".join(e_neg)) >= CLASH_HIGH:
359
+ discriminators.append(nid)
360
+ elif e_pos and tw_neg and _cov(tw_neg, " ".join(e_pos)) >= CLASH_HIGH:
361
+ discriminators.append(nid)
362
+ nxt.extend(_edge_targets(fm))
363
+ if discriminators:
364
+ return {"resolved_by": discriminators, "depth": d,
365
+ "nodes_visited": nodes_visited, "gain": 1.0,
366
+ "stopped_by": "resolved", "trace": trace}
367
+ fresh = [x for x in dict.fromkeys(nxt) if x not in visited]
368
+ last_gain = len(fresh) / float(max(1, len(frontier)))
369
+ trace.append({"depth": d, "frontier": len(frontier),
370
+ "fresh": len(fresh), "gain": round(last_gain, 4)})
371
+ if last_gain < min_gain:
372
+ return {"resolved_by": [], "depth": d, "nodes_visited": nodes_visited,
373
+ "gain": round(last_gain, 4),
374
+ "stopped_by": "gain_below_threshold", "trace": trace}
375
+ frontier = fresh
376
+ return {"resolved_by": [], "depth": int(max_depth),
377
+ "nodes_visited": nodes_visited, "gain": round(last_gain, 4),
378
+ "stopped_by": "depth_exceeded", "trace": trace}
379
+
380
+
381
+ # --------------------------------------------------------------------------
382
+ # 主入口:三级决策
383
+ # --------------------------------------------------------------------------
384
+
385
+ # 生效条件:以 cg.index.nodes 为既有节点、content(假值按 "")经 _new_terms 得 pos/neg 并算 tw_pos/tw_neg,按循环中 hard(自否定或纪律命中)→ divergences(同条件槽且 concl < CONCLUSION_SAME)→ strength ≥ CLASH_HIGH → strength ≥ CLASH_LOW → comparable==0 且 (pos or neg) → 否则 ACCEPT 的顺序定 verdict;DEFER 且 int(depth)>0 且 emo["bias"] != "approaching" 时调 _recursive_reflect 补 recursion,auto_flywheel 且 verdict∈{REJECT,DEFER,BLINDSPOT} 时加 unresolved_id,最后 log 并返回 rec;
386
+ def check(cg, content, layer=None, condition_space=None,
387
+ non_applicable_conditions=None, tags=None, exclude=None,
388
+ limit=MAX_SCAN, depth=MAX_DEPTH, auto_flywheel=False,
389
+ query=None):
390
+ """节点间自动冲突检测(L0 情绪 → L1 反思 → L2 递归反思)。
391
+
392
+ 返回完整判据(可审计):
393
+ verdict / reason / conflict_strength / emotional / conflicts[] /
394
+ recursion{} / missing[] / unresolved_id(若触发飞轮)
395
+
396
+ verdict:
397
+ ACCEPT 无冲突,或新节点未声明条件(无从冲突)
398
+ REJECT 硬冲突:自否定 / 违反纪律
399
+ DEFER 条件互斥但可能可分辨(交给 L2 递归或飞轮)
400
+ BLINDSPOT 有条件声明,但既有节点全无声明 → 无法建立比对路径(不假装确定)
401
+ """
402
+ _ccg_field, _declared, _neg_hit, _cov = _prims()
403
+ content = content or ""
404
+ pos, neg = _new_terms(content, condition_space, non_applicable_conditions)
405
+ tw_pos = expand_query_terms_weighted(" ".join(pos)) if pos else {}
406
+ tw_neg = expand_query_terms_weighted(" ".join(neg)) if neg else {}
407
+ # 结论文本词权(结论比对专用):**去 CCG 声明行**。模板行(`# 功能名` /
408
+ # `# 子功能` 等)在两条节点间逐字相同,若混入会稀释结论覆盖率——实测
409
+ # 逐字重复仅 0.32、同槽不同值 0.61,与异属性(0.62)不可分。去模板才可判。
410
+ tw_content = (expand_query_terms_weighted(_body_text(content))
411
+ if content else {})
412
+ # 结论槽(CCG 结构字段)——「是否同一件事」的代理,见 _slot_text 说明
413
+ n_fn, n_sb = _slot_text(content)
414
+
415
+ conflicts, hard, divergences = [], [], []
416
+ strength, scanned, comparable = 0.0, 0, 0
417
+
418
+ # ---- L1-a 自否定:自己的负条件排除自己的生效条件/正文 ----
419
+ body = _body_text(content)
420
+ if neg and (_ban_hit(" ".join(pos), neg) or _ban_hit(body, neg)):
421
+ hard.append({"type": "self_negation", "with": None,
422
+ "detail": "不适用条件命中自身生效条件/正文:条件自相矛盾",
423
+ "score": 1.0})
424
+ strength = 1.0
425
+ elif neg and _cov(tw_neg, body) >= SELF_NEGATION:
426
+ hard.append({"type": "self_negation", "with": None,
427
+ "detail": "负条件与正文强相关:条件与结论互斥",
428
+ "score": round(_cov(tw_neg, body), 4)})
429
+ strength = max(strength, round(_cov(tw_neg, body), 4))
430
+
431
+ # ---- L1-b 与既有节点的条件级比对(反题) ----
432
+ nodes = ((getattr(cg, "index", None) or {}).get("nodes") or {})
433
+ seeds = []
434
+ for nid, e in nodes.items():
435
+ if exclude and nid == exclude:
436
+ continue
437
+ if layer and e.get("layer") != layer:
438
+ continue
439
+ if scanned >= int(limit):
440
+ break
441
+ scanned += 1
442
+ node = cg.get(nid) or {}
443
+ fm = node.get("frontmatter") or {}
444
+ body = node.get("content") or ""
445
+ e_pos, e_neg = _declared(fm, body)
446
+ if not e_pos and not e_neg:
447
+ continue
448
+ comparable += 1
449
+ # 纪律违反:**正文行为**命中纪律节点的不适用条件(negative.reject)
450
+ # —— 这是「不能违反纪律」,与「条件互斥」是两回事:前者看做了什么,
451
+ # 后者看声明的条件是否互相覆盖。
452
+ if _is_discipline(fm, nid) and e_neg and _ban_hit(content, e_neg):
453
+ hard.append({"type": "discipline", "with": nid,
454
+ "with_layer": e.get("layer"),
455
+ "detail": "命中纪律节点的不适用条件(negative.reject)",
456
+ "score": 1.0})
457
+ seeds.append(nid)
458
+ strength = 1.0
459
+ continue
460
+ c1 = _cov(tw_pos, " ".join(e_neg)) if (tw_pos and e_neg) else 0.0
461
+ c2 = _cov(tw_neg, " ".join(e_pos)) if (tw_neg and e_pos) else 0.0
462
+ c = max(c1, c2)
463
+ # ---- L1-c 同侧比对:第二类关系(同条件空间 · 结论槽取值分歧) ----
464
+ # 与 L1-b 是**两类不同关系**:L1-b 判「条件互斥」(反题),L1-c 判
465
+ # 「同条件 + 同结论槽 + 取值不同」(矛盾)。后者在词面不可判——探针实测
466
+ # 「同属性不同值」正文覆盖率 0.612 反而低于「异属性」0.623,故改用
467
+ # CCG 槽位字段代理「是否同一件事」。
468
+ # 注:必须是独立 if 而非 else——同条件时 c=0,若并入 L1-b 分支会被
469
+ # `c < CLASH_LOW: continue` 提前跳过,L1-c 永不执行。
470
+ c3 = _cov(tw_pos, " ".join(e_pos)) if (tw_pos and e_pos) else 0.0
471
+ c4 = _cov(tw_neg, " ".join(e_neg)) if (tw_neg and e_neg) else 0.0
472
+ same_cond = max(c3, c4)
473
+ if same_cond >= SAME_COND_HIGH:
474
+ e_fn, e_sb = _slot_text(body)
475
+ slot = max(
476
+ _cov(expand_query_terms_weighted(n_fn), e_fn)
477
+ if (n_fn and e_fn) else 0.0,
478
+ _cov(expand_query_terms_weighted(n_sb), e_sb)
479
+ if (n_sb and e_sb) else 0.0)
480
+ if slot >= SLOT_HIGH:
481
+ # 同口径比对(正文↔正文);tw_content 已去模板行,见上文
482
+ concl = _cov(tw_content, _body_text(body)) if tw_content else 0.0
483
+ if concl < CONCLUSION_SAME:
484
+ divergences.append({
485
+ "type": "same_condition_divergence", "with": nid,
486
+ "with_layer": e.get("layer"),
487
+ "detail": ("适用条件与结论槽均重合但取值不同:"
488
+ "可能是更正(应覆盖旧值)或分歧(应补区分条件)"),
489
+ "same_condition": round(same_cond, 4),
490
+ "slot_overlap": round(slot, 4),
491
+ "conclusion_overlap": round(concl, 4),
492
+ "slot": (n_fn or n_sb)[:40]})
493
+ if c < CLASH_LOW:
494
+ continue
495
+ conflicts.append({
496
+ "type": "condition_clash", "with": nid,
497
+ "with_layer": e.get("layer"),
498
+ "detail": ("新节点适用条件落在既有节点不适用区"
499
+ if c1 >= c2 else "新节点不适用条件覆盖既有节点适用区"),
500
+ "score": round(c, 4),
501
+ "pos_side": _dedup(pos)[:6], "neg_side": _dedup(neg)[:6]})
502
+ seeds.append(nid)
503
+ strength = max(strength, c)
504
+
505
+ # ---- L0 情绪(独立通道,只调度不裁决) ----
506
+ emo = emotional_bias(strength, _last_strength(cg))
507
+
508
+ # ---- L1 四态判定 ----
509
+ recursion = None
510
+ missing = []
511
+ allc = hard + conflicts + divergences
512
+ if hard:
513
+ verdict = "REJECT"
514
+ reason = ";".join(h["detail"] for h in hard)
515
+ elif divergences:
516
+ verdict = "DEFER"
517
+ reason = "同条件空间下结论槽取值不一致:需裁决是更正还是分支"
518
+ # 两类关系可能同时成立(同条件分歧 vs 某节点 / 条件互斥 vs 另节点)——
519
+ # 若只报 L1-c,跨侧互斥的线索会被掩盖,飞轮收到的缺口就不完整。
520
+ if conflicts:
521
+ reason += f';另有 {len(conflicts)} 处条件互斥(见 conflicts[])'
522
+ elif strength >= CLASH_HIGH:
523
+ verdict = "DEFER"
524
+ reason = "条件互斥:需补区分条件后才能判定"
525
+ elif strength >= CLASH_LOW:
526
+ verdict = "DEFER"
527
+ reason = "条件部分覆盖:待确认是否互斥"
528
+ elif comparable == 0 and (pos or neg):
529
+ verdict = "BLINDSPOT"
530
+ reason = "既有节点均未声明条件:无法建立比对路径"
531
+ else:
532
+ verdict = "ACCEPT"
533
+ reason = "无冲突"
534
+
535
+ # ---- L2 递归反思(仅对 DEFER,且情绪未指向 approaching 的快速放行) ----
536
+ if verdict == "DEFER" and int(depth) > 0 and emo["bias"] != "approaching":
537
+ recursion = _recursive_reflect(cg, seeds, tw_pos, tw_neg,
538
+ max_depth=int(depth))
539
+ if recursion["stopped_by"] == "resolved":
540
+ # 找到区分条件 → 冲突可分辨,降级为待定(不直接放行,留人工/飞轮)
541
+ reason = f'{reason};已找到区分条件 {recursion["resolved_by"][:3]}'
542
+ else:
543
+ missing.append({
544
+ "need": "区分条件",
545
+ "why": f'递归反思停止于 {recursion["stopped_by"]}'
546
+ f'(深度 {recursion["depth"]},增益 {recursion["gain"]})',
547
+ "conflicts": [c["with"] for c in allc if c.get("with")][:5]})
548
+
549
+ # 同条件取值分歧:L2 递归提供不了「区分条件」(条件本就相同),故缺口是
550
+ # 「取值裁决」而非「补条件」。必须显式落 missing——否则 strength=0 →
551
+ # 情绪 approaching → L2 被跳过 → missing 为空 → 飞轮收不到任何信号。
552
+ if divergences and not missing:
553
+ missing.append({
554
+ "need": "取值裁决(同条件·同结论槽存在多条不同取值)",
555
+ "why": "适用条件与结论槽均重合而正文取值不同:"
556
+ "需确认是「更正」(应覆盖旧值)还是「分支」(应补区分条件)",
557
+ "conflicts": [c["with"] for c in allc if c.get("with")][:5]})
558
+
559
+ rec = {"t": time.time(), "layer": layer, "verdict": verdict,
560
+ "reason": reason, "conflict_strength": round(strength, 4),
561
+ "emotional": emo, "conflicts": allc, "recursion": recursion,
562
+ "missing": missing, "scanned": scanned, "comparable": comparable,
563
+ "pos": pos[:6], "neg": neg[:6],
564
+ "actor": getattr(cg, "actor", "unknown")}
565
+
566
+ # ---- 冲突自动触发飞轮(误差 → 补条件 → 结构更新) ----
567
+ if auto_flywheel and verdict in ("REJECT", "DEFER", "BLINDSPOT"):
568
+ rec["unresolved_id"] = _fire_flywheel(cg, query or content, verdict,
569
+ reason, missing, allc)
570
+ log(cg, rec)
571
+ return rec
572
+
573
+
574
+ # 生效条件:missing 为假值(None/空容器/空串)返回 "";否则逐项仅取 m.get("need") 真值者,格式化为 `need(why)`(why 缺键用 "",值为 None 则格式化 "None"),以 ";" 连接;
575
+ def _missing_text(missing):
576
+ """结构化缺口 → 一行文本(作为飞轮的 known_clues)。
577
+
578
+ 修断链:原先 `missing=reason` 把「人话」塞进 missing 字段,而判定器产出的
579
+ [{need, why, conflicts}] 落在 detail 里被 flywheel_step 忽略——上游产出了
580
+ 结构,却送不到下游。
581
+ """
582
+ if not missing:
583
+ return ""
584
+ return ";".join(f'{m.get("need", "")}({m.get("why", "")})'
585
+ for m in missing if m.get("need"))
586
+
587
+
588
+ # 生效条件:cg 提供可调用 flywheel_step 时,以 query(假值按空串)前 200 字符、verdict、missing 文本(空则 reason)、conflicts 非 None 则作 detail 否则 missing 调用;结果 dict 的 unresolved_id 真值时返回它,否则回落 id;无 flywheel_step 或异常返回 None;
589
+ def _fire_flywheel(cg, query, verdict, reason, missing, conflicts=None):
590
+ """把冲突作为「误差」投给知识飞轮,返回 unresolved 条目 id(失败不阻塞写入)。
591
+
592
+ conflicts:冲突现场(含 type / with / same_condition 等数值),供下游生成
593
+ `# 现场:`;missing 只描述「缺什么」,不带现场,故两者都要送。
594
+ """
595
+ step = getattr(cg, "flywheel_step", None)
596
+ if step is None:
597
+ return None
598
+ try:
599
+ r = step({"query": (query or "")[:200], "expected_state": "ACCEPT",
600
+ "actual_state": verdict,
601
+ "missing": _missing_text(missing) or reason,
602
+ "detail": conflicts if conflicts is not None else missing})
603
+ if isinstance(r, dict):
604
+ return r.get("unresolved_id") or r.get("id")
605
+ except Exception:
606
+ return None
607
+ return None
608
+
609
+
610
+ # --------------------------------------------------------------------------
611
+ # 留痕 / 统计 / 自描述
612
+ # --------------------------------------------------------------------------
613
+
614
+ # 生效条件:cg 与 rec 给出时,将 rec 序列化为 JSON 行追加到 cg.root 下 LOG_FILE,OSError 被吞掉,返回 rec;
615
+ def log(cg, rec):
616
+ """append-only 留痕:每条判定可审计。"""
617
+ p = os.path.join(cg.root, LOG_FILE)
618
+ try:
619
+ with open(p, "a", encoding="utf-8") as f:
620
+ f.write(json.dumps(rec, ensure_ascii=False) + "\n")
621
+ except OSError:
622
+ pass
623
+ return rec
624
+
625
+
626
+ # 生效条件:cg 给出时,若 cg.root 下 LOG_FILE 可读,则逐行解析 JSON(空行/解析失败跳过);limit 真值时返回 out[-int(limit):][::-1](int(limit)=0 时为全部倒序),limit 为假值(0/None/"")时返回 out[::-1];路径不可用或 OSError 返回 [];
627
+ def history(cg, limit=100):
628
+ """最近冲突判定留痕(倒序)。"""
629
+ p = os.path.join(cg.root, LOG_FILE)
630
+ if not os.path.exists(p):
631
+ return []
632
+ out = []
633
+ try:
634
+ with open(p, "r", encoding="utf-8") as f:
635
+ for line in f:
636
+ line = line.strip()
637
+ if not line:
638
+ continue
639
+ try:
640
+ out.append(json.loads(line))
641
+ except (ValueError, TypeError):
642
+ pass
643
+ except OSError:
644
+ return []
645
+ return out[-int(limit):][::-1] if limit else out[::-1]
646
+
647
+
648
+ # 生效条件:逐行 json.loads 计数(不可解析行跳过、OSError 忽略、路径缺失则计数为 0),每行 total 加 1 并按 r.get("verdict")(缺键即 None 键)与 emotional.bias 为真值时的 b 累加,返回 {'records','by_verdict','by_bias','max_scan','max_depth','min_gain'},后三者取模块常量 MAX_SCAN/MAX_DEPTH/MIN_GAIN;
649
+ def summary(cg):
650
+ """冲突面汇总(流式计数,供 health 审计)。"""
651
+ p = os.path.join(cg.root, LOG_FILE)
652
+ by_verdict, by_bias, total = {}, {}, 0
653
+ if os.path.exists(p):
654
+ try:
655
+ with open(p, "r", encoding="utf-8") as f:
656
+ for line in f:
657
+ line = line.strip()
658
+ if not line:
659
+ continue
660
+ try:
661
+ r = json.loads(line)
662
+ except (ValueError, TypeError):
663
+ continue
664
+ total += 1
665
+ v = r.get("verdict")
666
+ by_verdict[v] = by_verdict.get(v, 0) + 1
667
+ b = (r.get("emotional") or {}).get("bias")
668
+ if b:
669
+ by_bias[b] = by_bias.get(b, 0) + 1
670
+ except OSError:
671
+ pass
672
+ return {"records": total, "by_verdict": by_verdict, "by_bias": by_bias,
673
+ "max_scan": MAX_SCAN, "max_depth": MAX_DEPTH,
674
+ "min_gain": MIN_GAIN}
675
+
676
+
677
+ # 生效条件:无 required 形参,调用即返回引用 EMO_AVOID/EMO_APPROACH、VERDICTS、CLASH_HIGH/CLASH_LOW、SAME_COND_HIGH/SLOT_HIGH/CONCLUSION_SAME、MAX_DEPTH/MAX_NODES/MIN_GAIN 等模块级常量的自描述字典;
678
+ def catalog():
679
+ """自描述:三级决策 + 四态 + 递归约束(供 MCP / 文档对照验证)。"""
680
+ return {
681
+ "levels": {
682
+ "L0_emotion": {
683
+ "theory": "情绪 = 信息差二阶变化 d²D/dt²(智能论 §十一)",
684
+ "outputs": ["approaching", "stable", "avoiding"],
685
+ "constraint": "独立通道,不参与信任/资格计算,只做流程调度",
686
+ "thresholds": {"avoid": EMO_AVOID, "approach": EMO_APPROACH},
687
+ },
688
+ "L1_reflect": {
689
+ "theory": "反题 = 预测与事实冲突(条件论七操作)",
690
+ "checks": ["self_negation", "discipline", "condition_clash",
691
+ "same_condition_divergence"],
692
+ "relations": {
693
+ "condition_clash": "跨侧比对(新正↔旧负 / 新负↔旧正)= 条件互斥(反题)",
694
+ "same_condition_divergence": "同侧比对(新正↔旧正 / 新负↔旧负)"
695
+ "+ CCG 结论槽 = 同条件空间内的取值分歧(矛盾)",
696
+ },
697
+ "verdicts": list(VERDICTS),
698
+ "thresholds": {"high": CLASH_HIGH, "low": CLASH_LOW,
699
+ "same_condition": SAME_COND_HIGH, "slot": SLOT_HIGH,
700
+ "conclusion_same": CONCLUSION_SAME},
701
+ },
702
+ "L2_recursive_reflect": {
703
+ "theory": "递归受深度/节点数/循环/信息增益门槛约束(智能论 :273)",
704
+ "max_depth": MAX_DEPTH, "max_nodes": MAX_NODES,
705
+ "min_gain": MIN_GAIN,
706
+ "stop_reasons": ["resolved", "gain_below_threshold",
707
+ "depth_exceeded", "node_budget",
708
+ "frontier_exhausted"],
709
+ },
710
+ },
711
+ "auto_flywheel": {
712
+ "theory": "知识飞轮:误差 → 补条件 → 结构更新(智能论 :725)",
713
+ "triggers_on": ["REJECT", "DEFER", "BLINDSPOT"],
714
+ },
715
+ "discipline_detection": {"tags": list(DISCIPLINE_TAGS),
716
+ "id_prefixes": ["discipline_", "work_discipline"]},
717
+ "honest_boundary": "条件级(结构化)冲突检测,非语义蕴含证明;无法比对时 BLINDSPOT",
718
718
  }