@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.
- package/README.md +16 -16
- package/codebuddy/CODEBUDDY.md +11 -3
- package/codebuddy/README.md +92 -90
- package/codebuddy/mcp.json +27 -27
- 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
- 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
- package/docs/README.md +142 -111
- package/docs/discipline/harnesses.yaml +244 -226
- package/docs/discipline/templates/full.md.tmpl +61 -61
- package/docs/discipline/templates/rules.mdc.tmpl +68 -0
- package/docs/discipline/templates/skill.md.tmpl +23 -23
- 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
- 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
- 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
- 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
- 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
- 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
- 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
- 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
- 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
- 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
- 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
- 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
- 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
- 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
- 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
- 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
- package/docs/mdcg/README/350/257/246/347/273/206/347/211/210_v0.4.10.md +646 -646
- package/docs/mdcg/lingshu_tutorial.html +14449 -14449
- package/docs/mdcg/release_v0.4.11.md +49 -0
- package/docs/mdcg/release_v0.4.5.md +55 -55
- package/docs/mdcg/tool_table_v0.3.0.md +117 -117
- 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
- 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
- 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
- package/docs/mdcg//345/217/221/345/270/203/351/227/250/347/246/201/351/223/276_v0.1.md +54 -0
- 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
- 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
- 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
- package/docs/mdcg//347/274/272/345/217/243/345/215/225_P0/346/224/266/345/217/243_v0.1.md +270 -270
- 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
- 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
- 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
- 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
- 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
- package/docs/swarm//350/234/202/347/276/244/344/272/222/350/201/224_v0.1.md +704 -704
- 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
- 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
- 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
- package/docs/theory//346/231/272/350/203/275/350/256/2723.4.md +5260 -5260
- 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
- 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
- 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
- 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
- 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
- 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
- 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
- package/dsh/README.md +82 -82
- package/dsh/cordis.yml.example +139 -139
- package/dsh/update-lingshu.bat +11 -11
- package/lib/hooks.js +36 -2
- package/lib/lib/roleplay_web.js +427 -427
- package/md_cg/__init__.py +7 -7
- package/md_cg/audit.py +368 -368
- package/md_cg/autonomy.py +287 -287
- package/md_cg/backfill.py +1327 -1327
- package/md_cg/backfill_bigdomain.py +34 -34
- package/md_cg/bench6_arms.py +410 -410
- package/md_cg/bench6_common.py +230 -230
- package/md_cg/bench6_competitors.py +212 -212
- package/md_cg/bench_axis_domain.py +257 -257
- package/md_cg/bench_blind_comp.py +308 -308
- package/md_cg/bench_en_atoms_public.py +230 -230
- package/md_cg/bench_governance.py +348 -348
- package/md_cg/bench_lme_zh.py +410 -410
- package/md_cg/bench_locomo.py +121 -121
- package/md_cg/bench_locomo_zh.py +450 -450
- package/md_cg/bench_locomo_zh_public.py +147 -147
- package/md_cg/bench_longmem.py +112 -112
- package/md_cg/bench_membench.py +632 -632
- package/md_cg/bench_p0.py +149 -149
- package/md_cg/bench_progressive.py +287 -287
- package/md_cg/bench_role_views.py +238 -238
- package/md_cg/bench_task_ab.py +243 -243
- package/md_cg/bench_task_ab_llm.py +408 -408
- package/md_cg/bench_unified_en.py +204 -204
- package/md_cg/bench_zh_mad.py +601 -601
- package/md_cg/blindspot_tickets.py +123 -123
- package/md_cg/branches.py +285 -285
- package/md_cg/build_postings.py +73 -73
- package/md_cg/ccgc.py +1005 -948
- package/md_cg/census.py +132 -132
- package/md_cg/chain.py +300 -300
- package/md_cg/codeindex.py +531 -531
- package/md_cg/coldverify.py +292 -292
- package/md_cg/comment_gate.py +337 -337
- package/md_cg/cond_compose.py +190 -190
- package/md_cg/cond_facts.py +154 -154
- package/md_cg/cond_template.json +106 -106
- package/md_cg/condition_anchor.py +142 -142
- package/md_cg/conformance.py +726 -726
- package/md_cg/consistency.py +717 -717
- package/md_cg/consolidate.py +1536 -1439
- package/md_cg/corpus.py +110 -110
- package/md_cg/crosscheck.py +1097 -1097
- package/md_cg/crypto.py +437 -437
- package/md_cg/d_meta.py +310 -310
- package/md_cg/datapath.py +334 -334
- package/md_cg/docindex.py +473 -473
- package/md_cg/eval_common.py +575 -575
- package/md_cg/evidence.py +580 -580
- package/md_cg/evolution.py +477 -477
- package/md_cg/export.py +220 -220
- package/md_cg/forgetting.py +581 -581
- package/md_cg/fsutil.py +329 -329
- package/md_cg/hotcache.py +238 -214
- package/md_cg/hyperedge.py +251 -251
- package/md_cg/identity.py +390 -390
- package/md_cg/insight.py +500 -500
- package/md_cg/interop.py +199 -0
- package/md_cg/lexicon/build_cedict_en_zh.py +329 -329
- package/md_cg/lexicon/build_standard_en.py +171 -171
- package/md_cg/lexicon/expand_en_zh.py +211 -211
- package/md_cg/lifecycle.py +272 -272
- package/md_cg/linkref.py +280 -280
- package/md_cg/links.py +622 -622
- package/md_cg/mcp_server.py +129 -32
- package/md_cg/md_whitebox.py +345 -345
- package/md_cg/mdcg.py +176 -117
- package/md_cg/mdcos.py +79 -13
- package/md_cg/metacognition.py +591 -591
- package/md_cg/migrate.py +119 -119
- package/md_cg/migrate_aeis.py +221 -221
- package/md_cg/migrate_roleplay.py +293 -293
- package/md_cg/migrate_wisdom_graph.py +360 -360
- package/md_cg/mreview/__init__.py +25 -25
- package/md_cg/mreview/__main__.py +110 -110
- package/md_cg/mreview/bundle.py +178 -178
- package/md_cg/mreview/candidates.py +262 -262
- package/md_cg/mreview/govern.py +693 -693
- package/md_cg/mreview/locate.py +939 -939
- package/md_cg/mreview/pipeline.py +728 -728
- package/md_cg/mreview/rules/duplication.json +21 -21
- package/md_cg/mreview/rules/field_coverage.json +54 -54
- package/md_cg/mreview/rules/source_license.json +21 -21
- package/md_cg/mreview/rules/template_flow.json +21 -21
- package/md_cg/mreview/ruleset.py +252 -252
- package/md_cg/nodefile.py +575 -575
- package/md_cg/pooling.py +484 -472
- package/md_cg/postings.py +298 -298
- package/md_cg/predict.py +1100 -1100
- package/md_cg/progressive.py +123 -123
- package/md_cg/protect.py +272 -272
- package/md_cg/protocol/md_cg_gate.proto +33 -33
- package/md_cg/protocol.py +372 -372
- package/md_cg/provenance.py +582 -582
- package/md_cg/reach.py +453 -453
- package/md_cg/readcache.py +85 -0
- package/md_cg/refindex.py +833 -833
- package/md_cg/refine.py +604 -604
- package/md_cg/roleviews.py +89 -89
- package/md_cg/routing.py +365 -365
- package/md_cg/scrub.py +852 -852
- package/md_cg/security.py +274 -274
- package/md_cg/self_state.py +1029 -1029
- package/md_cg/selfreport.py +151 -151
- package/md_cg/semantic/__init__.py +10 -10
- package/md_cg/semantic/canonical.py +122 -122
- package/md_cg/semantic/en_normalizer.py +364 -364
- package/md_cg/semantic/en_zh_map.json +28694 -0
- package/md_cg/semantic/export_en_zh_map.py +64 -0
- package/md_cg/semantic/unify.py +45 -0
- package/md_cg/semantic/zh_en_atoms.py +139 -139
- package/md_cg/signer.py +562 -562
- package/md_cg/sources.py +815 -582
- package/md_cg/statushdr.py +179 -179
- package/md_cg/stg.py +48 -37
- package/md_cg/subgraph.py +729 -729
- package/md_cg/sustain.py +1138 -1138
- package/md_cg/tasks.py +470 -470
- package/md_cg/test_action_derive.py +203 -203
- package/md_cg/test_audit_rotate.py +270 -270
- package/md_cg/test_autonomy.py +143 -143
- package/md_cg/test_bench_governance.py +102 -102
- package/md_cg/test_blindspot_tickets.py +166 -166
- package/md_cg/test_branches.py +249 -249
- package/md_cg/test_ccg_perturb.py +184 -184
- package/md_cg/test_ccgc.py +433 -433
- package/md_cg/test_census_prune.py +81 -81
- package/md_cg/test_cond_compose_anchors.py +76 -76
- package/md_cg/test_cond_match.py +165 -165
- package/md_cg/test_condition_anchor.py +81 -81
- package/md_cg/test_d_meta.py +412 -412
- package/md_cg/test_datapath_root.py +199 -199
- package/md_cg/test_en_pipeline.py +166 -166
- package/md_cg/test_gain_gate.py +212 -212
- package/md_cg/test_health_scale.py +173 -173
- package/md_cg/test_hive_ingest.py +285 -0
- package/md_cg/test_hot_cold.py +215 -215
- package/md_cg/test_hyperedge.py +245 -245
- package/md_cg/test_i26_empty_first_write.py +116 -0
- package/md_cg/test_i27_e041_identity.py +128 -0
- package/md_cg/test_i28_hotcache_prodpath.py +122 -0
- package/md_cg/test_identity_attribution.py +147 -147
- package/md_cg/test_index_durability.py +224 -224
- package/md_cg/test_interop.py +93 -0
- package/md_cg/test_lifecycle.py +309 -309
- package/md_cg/test_linkref.py +306 -306
- package/md_cg/test_lock.py +43 -43
- package/md_cg/test_md_access_parity.py +255 -255
- package/md_cg/test_md_writepath.py +345 -345
- package/md_cg/test_mdstore_search_parity.py +160 -0
- package/md_cg/test_mr_m2.py +587 -587
- package/md_cg/test_mr_m3.py +710 -710
- package/md_cg/test_mr_m4.py +485 -485
- package/md_cg/test_p0.py +250 -250
- package/md_cg/test_p1.py +316 -316
- package/md_cg/test_p10_identity.py +173 -173
- package/md_cg/test_p11_consistency.py +233 -233
- package/md_cg/test_p12_metacognition.py +212 -212
- package/md_cg/test_p13_encryption.py +241 -241
- package/md_cg/test_p14_sustain.py +249 -249
- package/md_cg/test_p15_scrub.py +280 -280
- package/md_cg/test_p16_self_state.py +301 -301
- package/md_cg/test_p17_predict.py +354 -354
- package/md_cg/test_p18_whitebox.py +171 -171
- package/md_cg/test_p19_migrate_roleplay.py +149 -149
- package/md_cg/test_p20_evolution.py +315 -315
- package/md_cg/test_p21_tokens.py +293 -270
- package/md_cg/test_p22_theory.py +175 -175
- package/md_cg/test_p23_links.py +311 -311
- package/md_cg/test_p24_evidence.py +227 -227
- package/md_cg/test_p25_weights.py +156 -156
- package/md_cg/test_p26_refindex.py +416 -416
- package/md_cg/test_p27_docindex.py +765 -765
- package/md_cg/test_p28_refcheck.py +305 -305
- package/md_cg/test_p29_session_ingest_export.py +354 -333
- package/md_cg/test_p3.py +11 -2
- package/md_cg/test_p30_maintain.py +330 -330
- package/md_cg/test_p31_insight.py +534 -534
- package/md_cg/test_p32_backfill.py +298 -298
- package/md_cg/test_p33_ccg_wiring.py +293 -293
- package/md_cg/test_p34_crosscheck.py +331 -331
- package/md_cg/test_p35_conditioned_claim.py +252 -252
- package/md_cg/test_p36_kp_align.py +230 -230
- package/md_cg/test_p37_condition_space.py +248 -248
- package/md_cg/test_p38_concurrent_flush.py +102 -0
- package/md_cg/test_p38_contextualize.py +273 -273
- package/md_cg/test_p39_verify_flow.py +113 -0
- package/md_cg/test_p39_vision_evidence.py +369 -369
- package/md_cg/test_p40_refine_worklist.py +241 -241
- package/md_cg/test_p41_evolve_patrol.py +224 -224
- package/md_cg/test_p42_provenance.py +269 -269
- package/md_cg/test_p43_pooling.py +412 -398
- package/md_cg/test_p44_md_whitebox.py +231 -231
- package/md_cg/test_p45_session_identity.py +219 -219
- package/md_cg/test_p46_unit_scope.py +272 -272
- package/md_cg/test_p47_session_view.py +281 -0
- package/md_cg/test_p4_fuzzy.py +223 -223
- package/md_cg/test_p5_semantic.py +226 -226
- package/md_cg/test_p6_consolidate.py +440 -387
- package/md_cg/test_p7_goals_recent.py +202 -202
- package/md_cg/test_p8_subgraph_chain.py +200 -200
- package/md_cg/test_p9_forget_protect.py +231 -231
- package/md_cg/test_predict_beta.py +135 -135
- package/md_cg/test_preflight_failclosed.py +100 -100
- package/md_cg/test_progressive.py +146 -146
- package/md_cg/test_protocol.py +243 -243
- package/md_cg/test_reach.py +378 -378
- package/md_cg/test_reach_keys.py +201 -201
- package/md_cg/test_read_clip.py +141 -141
- package/md_cg/test_readcache_prodpath.py +155 -0
- package/md_cg/test_retr_gates_prodpath.py +140 -0
- package/md_cg/test_retr_s1.py +340 -340
- package/md_cg/test_retr_s1b.py +209 -209
- package/md_cg/test_retr_s3.py +194 -194
- package/md_cg/test_retr_s4.py +163 -163
- package/md_cg/test_retr_s5.py +200 -200
- package/md_cg/test_retr_s6.py +157 -157
- package/md_cg/test_retr_s7.py +384 -384
- package/md_cg/test_retr_s8_time.py +369 -316
- package/md_cg/test_retr_s9_edges.py +286 -286
- package/md_cg/test_retr_s9_entity_ctx.py +175 -175
- package/md_cg/test_review_conformance.py +367 -367
- package/md_cg/test_role_views.py +354 -354
- package/md_cg/test_sem_noise.py +242 -242
- package/md_cg/test_semantic_canonical.py +241 -241
- package/md_cg/test_subproc_encoding.py +192 -192
- package/md_cg/test_sustain_mutual.py +153 -153
- package/md_cg/test_tasks.py +409 -409
- package/md_cg/test_tool_face.py +189 -189
- package/md_cg/test_transfer.py +180 -180
- package/md_cg/test_trust.py +361 -361
- package/md_cg/test_twophase.py +286 -286
- package/md_cg/test_v14_fixes.py +397 -397
- package/md_cg/test_validity_filter.py +280 -280
- package/md_cg/test_verify_answer.py +138 -138
- package/md_cg/test_wisdom_md_store.py +292 -292
- package/md_cg/test_writelimit.py +197 -197
- package/md_cg/test_writepipe.py +214 -214
- package/md_cg/theory.py +273 -273
- package/md_cg/tokens.py +677 -663
- package/md_cg/tool_face.py +260 -260
- package/md_cg/trust.py +986 -950
- package/md_cg/twophase.py +231 -231
- package/md_cg/units.py +667 -667
- package/md_cg/vision_evidence.py +666 -666
- package/md_cg/weights.py +624 -624
- package/md_cg/whitebox.py +527 -527
- package/md_cg/whitebox_kb/__init__.py +37 -37
- package/md_cg/whitebox_kb/aeis_core/__init__.py +42 -42
- package/md_cg/whitebox_kb/aeis_core/semantic.py +280 -280
- package/md_cg/whitebox_kb/aeis_core/textutil.py +13 -13
- package/md_cg/whitebox_kb/engine.py +310 -310
- package/md_cg/whitebox_kb/seed_knowledge//346/231/272/350/203/275/350/256/2723.4.md +5260 -5260
- package/md_cg/whitebox_kb/wisdom/browser_units.py +2631 -2631
- package/md_cg/whitebox_kb/wisdom/causal_discover.py +432 -432
- package/md_cg/whitebox_kb/wisdom/chat_engine.py +1506 -1506
- package/md_cg/whitebox_kb/wisdom/code_solidified.json +6195 -6195
- package/md_cg/whitebox_kb/wisdom/compiler_code_units.py +3033 -3033
- package/md_cg/whitebox_kb/wisdom/condition_algebra.py +112 -112
- package/md_cg/whitebox_kb/wisdom/condition_frame.py +315 -315
- package/md_cg/whitebox_kb/wisdom/condition_kb.py +108 -108
- package/md_cg/whitebox_kb/wisdom/conflict_map.json +4445 -4445
- package/md_cg/whitebox_kb/wisdom/core/lexer.py +512 -512
- package/md_cg/whitebox_kb/wisdom/core/name_checker.py +1023 -1023
- package/md_cg/whitebox_kb/wisdom/cspmn.py +258 -258
- package/md_cg/whitebox_kb/wisdom/csre.py +264 -264
- package/md_cg/whitebox_kb/wisdom/danmaku_audit.py +252 -252
- package/md_cg/whitebox_kb/wisdom/distilled_condition_units.json +6417 -6417
- package/md_cg/whitebox_kb/wisdom/docs/WB-EVAL-20260902b.json +1950 -1950
- package/md_cg/whitebox_kb/wisdom/docs/WB-EVAL-20260902c.json +1296 -1296
- package/md_cg/whitebox_kb/wisdom/docs/whitebox_capability_graph_demo.json +59 -59
- package/md_cg/whitebox_kb/wisdom/graph_db_units.py +3089 -3089
- package/md_cg/whitebox_kb/wisdom/knowledge_points.py +318 -318
- package/md_cg/whitebox_kb/wisdom/md_access.py +470 -470
- package/md_cg/whitebox_kb/wisdom/md_store.py +276 -251
- package/md_cg/whitebox_kb/wisdom/migrate_wisdom.py +476 -476
- package/md_cg/whitebox_kb/wisdom/navigate.py +248 -248
- package/md_cg/whitebox_kb/wisdom/neural_retrieve.py +224 -224
- package/md_cg/whitebox_kb/wisdom/os_units.py +2735 -2735
- package/md_cg/whitebox_kb/wisdom/pattern_separation.py +376 -376
- package/md_cg/whitebox_kb/wisdom/prereq_map.json +364 -364
- package/md_cg/whitebox_kb/wisdom/python_code_units.py +2766 -2766
- package/md_cg/whitebox_kb/wisdom/role_solidified.json +7 -7
- package/md_cg/whitebox_kb/wisdom/route_memory.py +244 -244
- package/md_cg/whitebox_kb/wisdom/scene_reconstruction.py +148 -148
- package/md_cg/whitebox_kb/wisdom/snr_report.json +40 -40
- package/md_cg/whitebox_kb/wisdom/test_code_compose_domains.py +7541 -7541
- package/md_cg/whitebox_kb/wisdom/test_compiler_self_bootstrap.py +354 -354
- package/md_cg/whitebox_kb/wisdom/test_ecosystem_assembly.py +158 -158
- package/md_cg/whitebox_kb/wisdom/test_ecosystem_demos.py +193 -193
- package/md_cg/whitebox_kb/wisdom/test_graph_db.py +292 -292
- package/md_cg/whitebox_kb/wisdom/test_python_self_bootstrap.py +160 -160
- package/md_cg/whitebox_kb/wisdom/trigger_words_index.json +4366 -4366
- package/md_cg/whitebox_kb/wisdom/verifier.py +1297 -1297
- package/md_cg/writelimit.py +356 -356
- package/md_cg/writepipe.py +550 -542
- package/package.json +97 -96
- package/skills/plugin.json +54 -54
- package/skills/skills/designer-perspective/SKILL.md +158 -158
- package/skills/skills/designer-perspective/references/01-observation-position.md +66 -66
- package/skills/skills/designer-perspective/references/02-structure-recognition.md +62 -62
- package/skills/skills/designer-perspective/references/03-direction-judgment.md +55 -55
- package/skills/skills/designer-perspective/references/04-qualification-verdict.md +72 -72
- package/skills/skills/designer-perspective/references/05-condition-attribution.md +74 -74
- package/skills/skills/designer-perspective/scripts/designer.py +545 -545
- package/skills/skills/designer-perspective/tests/cases.jsonl +17 -17
- package/skills/skills/designer-perspective/tests/selftest.py +61 -61
- package/skills/skills/lingshu-browser/SKILL.md +60 -60
- package/skills/skills/lingshu-compiler/SKILL.md +56 -56
- package/skills/skills/lingshu-compiler/units/analyze-type-infer/SKILL.md +45 -45
- package/skills/skills/lingshu-compiler/units/check-name-real/SKILL.md +45 -45
- package/skills/skills/lingshu-compiler/units/compile-assign/SKILL.md +45 -45
- package/skills/skills/lingshu-compiler/units/compile-expr-tree/SKILL.md +45 -45
- package/skills/skills/lingshu-compiler/units/compile-full-pipeline/SKILL.md +45 -45
- package/skills/skills/lingshu-compiler/units/compile-func-def/SKILL.md +45 -45
- package/skills/skills/lingshu-compiler/units/compile-if-then/SKILL.md +45 -45
- package/skills/skills/lingshu-compiler/units/compile-logic-expr/SKILL.md +45 -45
- package/skills/skills/lingshu-compiler/units/compile-recursive/SKILL.md +45 -45
- package/skills/skills/lingshu-compiler/units/compile-scope/SKILL.md +45 -45
- package/skills/skills/lingshu-compiler/units/compile-type-check/SKILL.md +45 -45
- package/skills/skills/lingshu-compiler/units/compile-while/SKILL.md +45 -45
- package/skills/skills/lingshu-compiler/units/compiler-0010c4bf/SKILL.md +45 -45
- package/skills/skills/lingshu-compiler/units/compiler-0355bffb/SKILL.md +45 -45
- package/skills/skills/lingshu-compiler/units/compiler-0361708a/SKILL.md +45 -45
- package/skills/skills/lingshu-compiler/units/compiler-054a0414/SKILL.md +45 -45
- package/skills/skills/lingshu-compiler/units/compiler-05a1691a/SKILL.md +45 -45
- package/skills/skills/lingshu-compiler/units/compiler-05eeed1e/SKILL.md +45 -45
- package/skills/skills/lingshu-compiler/units/compiler-0622a1f6/SKILL.md +45 -45
- package/skills/skills/lingshu-compiler/units/compiler-08b54217/SKILL.md +45 -45
- package/skills/skills/lingshu-compiler/units/compiler-0a62b70c/SKILL.md +45 -45
- package/skills/skills/lingshu-compiler/units/compiler-0ab24d00/SKILL.md +45 -45
- package/skills/skills/lingshu-compiler/units/compiler-0e093688/SKILL.md +45 -45
- package/skills/skills/lingshu-compiler/units/compiler-0e82b966/SKILL.md +45 -45
- package/skills/skills/lingshu-compiler/units/compiler-0ee9b9b9/SKILL.md +45 -45
- package/skills/skills/lingshu-compiler/units/compiler-0f3787e6/SKILL.md +45 -45
- package/skills/skills/lingshu-compiler/units/compiler-1028685f/SKILL.md +45 -45
- package/skills/skills/lingshu-compiler/units/compiler-11897630/SKILL.md +45 -45
- package/skills/skills/lingshu-compiler/units/compiler-16661b9b/SKILL.md +45 -45
- package/skills/skills/lingshu-compiler/units/compiler-1f722303/SKILL.md +45 -45
- package/skills/skills/lingshu-compiler/units/compiler-25be1262/SKILL.md +45 -45
- package/skills/skills/lingshu-compiler/units/compiler-2a76ba07/SKILL.md +45 -45
- package/skills/skills/lingshu-compiler/units/compiler-2dbea54a/SKILL.md +45 -45
- package/skills/skills/lingshu-compiler/units/compiler-2df52f16/SKILL.md +45 -45
- package/skills/skills/lingshu-compiler/units/compiler-2ec2c9d2/SKILL.md +45 -45
- package/skills/skills/lingshu-compiler/units/compiler-2f8c8f39/SKILL.md +45 -45
- package/skills/skills/lingshu-compiler/units/compiler-38378ac7/SKILL.md +45 -45
- package/skills/skills/lingshu-compiler/units/compiler-39457d2e/SKILL.md +45 -45
- package/skills/skills/lingshu-compiler/units/compiler-39fb5926/SKILL.md +45 -45
- package/skills/skills/lingshu-compiler/units/compiler-47f4fbfa/SKILL.md +45 -45
- package/skills/skills/lingshu-compiler/units/compiler-4a8cd1f1/SKILL.md +45 -45
- package/skills/skills/lingshu-compiler/units/compiler-4b230b6b/SKILL.md +45 -45
- package/skills/skills/lingshu-compiler/units/compiler-4cbbda95/SKILL.md +45 -45
- package/skills/skills/lingshu-compiler/units/compiler-4d5a68ff/SKILL.md +45 -45
- package/skills/skills/lingshu-compiler/units/compiler-56dc9bdd/SKILL.md +45 -45
- package/skills/skills/lingshu-compiler/units/compiler-57e76ebe/SKILL.md +45 -45
- package/skills/skills/lingshu-compiler/units/compiler-61ff016b/SKILL.md +45 -45
- package/skills/skills/lingshu-compiler/units/compiler-63eae588/SKILL.md +45 -45
- package/skills/skills/lingshu-compiler/units/compiler-64c4224b/SKILL.md +45 -45
- package/skills/skills/lingshu-compiler/units/compiler-66377955/SKILL.md +45 -45
- package/skills/skills/lingshu-compiler/units/compiler-674ab4f6/SKILL.md +45 -45
- package/skills/skills/lingshu-compiler/units/compiler-6af76fd6/SKILL.md +45 -45
- package/skills/skills/lingshu-compiler/units/compiler-6d979db2/SKILL.md +45 -45
- package/skills/skills/lingshu-compiler/units/compiler-6de326c0/SKILL.md +45 -45
- package/skills/skills/lingshu-compiler/units/compiler-6f1c0eea/SKILL.md +45 -45
- package/skills/skills/lingshu-compiler/units/compiler-724d6c9b/SKILL.md +45 -45
- package/skills/skills/lingshu-compiler/units/compiler-7690177f/SKILL.md +45 -45
- package/skills/skills/lingshu-compiler/units/compiler-7b229a7d/SKILL.md +45 -45
- package/skills/skills/lingshu-compiler/units/compiler-7f471b3a/SKILL.md +45 -45
- package/skills/skills/lingshu-compiler/units/compiler-815cad08/SKILL.md +45 -45
- package/skills/skills/lingshu-compiler/units/compiler-83c61634/SKILL.md +45 -45
- package/skills/skills/lingshu-compiler/units/compiler-8c798c81/SKILL.md +45 -45
- package/skills/skills/lingshu-compiler/units/compiler-8dd747ac/SKILL.md +45 -45
- package/skills/skills/lingshu-compiler/units/compiler-90324d0a/SKILL.md +45 -45
- package/skills/skills/lingshu-compiler/units/compiler-94b8d72d/SKILL.md +45 -45
- package/skills/skills/lingshu-compiler/units/compiler-94f12231/SKILL.md +45 -45
- package/skills/skills/lingshu-compiler/units/compiler-95937c16/SKILL.md +45 -45
- package/skills/skills/lingshu-compiler/units/compiler-98a5625b/SKILL.md +45 -45
- package/skills/skills/lingshu-compiler/units/compiler-98b4c42f/SKILL.md +45 -45
- package/skills/skills/lingshu-compiler/units/compiler-98e3894a/SKILL.md +45 -45
- package/skills/skills/lingshu-compiler/units/compiler-9bdfe4b8/SKILL.md +45 -45
- package/skills/skills/lingshu-compiler/units/compiler-9d9b4e83/SKILL.md +45 -45
- package/skills/skills/lingshu-compiler/units/compiler-9f7be5ad/SKILL.md +45 -45
- package/skills/skills/lingshu-compiler/units/compiler-a6daf076/SKILL.md +45 -45
- package/skills/skills/lingshu-compiler/units/compiler-a7995a0c/SKILL.md +45 -45
- package/skills/skills/lingshu-compiler/units/compiler-a8399248/SKILL.md +45 -45
- package/skills/skills/lingshu-compiler/units/compiler-aabbd099/SKILL.md +45 -45
- package/skills/skills/lingshu-compiler/units/compiler-afe169d8/SKILL.md +45 -45
- package/skills/skills/lingshu-compiler/units/compiler-b0678bda/SKILL.md +45 -45
- package/skills/skills/lingshu-compiler/units/compiler-b09bd196/SKILL.md +45 -45
- package/skills/skills/lingshu-compiler/units/compiler-b1396e23/SKILL.md +45 -45
- package/skills/skills/lingshu-compiler/units/compiler-b9b31ce0/SKILL.md +45 -45
- package/skills/skills/lingshu-compiler/units/compiler-c10264a7/SKILL.md +45 -45
- package/skills/skills/lingshu-compiler/units/compiler-cb1e8e4b/SKILL.md +45 -45
- package/skills/skills/lingshu-compiler/units/compiler-ccafd438/SKILL.md +45 -45
- package/skills/skills/lingshu-compiler/units/compiler-cda9c262/SKILL.md +45 -45
- package/skills/skills/lingshu-compiler/units/compiler-ce648068/SKILL.md +45 -45
- package/skills/skills/lingshu-compiler/units/compiler-cf5776a4/SKILL.md +45 -45
- package/skills/skills/lingshu-compiler/units/compiler-d974e5d3/SKILL.md +45 -45
- package/skills/skills/lingshu-compiler/units/compiler-e3979fd3/SKILL.md +45 -45
- package/skills/skills/lingshu-compiler/units/compiler-eb1cf2b5/SKILL.md +45 -45
- package/skills/skills/lingshu-compiler/units/compiler-ecb30d5b/SKILL.md +45 -45
- package/skills/skills/lingshu-compiler/units/compiler-f8c8b24b/SKILL.md +45 -45
- package/skills/skills/lingshu-compiler/units/compiler-f99fedbe/SKILL.md +45 -45
- package/skills/skills/lingshu-compiler/units/compiler-fa8ff5f7/SKILL.md +45 -45
- package/skills/skills/lingshu-compiler/units/compiler-fe1b058d/SKILL.md +45 -45
- package/skills/skills/lingshu-compiler/units/lex-chinese-program/SKILL.md +45 -45
- package/skills/skills/lingshu-compiler/units/lex-dao-de-jing/SKILL.md +45 -45
- package/skills/skills/lingshu-compiler/units/lex-nine-chapters/SKILL.md +45 -45
- package/skills/skills/lingshu-compiler/units/vm-arithmetic/SKILL.md +45 -45
- package/skills/skills/lingshu-compiler/units/vm-array-ops/SKILL.md +45 -45
- package/skills/skills/lingshu-compiler/units/vm-closure-call/SKILL.md +45 -45
- package/skills/skills/lingshu-compiler/units/vm-closure-create/SKILL.md +45 -45
- package/skills/skills/lingshu-compiler/units/vm-compare/SKILL.md +45 -45
- package/skills/skills/lingshu-compiler/units/vm-cond-jump/SKILL.md +45 -45
- package/skills/skills/lingshu-compiler/units/vm-cond-space/SKILL.md +45 -45
- package/skills/skills/lingshu-compiler/units/vm-exception/SKILL.md +45 -45
- package/skills/skills/lingshu-compiler/units/vm-func-call/SKILL.md +45 -45
- package/skills/skills/lingshu-compiler/units/vm-loop-run/SKILL.md +45 -45
- package/skills/skills/lingshu-compiler/units/vm-profiling/SKILL.md +45 -45
- package/skills/skills/lingshu-compiler/units/vm-refcount/SKILL.md +45 -45
- package/skills/skills/lingshu-compiler/units/vm-run-loop/SKILL.md +45 -45
- package/skills/skills/lingshu-compiler/units/vm-short-circuit/SKILL.md +45 -45
- package/skills/skills/lingshu-compiler/units/vm-stack-guard/SKILL.md +45 -45
- package/skills/skills/lingshu-compiler/units/vm-stack-ops/SKILL.md +45 -45
- package/skills/skills/lingshu-compiler/units/vm-trust-accum/SKILL.md +45 -45
- package/skills/skills/lingshu-graph/SKILL.md +63 -63
- package/skills/skills/lingshu-net/SKILL.md +48 -48
- package/skills/skills/lingshu-os/SKILL.md +64 -64
- package/skills/skills/lingshu-pylang/SKILL.md +71 -71
- package/src/bridge.ts +401 -401
- package/src/hooks.ts +38 -2
- package/src/lib/datapath.ts +326 -326
- package/src/lib/mdcg_client.ts +413 -413
- package/src/lib/mutual.ts +428 -428
- package/src/lib/prompt_safety.ts +62 -62
- package/src/lib/python_path.ts +71 -71
- package/src/lib/roleplay_web.ts +932 -932
- package/src/lib/token_store.ts +192 -192
- package/src/tools.ts +212 -212
- package/zcode/AGENTS.md +11 -3
- package/zcode/README.md +41 -41
- /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
package/md_cg/consistency.py
CHANGED
|
@@ -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
|
}
|