@furongjun1999/dsh-memory 0.4.7 → 0.4.9
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +130 -47
- package/codebuddy/CODEBUDDY.md +21 -10
- package/codebuddy/README.md +13 -1
- package/codebuddy/mcp.json +9 -0
- package/docs/GBrain/345/217/257/345/200/237/351/211/264/347/202/271_/347/201/265/346/236/242/350/220/275/347/202/271/344/272/244/346/216/245_20260919.md +169 -0
- package/docs/Pi/345/217/257/345/255/246/344/271/240/344/274/230/347/202/271_/347/201/265/346/236/242/345/244/247/350/204/221/346/224/271/350/277/233/344/272/244/346/216/245_20260915.md +144 -0
- package/docs/README.md +111 -0
- package/docs/discipline/harnesses.yaml +226 -152
- package/docs/discipline/templates/full.md.tmpl +61 -58
- package/docs/eval//347/254/254/344/270/211/346/226/271/351/252/214/350/257/201/346/212/245/345/221/212_LoCoMo_/347/201/265/346/236/242_.md +127 -0
- package/docs/eval//347/254/254/344/270/211/346/226/271/351/252/214/350/257/201/346/212/245/345/221/212_LoCoMo_/347/201/265/346/236/242_.png +0 -0
- package/docs/eval//347/254/254/344/270/211/346/226/271/351/252/214/350/257/201/346/212/245/345/221/212_/347/201/265/346/236/242_vs_dejavu_/347/273/237/344/270/200/350/257/204/345/210/206_v7.md +202 -0
- package/docs/experiments/linkref_backfill/candidates_20260917.json +726 -0
- package/docs/experiments/linkref_backfill/candidates_internal_20260917.json +602 -0
- package/docs/experiments/linkref_backfill/candidates_internal_v2.json +603 -0
- package/docs/experiments/linkref_backfill/candidates_secret_20260917.json +884 -0
- package/docs/experiments/linkref_backfill/candidates_secret_v2.json +789 -0
- package/docs/experiments/m4-role-probe/census.py +86 -0
- package/docs/experiments/m4-role-probe/probe.py +89 -0
- package/docs/experiments/mapped_confidence/bench_mapped_conf.py +216 -0
- package/docs/experiments/mapped_confidence/post_check.py +75 -0
- package/docs/experiments/mapped_confidence/repro_thirdparty_tol.py +83 -0
- package/docs/experiments/mapped_confidence/result_mapped_conf.json +215 -0
- package/docs/hive//345/244/232/347/253/257harness/351/200/232/344/277/241/345/245/221/347/272/246_v0.1.md +42 -0
- package/docs/hive//346/243/200/347/264/242/346/224/266/346/225/233/345/256/236/346/265/213/344/270/216S1b/350/256/276/350/256/241_v0.1.md +43 -0
- package/docs/hive//346/243/200/347/264/242/350/267/257/345/276/204/344/270/216/350/256/244/347/237/245/347/273/223/346/236/204/345/245/221/347/272/246_v0.1.md +102 -0
- package/docs/hive//347/234/237/345/256/236/345/272/223/347/253/257/345/210/260/347/253/257/345/256/236/346/265/213_S1b/344/270/216/345/217/254/345/233/236/346/235/203/350/241/241_v0.1.md +57 -0
- package/docs/hive//347/234/237/345/256/236/345/272/223/347/253/257/345/210/260/347/253/257/345/256/236/346/265/213_S7/345/200/222/346/216/222/345/200/231/351/200/211/345/261/202_v0.1.md +126 -0
- package/docs/hive//350/234/202/345/267/242/345/217/214/345/256/236/344/276/213/344/272/222/351/252/214_/350/256/276/350/256/241/345/256/232/347/250/277.md +503 -0
- package/docs/{ → hive/}/350/234/202/345/267/242/345/267/245/344/275/234/350/256/260/345/277/206_/351/241/271/347/233/256/350/256/241/345/210/222.md +14 -2
- package/docs/mdcg/D_meta_/345/267/245/347/250/213/345/214/226/346/226/271/346/241/210_v0.2.md +216 -0
- package/docs/{README → mdcg/README}/350/257/246/347/273/206/347/211/210_v0.4.5.md +631 -625
- package/docs/{ → mdcg/}/344/270/273/344/273/243/347/220/206/345/255/220/344/273/243/347/220/206/350/256/260/345/277/206/346/236/266/346/236/204/350/256/276/350/256/241.md +1 -1
- package/docs/mdcg//344/273/243/347/240/201/350/257/204/345/256/241/344/270/216/346/235/241/344/273/266/345/214/226/346/263/250/351/207/212_/345/245/221/347/272/246_v0.1.md +82 -0
- package/docs/mdcg//345/205/250/345/272/223/344/273/243/347/240/201/350/257/204/345/256/241/344/270/216/346/235/241/344/273/266/345/214/226/346/263/250/351/207/212_/350/256/241/345/210/222_v0.1.md +600 -0
- package/docs/mdcg//345/212/237/350/203/275/350/260/203/347/224/250/346/230/240/345/260/204/350/241/250_v0.1.md +263 -0
- package/docs/{ → mdcg/}/345/215/225/345/205/203/350/207/252/346/210/221/351/224/232/347/202/271_/347/263/273/347/273/237/346/217/220/347/244/272/350/257/215/346/240/207/345/207/206_v0.3.md +1 -1
- package/docs/mdcg//345/255/220/344/273/243/347/220/206/351/205/215/347/275/256/346/240/207/345/207/206_v0.5.md +236 -0
- package/docs/{ → mdcg/}/346/272/220/347/240/201/347/272/247/346/236/266/346/236/204/345/256/241/350/256/241_GPT/346/211/271/350/257/204/345/257/271/347/205/247_v1.0.md +2 -2
- package/docs/{ → mdcg/}/347/201/265/346/236/242/344/270/211/345/261/202/346/213/206/345/210/206/350/247/204/345/210/222_v0.1.md +181 -181
- package/docs/mdcg//347/201/265/346/236/242/350/256/260/345/277/206/345/212/250/350/257/215/345/215/217/350/256/256_v1.0-draft.md +172 -0
- package/docs/mdcg//347/216/257/344/272/214_/347/231/275/347/256/261/345/241/253/345/205/205/346/265/201/346/260/264/347/272/277_v0.1.md +31 -0
- package/docs/{ → mdcg/}/347/274/272/345/217/243/345/215/225_P0/346/224/266/345/217/243_v0.1.md +2 -2
- package/docs/{ → mdcg/}/350/256/244/347/237/245/345/233/276_G4-G8/347/274/272/345/217/243/350/243/201/345/256/232/345/215/225_v0.1.md +1 -1
- package/docs/{ → mdcg/}/350/256/244/347/237/245/345/233/276_/347/264/242/345/274/225/344/270/216/345/267/245/347/250/213/350/247/204/350/214/203/345/214/226_/350/256/241/345/210/222_v0.1.md +4 -4
- package/docs/{ → mdcg/}/350/256/260/345/277/206/346/223/215/344/275/234/347/263/273/347/273/237_MdCGOS/344/270/216MCP/346/216/245/345/205/245_v0.1.md +2 -2
- package/docs/mdcg//350/267/250/347/253/257/351/252/214/350/257/201/344/270/216/345/220/214/346/255/245/345/215/217/350/256/256_v0.1.md +93 -0
- package/docs/plans/GridWorld/346/234/200/345/260/217/351/227/255/347/216/257/350/247/204/346/240/274_v0.1.md +176 -0
- package/docs/{ → swarm/}/350/234/202/347/276/244/344/272/222/350/201/224_v0.1.md +3 -3
- package/docs/swarm//350/234/202/347/276/244/345/220/214/351/224/231/346/243/200/346/265/213/345/256/236/351/252/214/345/215/217/350/256/256_v0.1.md +242 -0
- package/docs/theory//345/215/225/347/272/277/347/250/213/344/270/216/346/263/250/346/204/217/345/212/233/351/233/206/344/270/255_/346/227/240/344/272/211/350/256/256/347/220/206/350/256/272/346/226/207/346/241/243_v1.0.md +129 -0
- package/docs/theory//345/271/266/345/217/221/345/277/205/347/204/266/346/200/247/347/220/206/350/256/272_v0.2.md +134 -0
- package/docs/theory//346/246/202/345/277/265/345/210/206/345/261/202/345/257/271/351/275/220/350/241/250_v0.1.md +145 -0
- package/docs/{ → theory/}/347/220/206/350/256/272_/346/234/272/345/210/266_/344/273/243/347/240/201_/345/256/236/351/252/214_/347/274/272/345/217/243/347/237/251/351/230/265_v0.1.md +6 -6
- package/docs/{ → theory/}/347/220/206/350/256/272/344/273/223/346/213/206/345/210/206/344/270/216/347/231/275/347/256/261/347/237/245/350/257/206/345/272/223/345/206/205/350/277/201_v0.1.md +1 -1
- package/docs/theory//350/256/244/347/237/245/344/273/243/347/220/206/344/270/216/346/224/266/346/225/233/347/273/223/346/236/204_/346/235/241/344/273/266/350/256/272/351/207/215/346/236/204_v0.1.md +221 -0
- package/docs/world_model//344/270/226/347/225/214/346/250/241/345/236/213_/347/245/236/347/273/217/347/275/221/347/273/234/345/272/225/345/261/202/346/236/266/346/236/204_v1.0.md +237 -0
- package/docs//345/255/230/347/256/227/344/270/200/344/275/223/346/236/266/346/236/204/345/255/246/344/271/240_/345/244/226/351/203/250/347/220/206/350/256/272/345/257/271/347/205/247/344/270/216/350/267/257/347/272/277/344/272/244/346/216/245_20260916.md +98 -0
- package/docs//345/255/230/347/256/227/344/270/200/344/275/223/347/245/236/347/273/217/347/275/221/347/273/234/346/236/266/346/236/204_/346/200/273/347/272/262/344/270/216/344/272/244/346/216/245_20260916.md +109 -0
- package/docs//345/267/245/344/275/234/347/272/252/345/276/213_/350/256/244/347/237/245/345/233/276/346/235/241/347/233/256_v1.1.json +434 -405
- package/docs//347/201/265/346/236/242/350/207/252/346/210/221/346/224/271/350/277/233/345/267/245/344/275/234/350/256/241/345/210/222_/345/244/226/351/203/250/347/240/224/347/251/266/347/263/273/345/210/227/345/220/270/346/224/266_v1_20260919.md +286 -0
- package/docs//347/231/275/347/256/261/345/214/226/347/272/262/351/242/206_/344/270/211/351/241/271/347/233/256/345/255/246/344/271/240/346/200/273/346/236/266/346/236/204/344/270/216Ghidra/344/272/244/346/216/245_20260916.md +104 -0
- package/docs//350/256/260/345/277/206/350/257/204/345/256/241/347/263/273/347/273/237_/347/253/213/351/241/271/350/256/276/350/256/241/344/270/216/346/226/275/345/267/245/344/272/244/346/216/245_20260915.md +183 -0
- package/dsh/README.md +34 -1
- package/dsh/cordis.yml.example +13 -7
- package/dsh/hive-mcp-probe.mjs +94 -0
- package/dsh/hive-mcp.example.yml +62 -0
- package/dsh/update-lingshu.bat +11 -0
- package/dsh/update-lingshu.ps1 +337 -0
- package/lib/hooks.d.ts +8 -0
- package/lib/hooks.js +27 -24
- package/lib/index.d.ts +4 -2
- package/lib/index.js +29 -6
- package/lib/lib/datapath.d.ts +76 -1
- package/lib/lib/datapath.js +199 -13
- package/lib/lib/mdcg_client.d.ts +6 -3
- package/lib/lib/mdcg_client.js +6 -5
- package/lib/lib/mutual.js +4 -4
- package/lib/lib/prompt_safety.d.ts +48 -0
- package/lib/lib/prompt_safety.js +62 -0
- package/lib/lib/token_store.js +4 -5
- package/md_cg/audit.py +91 -2
- package/md_cg/autonomy.py +86 -15
- package/md_cg/backfill.py +36 -1
- package/md_cg/backfill_bigdomain.py +34 -0
- package/md_cg/bench6_arms.py +28 -1
- package/md_cg/bench6_common.py +10 -1
- package/md_cg/bench6_competitors.py +6 -1
- package/md_cg/bench_axis_domain.py +9 -1
- package/md_cg/bench_blind_comp.py +7 -1
- package/md_cg/bench_en_atoms_public.py +9 -0
- package/md_cg/bench_governance.py +348 -0
- package/md_cg/bench_lme_zh.py +16 -1
- package/md_cg/bench_locomo.py +2 -1
- package/md_cg/bench_locomo_zh.py +16 -1
- package/md_cg/bench_locomo_zh_public.py +4 -1
- package/md_cg/bench_longmem.py +2 -1
- package/md_cg/bench_membench.py +37 -6
- package/md_cg/bench_p0.py +4 -1
- package/md_cg/bench_progressive.py +61 -10
- package/md_cg/bench_role_views.py +238 -0
- package/md_cg/bench_task_ab.py +8 -1
- package/md_cg/bench_task_ab_llm.py +13 -1
- package/md_cg/bench_unified_en.py +6 -1
- package/md_cg/bench_zh_mad.py +20 -1
- package/md_cg/blindspot_tickets.py +123 -0
- package/md_cg/branches.py +286 -0
- package/md_cg/build_postings.py +73 -0
- package/md_cg/ccgc.py +949 -0
- package/md_cg/census.py +5 -1
- package/md_cg/chain.py +24 -3
- package/md_cg/codeindex.py +134 -17
- package/md_cg/coldverify.py +265 -0
- package/md_cg/comment_gate.py +338 -0
- package/md_cg/cond_compose.py +190 -0
- package/md_cg/cond_facts.py +155 -0
- package/md_cg/cond_template.json +107 -0
- package/md_cg/condition_anchor.py +143 -0
- package/md_cg/conformance.py +727 -0
- package/md_cg/consistency.py +25 -2
- package/md_cg/consolidate.py +53 -2
- package/md_cg/corpus.py +5 -1
- package/md_cg/crosscheck.py +42 -2
- package/md_cg/crypto.py +35 -1
- package/md_cg/d_meta.py +310 -0
- package/md_cg/datapath.py +201 -26
- package/md_cg/docindex.py +122 -1
- package/md_cg/eval_common.py +35 -6
- package/md_cg/evidence.py +27 -1
- package/md_cg/evolution.py +21 -1
- package/md_cg/export.py +11 -1
- package/md_cg/forgetting.py +34 -4
- package/md_cg/fsutil.py +81 -2
- package/md_cg/hotcache.py +214 -0
- package/md_cg/hyperedge.py +251 -0
- package/md_cg/identity.py +20 -3
- package/md_cg/insight.py +19 -3
- package/md_cg/lexicon/build_cedict_en_zh.py +9 -0
- package/md_cg/lexicon/build_standard_en.py +171 -168
- package/md_cg/lexicon/expand_en_zh.py +6 -0
- package/md_cg/lifecycle.py +273 -0
- package/md_cg/linkref.py +281 -0
- package/md_cg/links.py +29 -1
- package/md_cg/mcp_server.py +894 -168
- package/md_cg/md_whitebox.py +53 -1
- package/md_cg/mdcg.py +1205 -41
- package/md_cg/mdcos.py +1060 -76
- package/md_cg/metacognition.py +39 -4
- package/md_cg/migrate.py +4 -0
- package/md_cg/migrate_aeis.py +221 -213
- package/md_cg/migrate_roleplay.py +8 -0
- package/md_cg/migrate_wisdom_graph.py +14 -1
- package/md_cg/mreview/__init__.py +25 -0
- package/md_cg/mreview/__main__.py +110 -0
- package/md_cg/mreview/bundle.py +178 -0
- package/md_cg/mreview/candidates.py +262 -0
- package/md_cg/mreview/govern.py +694 -0
- package/md_cg/mreview/locate.py +939 -0
- package/md_cg/mreview/pipeline.py +729 -0
- package/md_cg/mreview/rules/duplication.json +21 -0
- package/md_cg/mreview/rules/field_coverage.json +54 -0
- package/md_cg/mreview/rules/source_license.json +21 -0
- package/md_cg/mreview/rules/template_flow.json +21 -0
- package/md_cg/mreview/ruleset.py +253 -0
- package/md_cg/nodefile.py +269 -1
- package/md_cg/pooling.py +23 -1
- package/md_cg/postings.py +298 -0
- package/md_cg/predict.py +113 -15
- package/md_cg/progressive.py +3 -0
- package/md_cg/protect.py +18 -5
- package/md_cg/protocol.py +372 -0
- package/md_cg/provenance.py +262 -0
- package/md_cg/reach.py +453 -0
- package/md_cg/refindex.py +88 -4
- package/md_cg/refine.py +20 -1
- package/md_cg/roleviews.py +89 -0
- package/md_cg/routing.py +76 -0
- package/md_cg/scrub.py +68 -3
- package/md_cg/security.py +26 -1
- package/md_cg/self_state.py +65 -2
- package/md_cg/selfreport.py +151 -0
- package/md_cg/semantic/canonical.py +5 -0
- package/md_cg/semantic/en_normalizer.py +364 -295
- package/md_cg/semantic/zh_en_atoms.py +139 -136
- package/md_cg/signer.py +41 -1
- package/md_cg/sources.py +583 -547
- package/md_cg/statushdr.py +179 -0
- package/md_cg/stg.py +59 -18
- package/md_cg/subgraph.py +23 -0
- package/md_cg/sustain.py +74 -1
- package/md_cg/tasks.py +471 -0
- package/md_cg/test_action_derive.py +203 -0
- package/md_cg/test_audit_rotate.py +270 -0
- package/md_cg/test_autonomy.py +26 -0
- package/md_cg/test_bench_governance.py +102 -0
- package/md_cg/test_blindspot_tickets.py +166 -0
- package/md_cg/test_branches.py +249 -0
- package/md_cg/test_ccg_perturb.py +1 -1
- package/md_cg/test_ccgc.py +433 -0
- package/md_cg/test_codeindex.py +338 -0
- package/md_cg/test_comment_gate.py +187 -0
- package/md_cg/test_cond_compose_anchors.py +76 -0
- package/md_cg/test_condition_anchor.py +82 -0
- package/md_cg/test_conformance.py +343 -0
- package/md_cg/test_d_meta.py +412 -0
- package/md_cg/test_datapath_root.py +188 -0
- package/md_cg/test_en_pipeline.py +24 -0
- package/md_cg/test_gain_gate.py +47 -1
- package/md_cg/test_health_scale.py +173 -0
- package/md_cg/test_hot_cold.py +187 -0
- package/md_cg/test_hyperedge.py +245 -0
- package/md_cg/test_identity_attribution.py +6 -0
- package/md_cg/test_index_durability.py +224 -0
- package/md_cg/test_lifecycle.py +309 -0
- package/md_cg/test_linkref.py +306 -0
- package/md_cg/test_md_access_parity.py +15 -3
- package/md_cg/test_mr_m1.py +769 -0
- package/md_cg/test_mr_m2.py +587 -0
- package/md_cg/test_mr_m3.py +710 -0
- package/md_cg/test_mr_m4.py +485 -0
- package/md_cg/test_p1.py +1 -1
- package/md_cg/test_p11_consistency.py +1 -1
- package/md_cg/test_p12_metacognition.py +2 -2
- package/md_cg/test_p16_self_state.py +1 -1
- package/md_cg/test_p26_refindex.py +50 -21
- package/md_cg/test_p27_docindex.py +258 -4
- package/md_cg/test_p28_refcheck.py +1 -1
- package/md_cg/test_p29_session_ingest_export.py +1 -1
- package/md_cg/test_p2_mcp.py +7 -1
- package/md_cg/test_p31_insight.py +24 -0
- package/md_cg/test_p38_contextualize.py +1 -1
- package/md_cg/test_p39_vision_evidence.py +1 -1
- package/md_cg/test_p40_refine_worklist.py +1 -1
- package/md_cg/test_p41_evolve_patrol.py +1 -1
- package/md_cg/test_p42_provenance.py +1 -1
- package/md_cg/test_p43_pooling.py +41 -13
- package/md_cg/test_p44_md_whitebox.py +14 -1
- package/md_cg/test_protocol.py +243 -0
- package/md_cg/test_reach.py +378 -0
- package/md_cg/test_reach_keys.py +201 -0
- package/md_cg/test_reach_meta_exits.py +145 -0
- package/md_cg/test_read_clip.py +141 -0
- package/md_cg/test_retr_s1.py +340 -0
- package/md_cg/test_retr_s1b.py +209 -0
- package/md_cg/test_retr_s3.py +194 -0
- package/md_cg/test_retr_s4.py +163 -0
- package/md_cg/test_retr_s5.py +200 -0
- package/md_cg/test_retr_s6.py +157 -0
- package/md_cg/test_retr_s7.py +385 -0
- package/md_cg/test_retr_s8_time.py +316 -0
- package/md_cg/test_retr_s9_edges.py +286 -0
- package/md_cg/test_retr_s9_entity_ctx.py +175 -0
- package/md_cg/test_review_conformance.py +367 -0
- package/md_cg/test_role_views.py +354 -0
- package/md_cg/test_tasks.py +409 -0
- package/md_cg/test_tool_face.py +189 -0
- package/md_cg/test_trust.py +361 -0
- package/md_cg/test_twophase.py +286 -0
- package/md_cg/test_units_poll.py +71 -0
- package/md_cg/test_v14_fixes.py +397 -0
- package/md_cg/test_validity_filter.py +280 -0
- package/md_cg/test_wisdom_md_store.py +7 -3
- package/md_cg/test_writepipe.py +214 -0
- package/md_cg/theory.py +17 -2
- package/md_cg/tokens.py +134 -12
- package/md_cg/tool_face.py +261 -0
- package/md_cg/trust.py +943 -0
- package/md_cg/twophase.py +232 -0
- package/md_cg/units.py +665 -0
- package/md_cg/vision_evidence.py +25 -2
- package/md_cg/weights.py +25 -2
- package/md_cg/whitebox.py +33 -2
- package/md_cg/whitebox_kb/data/verify_cache.json +21233 -360
- package/md_cg/whitebox_kb/data/verify_savings.jsonl +5124 -0
- package/md_cg/whitebox_kb/wisdom/audit_log/chain_heat.json +10 -10
- package/md_cg/whitebox_kb/wisdom/code_compose.py +113 -6
- package/md_cg/whitebox_kb/wisdom/code_solidified.json +1 -1
- package/md_cg/whitebox_kb/wisdom/verifier.py +340 -55
- package/md_cg/whitebox_kb/wisdom/wisdom-book-cloud.db +0 -0
- package/md_cg/writelimit.py +37 -7
- package/md_cg/writepipe.py +543 -0
- package/package.json +2 -2
- package/skills/skills/designer-perspective/scripts/__pycache__/designer.cpython-310.pyc +0 -0
- package/skills/skills/designer-perspective/scripts/designer.py +17 -1
- package/skills/skills/designer-perspective/tests/selftest.py +3 -1
- package/src/hooks.ts +27 -22
- package/src/index.ts +33 -6
- package/src/lib/datapath.ts +211 -13
- package/src/lib/mdcg_client.ts +12 -8
- package/src/lib/mutual.ts +411 -411
- package/src/lib/prompt_safety.ts +62 -0
- package/src/lib/token_store.ts +4 -5
- package/zcode/AGENTS.md +21 -10
- package/zcode/README.md +4 -0
- package/docs//345/212/237/350/203/275/350/260/203/347/224/250/346/230/240/345/260/204/350/241/250_v0.1.md +0 -221
- /package/docs/{AGI → eval/AGI}/344/270/203/347/273/264/350/257/204/345/210/206/346/212/245/345/221/212_md_cg_v1.0.md" +0 -0
- /package/docs/{AGI → eval/AGI}/344/270/203/347/273/264/350/257/204/345/210/206/346/212/245/345/221/212_md_cg_v2.0.md" +0 -0
- /package/docs/{ → eval/}/345/256/236/351/252/214/346/226/271/346/241/210_/345/255/246/344/271/240/351/227/255/347/216/257AB/344/270/216/346/250/252/350/257/204_v1.0.md" +0 -0
- /package/docs/{ → eval/}/346/250/252/350/257/204_/345/205/255/345/256/266100/351/242/230/344/270/255/350/213/261/345/217/214/346/237/245_v1.0.md" +0 -0
- /package/docs/{guardrail-charter.md → mdcg/guardrail-charter.md} +0 -0
- /package/docs/{lingshu_tutorial.html → mdcg/lingshu_tutorial.html} +0 -0
- /package/docs/{memory-assessment.html → mdcg/memory-assessment.html} +0 -0
- /package/docs/{memory_score.html → mdcg/memory_score.html} +0 -0
- /package/docs/{memory_score.png → mdcg/memory_score.png} +0 -0
- /package/docs/{release_v0.3.0.md → mdcg/release_v0.3.0.md} +0 -0
- /package/docs/{release_v0.4.5.md → mdcg/release_v0.4.5.md} +0 -0
- /package/docs/{tool_table_v0.3.0.md → mdcg/tool_table_v0.3.0.md} +0 -0
- /package/docs/{ → mdcg/}/344/273/244/347/211/214/344/270/216/350/247/222/350/211/262/346/235/203/350/201/214/345/210/206/347/246/273_v0.1.md" +0 -0
- /package/docs/{ → mdcg/}/347/201/265/346/236/24282/345/267/245/345/205/267_/345/212/237/350/203/275/346/225/264/347/220/206/344/270/216/350/277/201/347/247/273/346/230/240/345/260/204_v0.1.md" +0 -0
- /package/docs/{ → mdcg/}/347/201/265/346/236/242MCP/345/267/245/345/205/267/346/200/273/350/241/250_v3.4.md" +0 -0
- /package/docs/{ → mdcg/}/347/201/265/346/236/242_/350/207/252/346/210/221/345/261/202/345/256/232/344/271/211.md" +0 -0
- /package/docs/{ → mdcg/}/350/256/244/347/237/245/345/233/276_MD/347/233/256/345/275/225/346/226/271/346/241/210_v0.1.md" +0 -0
- /package/docs/{ → mdcg/}/350/256/244/347/237/245/345/233/276_/346/235/241/344/273/266/347/251/272/351/227/264/345/220/210/346/210/220/344/270/216/347/224/237/346/225/210/346/235/241/344/273/266/345/217/243/345/276/204_v0.1.md" +0 -0
- /package/docs/{ → mdcg/}/350/256/244/347/237/245/345/233/276/344/275/234/344/270/272/350/256/260/345/277/206/346/223/215/344/275/234/347/263/273/347/273/237_/350/257/204/344/274/260/344/270/216/350/267/257/347/272/277_v0.1.md" +0 -0
- /package/docs/{ → plans/}/345/221/275/345/220/215/346/262/273/347/220/206_/351/241/271/347/233/256/350/256/241/345/210/222.md" +0 -0
- /package/docs/{ → plans/}/347/237/245/350/257/206/345/233/276/350/260/261/351/241/271/347/233/256_/344/272/244/346/216/245/346/226/207/346/241/243_20260914.md" +0 -0
- /package/docs/{ → swarm/}/350/234/202/347/276/244/345/244/232/346/231/272/350/203/275/344/275/223_/344/275/277/347/224/250/346/212/245/345/221/212_20260913.md" +0 -0
- /package/docs/{ → swarm/}/350/234/202/347/276/244/345/244/232/346/231/272/350/203/275/344/275/223_/345/212/237/350/203/275/350/257/264/346/230/216_v0.6.md" +0 -0
- /package/docs/{ → swarm/}/350/234/202/347/276/244/347/233/262/345/214/272/346/240/207/350/256/260_v1.0.md" +0 -0
- /package/docs/{ → theory/}/344/277/241/346/201/257/345/267/256/344/270/272/344/273/200/344/271/210/345/277/205/347/204/266/345/255/230/345/234/250/344/270/224/350/207/252/347/204/266/346/211/251/345/244/247.md" +0 -0
- /package/docs/{ → theory/}/346/231/272/350/203/275/347/232/204/345/205/254/347/220/206/345/214/226/345/237/272/347/237/263.md" +0 -0
- /package/docs/{ → theory/}/346/231/272/350/203/275/347/232/204/350/256/244/347/237/245/350/277/207/347/250/213.md" +0 -0
- /package/docs/{ → theory/}/346/231/272/350/203/275/350/256/2723.4.md" +0 -0
- /package/docs/{ → theory/}/347/231/275/347/256/261/346/231/272/350/203/275/346/230/257/344/273/200/344/271/210/357/274/237.md" +0 -0
- /package/docs/{ → theory/}/347/231/275/347/256/261/346/231/272/350/203/275/347/263/273/345/210/227/302/267/347/254/254/344/272/224/347/257/207/357/274/232/350/256/251AI/347/234/237/346/255/243/350/243/205/344/270/212/350/256/260/345/277/206.md" +0 -0
package/md_cg/mcp_server.py
CHANGED
|
@@ -52,11 +52,13 @@ PROTOCOL_VERSION = "2024-11-05"
|
|
|
52
52
|
# 工具定义
|
|
53
53
|
# --------------------------------------------------------------------------
|
|
54
54
|
|
|
55
|
+
# 生效条件:传 _desc 与任意 props 时返回 {"type":"object","properties":props,"required":[...]},required 仅列出 props 中值含真值 "_req" 键的条目名。
|
|
55
56
|
def _s(_desc, **props):
|
|
56
57
|
return {"type": "object", "properties": props, "required":
|
|
57
58
|
[k for k, v in props.items() if v.get("_req")]}
|
|
58
59
|
|
|
59
60
|
|
|
61
|
+
# 生效条件:始终返回 {"type":t,"description":desc},仅当 req 为真值时该字典额外含 "_req": True。
|
|
60
62
|
def _p(t, desc, req=False):
|
|
61
63
|
d = {"type": t, "description": desc}
|
|
62
64
|
if req:
|
|
@@ -64,6 +66,7 @@ def _p(t, desc, req=False):
|
|
|
64
66
|
return d
|
|
65
67
|
|
|
66
68
|
|
|
69
|
+
# 生效条件:exp 为假值(None/空容器等)时返回 None,exp 为真值时返回 _expand 闭包——该闭包调用时先取 expand_query_terms_weighted(q),再对 exp 每项(dict 项 term=str(it.get("term") or "").strip()、w=float(it.get("weight",0.5)) 抛 TypeError/ValueError 则 w=0.5;非 dict 项 term=str(it).strip()、w=0.5)在 term 非空时写 out[term]=max(out.get(term,0.0), max(0.0,min(1.0,w))),最后置 out["__source__"]="llm" 并返回 out;
|
|
67
70
|
def _make_query_expand(exp):
|
|
68
71
|
"""把调用方(LLM/多智能体)提供的扩展词包装成 query_expand 注入函数。
|
|
69
72
|
|
|
@@ -74,6 +77,7 @@ def _make_query_expand(exp):
|
|
|
74
77
|
return None
|
|
75
78
|
from .mdcg import expand_query_terms_weighted
|
|
76
79
|
|
|
80
|
+
# 生效条件:在外层 _make_query_expand(exp) 的 exp 为真值前提下被调用时,先 out=expand_query_terms_weighted(q),再对 _exp(默认绑定外层 exp)每项——dict 项取 term=str(it.get("term") or "").strip()、w=float(it.get("weight",0.5))(抛 TypeError/ValueError 则 w=0.5),非 dict 项取 term=str(it).strip()、w=0.5,term 非空时 out[term]=max(out.get(term,0.0), max(0.0,min(1.0,w))),最后置 out["__source__"]="llm" 并返回 out。
|
|
77
81
|
def _expand(q, _exp=exp):
|
|
78
82
|
out = expand_query_terms_weighted(q)
|
|
79
83
|
for it in _exp:
|
|
@@ -138,6 +142,11 @@ TOOLS = [
|
|
|
138
142
|
"仅在查询时刻生效,索引侧仍白箱"),
|
|
139
143
|
session=_p("string", "会话归属过滤(frontmatter.session;"
|
|
140
144
|
"多会话共用 root 时只取本会话记忆;缺省不过滤)"),
|
|
145
|
+
validity=_p("boolean", "时效过滤(**显式启用**,缺省不过滤):"
|
|
146
|
+
"仅排除**已过期**(valid_until 已过)节点;"
|
|
147
|
+
"**未生效(valid_from 未到)一律保留**——"
|
|
148
|
+
"「尚未开始」与「已失效」语义相反,预约/计划类"
|
|
149
|
+
"记忆在生效前仍可召回"),
|
|
141
150
|
goal=_p("string", "当前目标(第 5 篇第 3 章):启用 goal 路给召回定向;"
|
|
142
151
|
"省略则自动取活跃目标"),
|
|
143
152
|
goal_path=_p("boolean", "启用目标定向路(默认否;给 goal 即自动启用)"),
|
|
@@ -155,7 +164,10 @@ TOOLS = [
|
|
|
155
164
|
layer=_p("string", "限定层"), context=_p("object", "情境"),
|
|
156
165
|
roles=_p("array", "限定角色"), include_work=_p("boolean", "含工作角色"),
|
|
157
166
|
session=_p("string", "会话归属过滤(frontmatter.session;"
|
|
158
|
-
"缺省不过滤)")
|
|
167
|
+
"缺省不过滤)"),
|
|
168
|
+
validity=_p("boolean", "时效过滤(显式启用,缺省不过滤):仅排除"
|
|
169
|
+
"**已过期**(valid_until 已过)节点,"
|
|
170
|
+
"未生效(valid_from 未到)保留")),
|
|
159
171
|
},
|
|
160
172
|
{
|
|
161
173
|
"name": "mdcg_get",
|
|
@@ -213,11 +225,13 @@ TOOLS = [
|
|
|
213
225
|
},
|
|
214
226
|
{
|
|
215
227
|
"name": "mdcg_review_decide",
|
|
216
|
-
"description": "审核裁决:accept / reject / edit / merge(merge 需 merge_into)。"
|
|
228
|
+
"description": "审核裁决:accept / reject / edit / merge / noop(merge 需 merge_into)。"
|
|
229
|
+
"noop=已评估、判定不改变任何现有记忆:只留痕并关闭提案,"
|
|
230
|
+
"不落业务节点、不进负记忆(与 reject 的区别是语义而非路径)。"
|
|
217
231
|
"redteam.verdict=reject 不落库,转 needs_reapproval,"
|
|
218
232
|
"修复后须带递增 round 的 pass 再审批;判据只读不可改。",
|
|
219
233
|
"inputSchema": _s("", pid=_p("string", "提案 id", True),
|
|
220
|
-
decision=_p("string", "accept|reject|edit|merge", True),
|
|
234
|
+
decision=_p("string", "accept|reject|edit|merge|noop", True),
|
|
221
235
|
edits=_p("object", "edit 时的覆盖字段"), merge_into=_p("string", "merge 目标节点 id"),
|
|
222
236
|
reason=_p("string", "裁决理由"),
|
|
223
237
|
redteam=_p("object", "红队裁决 {verdict:pass|reject, issues:[], round:n}"),
|
|
@@ -307,13 +321,16 @@ TOOLS = [
|
|
|
307
321
|
"情绪=信息差二阶变化 d²D/dt²(§十一)→ 轨迹面;"
|
|
308
322
|
"自信校准(期望正确率 vs 实际验证通过率,过度自信/过度保守)→ 校准面;"
|
|
309
323
|
"盲区地图(反复 BLINDSPOT 的查询邻域 + 未解问题,推论三)→ 盲区面;"
|
|
310
|
-
"P_gap/P_trust + 情感 d²T/dt²(§十)→
|
|
324
|
+
"P_gap/P_trust + 情感 d²T/dt²(§十)→ 信任面;"
|
|
325
|
+
"D_meta 边界压力向量(events_pressure / unmodeled_growth / "
|
|
326
|
+
"boundary_violation_rate 各自 [0,1],**不合成单值**,DEV-002a)"
|
|
327
|
+
"→ 边界面。"
|
|
311
328
|
"action=report 完整报告(含确定性建议)/ trace / calibration / "
|
|
312
329
|
"blindspots / trust / self_check(回答前自检:该直接答还是先补条件)"
|
|
313
|
-
" / history / catalog。只读留痕,不改事实层。",
|
|
330
|
+
" / history / d_meta / catalog。只读留痕,不改事实层。",
|
|
314
331
|
"inputSchema": _s("", action=_p("string", "report|trace|calibration|"
|
|
315
332
|
"blindspots|trust|self_check|"
|
|
316
|
-
"history|catalog"),
|
|
333
|
+
"history|d_meta|catalog"),
|
|
317
334
|
query=_p("string", "self_check 的待答查询"),
|
|
318
335
|
k=_p("integer", "self_check:相似历史条数"),
|
|
319
336
|
window=_p("integer", "轨迹/信任的滚动窗口"),
|
|
@@ -496,7 +513,9 @@ KERNEL_TOOLS = [
|
|
|
496
513
|
{
|
|
497
514
|
"name": "cg",
|
|
498
515
|
"description": "认知图接口(唯一入口)。op=route:按情境条件路由,返回相关知识 + "
|
|
499
|
-
"建议能力名(不执行,由调用方决定);op=read:召回/检索/按 id
|
|
516
|
+
"建议能力名(不执行,由调用方决定);op=read:召回/检索/按 id 取"
|
|
517
|
+
"(长内容自动截断 2000 行 / 50KB,返回 truncated+next_offset,"
|
|
518
|
+
"续读传 offset=next_offset,不静默丢内容);"
|
|
500
519
|
"op=write:写入前按 content_kind 审核(ACCEPT 落盘 / REJECT 进负记忆 / "
|
|
501
520
|
"DEFER 进审核队列)+ 节点间冲突检测(三级决策:情绪→反思→递归反思;"
|
|
502
521
|
"consistency=false 可关,on_conflict=reject|defer|record);"
|
|
@@ -507,6 +526,12 @@ KERNEL_TOOLS = [
|
|
|
507
526
|
"op=forget:软删除/恢复(受保护节点需 override);"
|
|
508
527
|
"op=goal:目标槽(第 5 篇七件套之「目标」,"
|
|
509
528
|
"action=add|list|status;目标不进召回,只给 read 定向);"
|
|
529
|
+
"op=task:结构层任务实体(跨会话的工程台账,与信任/自我/协议同级;"
|
|
530
|
+
"action=open 登记或更新(同名即同卡)、status 状态迁移"
|
|
531
|
+
"(进行中/受阻/完成/放弃,迁 完成 时结果必填)、plan_add 追加计划变更、"
|
|
532
|
+
"get 单卡全字段、list 清单、find 同族提示(只提示不合并)、"
|
|
533
|
+
"session 会话装配面(进行中+近期完成);"
|
|
534
|
+
"任务只存骨架,中间过程不入库,任务知识走 knowledge 层);"
|
|
510
535
|
"op=recent:近期事件窗口(七件套之「近期事件」,"
|
|
511
536
|
"action=add|list|clear,滚动保留最近 N 条);"
|
|
512
537
|
"op=identity:身份特征识别(智能论 v3.4 位置效应 + 扮演论"
|
|
@@ -562,16 +587,59 @@ KERNEL_TOOLS = [
|
|
|
562
587
|
"另有节点**派生溯源**(区别于对端信任):derive 列边、"
|
|
563
588
|
"derive_dangling 悬空巡检(只读、不删边)、derive_catalog 自描述、"
|
|
564
589
|
"derive_rebuild 按 frontmatter 重建台账(默认预演);权威声明只在"
|
|
565
|
-
"节点写入时产生(write/remember 的 derived_from
|
|
590
|
+
"节点写入时产生(write/remember 的 derived_from),本层不新增写入口);"
|
|
591
|
+
"op=session:会话三件套(action=note 写要点 / recall 续接 / "
|
|
592
|
+
"compact 压摘要;hook 缺失时的库侧替代——载体负责「何时做」、库保证"
|
|
593
|
+
"「一次调用就够用」;note 与 compact(note=True) 需 can_write,recall 只读);"
|
|
594
|
+
"op=ingest:文件摄取(action=file|dir|jsonl|stat;写链需 can_write,"
|
|
595
|
+
"支持 dry_run 预演与 incremental 增量去重、watermark 留痕);"
|
|
596
|
+
"op=export:全库导出(action=graph|nodes|slice|stat;导出整库属管理"
|
|
597
|
+
"操作,一律 require_admin);"
|
|
598
|
+
"op=maintain:记忆维护(action=stat|history|importance|longterm|"
|
|
599
|
+
"prefeed|separate|rollback|backfill|cap|exempt|vision_evidence|refine|"
|
|
600
|
+
"propagate 及其 *_history;propagate = 验证态的**多跳**失效传播巡检"
|
|
601
|
+
"(默认预演,apply 需 admin);权限按 action 分档:只读放行、prefeed "
|
|
602
|
+
"写入需 can_write、批量改写与 rollback 需 admin;dry-run 只出报表不改盘);"
|
|
603
|
+
"op=consolidate:离线固化(action=promote 提升 | induce 归纳 | "
|
|
604
|
+
"contextualize 语境化,及其 _rollback/_history;批量提升属管理操作,"
|
|
605
|
+
"一律 require_admin);"
|
|
606
|
+
"op=insight:洞察(action=window|record|verify|list|report|"
|
|
607
|
+
"reconstruct|learn|outlook|catalog|fork|branch_rewrite|branch_search|"
|
|
608
|
+
"branch_merge|branch_discard|branches|tickets;权限按 action 分档:只读放行、"
|
|
609
|
+
"条件记账与分支写需 can_write、落库 apply 与分支弃置需 admin);"
|
|
610
|
+
"op=ccg:CCG 六要素编译器(action=compile|review|attest|link|"
|
|
611
|
+
"recalibrate|units|catalog;入参统一在 ccg 对象里)。"
|
|
612
|
+
"把对话记录编译为六要素候选 → **编外复核**(裁定 A:编译者不得自证,"
|
|
613
|
+
"E041 机械拒绝)→ 落库;复核优先走蜂巢 reflect/verify 单元,"
|
|
614
|
+
"蜂巢不可用则提示配置,或显式 allow_degrade 降级 harness 端子代理。"
|
|
615
|
+
"op=status:**可验证记忆单元**读面(验证态 unverified|verified|"
|
|
616
|
+
"doubted|expired|rechecking + 依赖 depends_on + 双时间轴 valid_from/"
|
|
617
|
+
"valid_until + 履历台账);给 node_id 看单节点全貌、不给看全库摘要、"
|
|
618
|
+
"action=ledger 读台账。所有读面返回体统一带 status_head 状态头"
|
|
619
|
+
"(✓已验证 / △已修改 / !异常 / ?存疑),hint 亦升级为该格式"
|
|
620
|
+
"(MDCG_STATUS_HEAD=0 回退旧文本)。"
|
|
621
|
+
"op=edges:**三元组反查**读面(阶段二 4.2):按派生边任意端 / "
|
|
622
|
+
"谓词 / 时间反查「这条记忆从哪来、谁由它派生」——subject/predicate/"
|
|
623
|
+
"object ≡ child/relation/parent(`derived_from` 派生的三元组)。"
|
|
624
|
+
"支持排序(ordering=desc 按写入时刻新→旧,缺省/asc)、分页"
|
|
625
|
+
"(offset/limit)、**分页前全集**聚合(aggregation=by_relation|"
|
|
626
|
+
"by_parent|by_child)、端点索引摘要(expand_nodes=true)。"
|
|
627
|
+
"时间条件缺省走**观察轴**(派生边只有写入时刻 t,无效力声明)"
|
|
628
|
+
"——与 op=read 缺省效力轴**有意不同**,由库层单点校验。",
|
|
566
629
|
"inputSchema": _s("",
|
|
567
630
|
op=_p("string", "route|read|write|verify|review|protect|identity|"
|
|
568
631
|
"consistency|metacognition|self_state|evolution|sustain|"
|
|
569
632
|
"scrub|predict|causal|"
|
|
570
|
-
"forget|goal|recent|info|index_code|index_doc|ref|whitebox|"
|
|
633
|
+
"forget|goal|task|recent|info|index_code|index_doc|ref|whitebox|"
|
|
571
634
|
"theory|link|session|ingest|export|maintain|consolidate|"
|
|
572
|
-
"insight", True),
|
|
635
|
+
"insight|ccg|status|edges|help", True),
|
|
636
|
+
ccg=_p("object", "CCG 六要素编译器入参:{action, node_id, dialog, marks, "
|
|
637
|
+
"slots, strict_spans, role, verdict, verifier, compiled_by, "
|
|
638
|
+
"evidence, slot_corrections, model, jobs, blocking, wait_s, "
|
|
639
|
+
"allow_degrade, channel, autostart, doctor, apply, basis}"),
|
|
573
640
|
intent=_p("string", "route 的查询意图"), query=_p("string", "read 的查询"),
|
|
574
|
-
goal=_p("string", "goal op 的目标文本;read
|
|
641
|
+
goal=_p("string", "goal op 的目标文本;read 的定向目标(缺省用活跃目标);"
|
|
642
|
+
"task op:任务目标(CCG「执行」栏)"),
|
|
575
643
|
goal_status=_p("string", "goal op:active|done|dropped"),
|
|
576
644
|
priority=_p("number", "goal op:优先级 0-1(兼作定向偏置依据)"),
|
|
577
645
|
deadline=_p("string", "goal op:截止时间(仅排序用,不做硬约束)"),
|
|
@@ -583,10 +651,34 @@ KERNEL_TOOLS = [
|
|
|
583
651
|
meta=_p("object", "recent op:附加元数据"),
|
|
584
652
|
window=_p("integer", "recent op:滚动窗口大小(默认 200)"),
|
|
585
653
|
include_recent=_p("boolean", "read:是否附近期事件窗口(默认否)"),
|
|
586
|
-
limit=_p("integer", "goal/recent 的返回条数;read
|
|
654
|
+
limit=_p("integer", "goal/recent 的返回条数;read 的近期事件条数;"
|
|
655
|
+
"edges 分页条数(缺省 50、上限 500,0/负数报错不当「全部」)"),
|
|
587
656
|
node_id=_p("string", "节点 id"),
|
|
657
|
+
offset=_p("integer", "read 的续读起始行(1 基;传上次返回的 next_offset);"
|
|
658
|
+
"edges 的分页偏移(排序后切片,默认 0)"),
|
|
588
659
|
content=_p("string", "write 的内容(建议含 CCG 5 要素注释)"),
|
|
589
|
-
content_kind=_p("string", "write 的内容类型:code|image_desc|text|permission|work_done|work_wip"),
|
|
660
|
+
content_kind=_p("string", "write 的内容类型:code|image_desc|text|permission|work_done|work_wip|ccg_marks|hyperedge"),
|
|
661
|
+
depends_on=_p("array", "write/verify:本单元**依赖**的节点 id 列表(CCG「子功能」"
|
|
662
|
+
"的落字段,单值/逗号串亦可)。被依赖单元被修改或被证伪时,"
|
|
663
|
+
"本节点**同跳**标「存疑」(一跳同步;多跳走 maintain"
|
|
664
|
+
" action=propagate)。**何时需要它**:正文「# 子功能:」行"
|
|
665
|
+
"以 @<节点 id> 显式引用其它单元时(仅自述本单元内部构成"
|
|
666
|
+
"不算依赖,无需本字段)——显式引用却无可解析目标 → 硬拒"
|
|
667
|
+
"(E050 缺 depends_on / E051 目标悬空)"),
|
|
668
|
+
valid_from=_p("string", "双时间轴**起点**(ISO8601,如 2026-01-01):此刻起才成立"
|
|
669
|
+
"(未到点在 scrub 报 not_yet,仅提示不降权)"),
|
|
670
|
+
valid_until=_p("string", "双时间轴**终点**(ISO8601):此刻后不再成立"
|
|
671
|
+
"(过期在 scrub 报 expired,weaken/demote)"),
|
|
672
|
+
start_time=_p("string", "时间算子:查询窗起点(ISO8601/时间戳)。启用后 "
|
|
673
|
+
"read 按 time_axis 轴把候选收敛到窗内;edges 按边"
|
|
674
|
+
"写入时刻 t 收敛(**edges 缺省轴 observed**,与 read 不同)"),
|
|
675
|
+
end_time=_p("string", "时间算子:查询窗终点(缺省该侧=无界)"),
|
|
676
|
+
start_operator=_p("string", "时间算子:起点比较 gt|gte|eq|lte|lt"
|
|
677
|
+
"(两端都不给算子=区间重叠语义)"),
|
|
678
|
+
end_operator=_p("string", "时间算子:终点比较 gt|gte|eq|lte|lt"),
|
|
679
|
+
time_axis=_p("string", "时间算子轴:effective(效力轴,read 缺省)|"
|
|
680
|
+
"observed(观察轴 temporal/time_window;"
|
|
681
|
+
"**edges 的缺省轴**——派生边只有记录时刻,无效力声明)"),
|
|
590
682
|
layer=_p("string", "层:anchor|structural|knowledge|contextual|self"),
|
|
591
683
|
tags=_p("array", "标签(cap:xxx 会作为 route 的建议能力名)"),
|
|
592
684
|
importance=_p("number", "重要性 0-1"),
|
|
@@ -610,6 +702,11 @@ KERNEL_TOOLS = [
|
|
|
610
702
|
non_applicable_conditions=_p("array", "不适用条件"),
|
|
611
703
|
context=_p("object", "当前情境"),
|
|
612
704
|
k=_p("integer", "返回条数(sustain pool_bench 亦用)"),
|
|
705
|
+
view=_p("string", "read/route 的角色化读取视图(第四阶段 6.1,缺省关):"
|
|
706
|
+
"main(主代理:结论与修正历史)|"
|
|
707
|
+
"verifier(验证端:判据面与环境陷阱)|"
|
|
708
|
+
"receipt(回执审计:命令与预期输出);"
|
|
709
|
+
"非法值库层报错(fail-closed)"),
|
|
613
710
|
budget_tokens=_p("integer", "read 的 token 预算"),
|
|
614
711
|
evidence=_p("string", "verify 的证据"),
|
|
615
712
|
verdict=_p("string", "verify 裁决:confirmed|weakened|falsified;"
|
|
@@ -620,7 +717,7 @@ KERNEL_TOOLS = [
|
|
|
620
717
|
marker=_p("string", "whitebox verify_encoding:唯一口令标记(缺省自动生成)"),
|
|
621
718
|
fact=_p("string", "whitebox verify_encoding:待编码事实"),
|
|
622
719
|
questions=_p("array", "whitebox verify_existing:探针问题列表"),
|
|
623
|
-
action=_p("string", "review: list|decide|rounds;forget: forget|restore;"
|
|
720
|
+
action=_p("string", "review: list|decide|rounds|stats;forget: forget|restore;"
|
|
624
721
|
"protect: stats|check|mark|snapshot|history|forgetting;"
|
|
625
722
|
"identity: observe|anchor|trait|profile|positions|catalog;"
|
|
626
723
|
"consistency: check|history|stats|catalog;"
|
|
@@ -652,7 +749,15 @@ KERNEL_TOOLS = [
|
|
|
652
749
|
"promote_history|induce|contextualize|"
|
|
653
750
|
"contextualize_rollback|contextualize_history;"
|
|
654
751
|
"insight: window|record|verify|list|report|"
|
|
655
|
-
"reconstruct|learn|outlook|catalog"
|
|
752
|
+
"reconstruct|learn|outlook|catalog|"
|
|
753
|
+
"fork|branch_rewrite|branch_search|"
|
|
754
|
+
"branch_merge|branch_discard|branches|"
|
|
755
|
+
"tickets;"
|
|
756
|
+
"分支六 act:node_ids/branch_id/note/content/"
|
|
757
|
+
"reason 按 act 取用(rewrite 传 node_id+content);"
|
|
758
|
+
"tickets:盲区→四类消解票据任务卡"
|
|
759
|
+
"(types=[research|prototype|grilling|task],"
|
|
760
|
+
"min_blindspot 资格线;apply=True 落库需 admin)"),
|
|
656
761
|
pid=_p("string", "review decide 的提案 id"),
|
|
657
762
|
decision=_p("string", "review 裁决:accept|reject|edit|merge"),
|
|
658
763
|
edits=_p("object", "review edit 的覆盖字段(不可含 verify)"),
|
|
@@ -686,10 +791,15 @@ KERNEL_TOOLS = [
|
|
|
686
791
|
"路径命中私有提示时保守降为 private)"),
|
|
687
792
|
ref=_p("object", "ref op:直接给 code_ref/doc_ref 对象(与 node_id 二选一)"),
|
|
688
793
|
root=_p("string", "ref op:覆盖 ref 里记录的 root(索引结果的跨机器搬迁)"),
|
|
689
|
-
name=_p("string", "sustain:心跳名(默认 md_cg
|
|
794
|
+
name=_p("string", "sustain:心跳名(默认 md_cg);"
|
|
795
|
+
"task op:任务名(**身份判据**:同名即同任务,slug 归一后落 id)"),
|
|
690
796
|
session=_p("string", "read(search/recall 分支):会话归属过滤"
|
|
691
797
|
"(frontmatter.session;缺省不过滤);"
|
|
692
798
|
"sustain:会话 id(resume/note 用)"),
|
|
799
|
+
validity=_p("boolean", "read(search/recall 分支):时效过滤(显式启用,"
|
|
800
|
+
"缺省不过滤)——仅排除**已过期**(valid_until 已过)"
|
|
801
|
+
"节点;**未生效(valid_from 未到)保留**"
|
|
802
|
+
"(两者语义相反,预约/计划类记忆生效前仍可召回)"),
|
|
693
803
|
ts=_p("number", "sustain note:事件时间戳"),
|
|
694
804
|
seq=_p("integer", "sustain note:事件序号"),
|
|
695
805
|
task_running=_p("boolean", "sustain:任务执行中(心跳阈值放宽)"),
|
|
@@ -729,7 +839,8 @@ KERNEL_TOOLS = [
|
|
|
729
839
|
hit=_p("boolean", "predict feedback:是否命中(缺省按 predicted==actual)"),
|
|
730
840
|
rule=_p("string", "evolution record:规律(必填,一句话认知规律)"),
|
|
731
841
|
missing=_p("string", "evolution record:补的是哪一维缺失条件"),
|
|
732
|
-
change=_p("string", "evolution record
|
|
842
|
+
change=_p("string", "evolution record:这次具体改了什么;"
|
|
843
|
+
"task op:本轮计划变更/新增问题(追加进「计划变更」节,可追溯)"),
|
|
733
844
|
kind=_p("string", "evolution:condition_gap|layer_shift|general"),
|
|
734
845
|
entry_id=_p("string", "evolution show/rollback:条目 id"),
|
|
735
846
|
source=_p("string", "evolution record:来源 consolidate|verify|manual;"
|
|
@@ -768,14 +879,22 @@ KERNEL_TOOLS = [
|
|
|
768
879
|
verdicts=_p("array", "maintain refine apply:人工核对裁决 "
|
|
769
880
|
"[{concept_id, faithful, added_info, note}];"
|
|
770
881
|
"缺省只落抽检留痕(不改节点)"),
|
|
771
|
-
batch=_p("string", "maintain/consolidate
|
|
882
|
+
batch=_p("string", "maintain/consolidate:批次号(回滚用);"
|
|
883
|
+
"edges:按派生边批次号过滤"),
|
|
772
884
|
derived_from=_p("string", "write/remember:派生来源节点 id(G8,可用逗号/空格"
|
|
773
885
|
"分隔多个);声明后写入 frontmatter 并建派生边"),
|
|
774
|
-
relation=_p("string", "write/remember/link derive
|
|
886
|
+
relation=_p("string", "write/remember/link derive/edges:派生关系名(**谓词**),"
|
|
775
887
|
"默认 derived_from(split_from|extracted_from|"
|
|
776
888
|
"merged_from|refined_from|source)"),
|
|
777
|
-
child=_p("string", "link derive:按子节点 id 过滤派生边"
|
|
778
|
-
|
|
889
|
+
child=_p("string", "link derive/edges:按子节点 id 过滤派生边"
|
|
890
|
+
"(edges 中即三元组的**主体**)"),
|
|
891
|
+
parent=_p("string", "link derive/edges:按父节点 id 过滤派生边"
|
|
892
|
+
"(edges 中即三元组的**对象**)"),
|
|
893
|
+
ordering=_p("string", "edges:排序方向 desc(按写入时刻 新→旧,缺省)|asc"),
|
|
894
|
+
aggregation=_p("string", "edges:分页前全集分桶 by_relation|by_parent|"
|
|
895
|
+
"by_child(缺省不聚合)"),
|
|
896
|
+
expand_nodes=_p("boolean", "edges:是否附端点索引摘要 child_node/"
|
|
897
|
+
"parent_node(默认否;只读索引快照)"),
|
|
779
898
|
ledger_only=_p("boolean", "link derive_dangling:只看台账、忽略索引声明"),
|
|
780
899
|
pools=_p("object", "search/sustain pool_bench:召回分池表"
|
|
781
900
|
"{knowledge:{cap_ratio,weight},index:{…},"
|
|
@@ -810,21 +929,37 @@ KERNEL_TOOLS = [
|
|
|
810
929
|
neighbors=_p("boolean", "insight reconstruct:是否并入一跳邻域(默认 true)"),
|
|
811
930
|
recent_days=_p("integer", "insight outlook:近期窗口天数(默认 7)"),
|
|
812
931
|
sample_limit=_p("integer", "insight outlook:抽样清单条数(默认 8)"),
|
|
813
|
-
max_events=_p("integer", "ingest:单次最多摄取事件数")
|
|
932
|
+
max_events=_p("integer", "ingest:单次最多摄取事件数"),
|
|
933
|
+
task_status=_p("string", "task op:active|blocked|done|dropped;"
|
|
934
|
+
"迁 done 必须同时给 result(缺一不收)"),
|
|
935
|
+
plan=_p("string", "task op:分步计划(每轮覆盖更新,跨会话持久存在)"),
|
|
936
|
+
result=_p("string", "task op:任务结果(done 时必填;本次不传则**保留旧值**,"
|
|
937
|
+
"不会被静默清空)"),
|
|
938
|
+
acceptance=_p("string", "task op:验收判据(怎么算完成)"),
|
|
939
|
+
boundary=_p("string", "task op:不适用条件/边界"),
|
|
940
|
+
note=_p("string", "task op:本轮备注(change 是计划变更,note 是附注);"
|
|
941
|
+
"self_state relate:备注"),
|
|
942
|
+
condition=_p("string", "task op:生效条件(CCG「生效条件」栏);"
|
|
943
|
+
"self_state relate:关系成立条件"),
|
|
944
|
+
active_limit=_p("integer", "task action=session:进行中任务条数(默认 5)"),
|
|
945
|
+
done_limit=_p("integer", "task action=session:近期已完成条数(默认 5)")),
|
|
814
946
|
},
|
|
815
947
|
{
|
|
816
948
|
"name": "stg",
|
|
817
949
|
"description": "语义时空图接口:精确得到信息的时间/空间关系。"
|
|
818
950
|
"op=relation:两节点时空关系(Allen 时间 6 态 + RCC 空间 7 态);"
|
|
819
951
|
"op=timeline:按时间排序;op=anchors:落在时间窗/空间范围的节点;"
|
|
820
|
-
"op=consistency:时空字段自洽性检查。"
|
|
952
|
+
"op=consistency:时空字段自洽性检查。"
|
|
953
|
+
"四个 op 均可用 time_axis 切换时间轴(缺省 observed)。",
|
|
821
954
|
"inputSchema": _s("",
|
|
822
955
|
op=_p("string", "relation|timeline|anchors|consistency", True),
|
|
823
956
|
a=_p("string", "relation 的节点 a"), b=_p("string", "relation 的节点 b"),
|
|
824
957
|
time_window=_p("array", "anchors 的时间窗 [t1,t2]"),
|
|
825
958
|
bbox=_p("array", "anchors 的包围盒 [x1,y1,x2,y2]"),
|
|
826
959
|
layer=_p("string", "限定层"), limit=_p("integer", "返回条数"),
|
|
827
|
-
desc=_p("boolean", "timeline 是否倒序(默认是)")
|
|
960
|
+
desc=_p("boolean", "timeline 是否倒序(默认是)"),
|
|
961
|
+
time_axis=_p("string", "时间轴:observed(观察轴 temporal/time_window,"
|
|
962
|
+
"缺省)| effective(效力轴 effective_from/until)")),
|
|
828
963
|
},
|
|
829
964
|
]
|
|
830
965
|
|
|
@@ -832,19 +967,30 @@ ALL_TOOLS = KERNEL_TOOLS + TOOLS
|
|
|
832
967
|
SURFACE = os.environ.get("MDCG_MCP_SURFACE", "kernel").strip().lower()
|
|
833
968
|
|
|
834
969
|
|
|
970
|
+
# 生效条件:模块级 SURFACE 等于 "full" 时以 ALL_TOOLS、否则以 KERNEL_TOOLS 调 slim_tools 并返回其结果。
|
|
835
971
|
def tools_for_surface():
|
|
836
|
-
"""kernel:只暴露 2 个基元;full:2 个基元 + 31 个细粒度工具(兼容/调试)。
|
|
837
|
-
|
|
972
|
+
"""kernel:只暴露 2 个基元;full:2 个基元 + 31 个细粒度工具(兼容/调试)。
|
|
973
|
+
|
|
974
|
+
返回**投影后**的工具面(工具一行职责 + 参数短提示):完整语义由
|
|
975
|
+
``cg(op=help, query=…)`` 按需取回。真源 KERNEL_TOOLS/TOOLS 保持完整定义,
|
|
976
|
+
投影只是运行时视图(信息零丢失,见 md_cg/tool_face.py)。
|
|
977
|
+
关闭投影:``MDCG_TOOL_FACE=full``。
|
|
978
|
+
"""
|
|
979
|
+
tools = ALL_TOOLS if SURFACE == "full" else KERNEL_TOOLS
|
|
980
|
+
from .tool_face import slim_tools
|
|
981
|
+
return slim_tools(tools)
|
|
838
982
|
|
|
839
983
|
|
|
840
984
|
# --------------------------------------------------------------------------
|
|
841
985
|
# 序列化
|
|
842
986
|
# --------------------------------------------------------------------------
|
|
843
987
|
|
|
988
|
+
# 生效条件:始终返回 json.dumps(obj, ensure_ascii=False, default=str)。
|
|
844
989
|
def _j(obj) -> str:
|
|
845
990
|
return json.dumps(obj, ensure_ascii=False, default=str)
|
|
846
991
|
|
|
847
992
|
|
|
993
|
+
# 生效条件:path 以 ".zstd" 结尾时直接返回 DSHSessionSource(path);否则读首个非空行做 json.loads,该 dict 满足 o.get("type")=="session" 或同时含 "type"/"seq"/"data" 时返回 DSHSessionSource(path),能解析但不满足时返回 JsonlSource(path),json.loads 抛 ValueError 或 open/读抛 OSError 或无非空行时落到返回 JsonlSource(path)。
|
|
848
994
|
def _pick_source(path):
|
|
849
995
|
"""按内容嗅探源类型:DSH 会话格式 vs 通用 JSONL。"""
|
|
850
996
|
from .sources import DSHSessionSource, JsonlSource
|
|
@@ -866,17 +1012,80 @@ def _pick_source(path):
|
|
|
866
1012
|
return JsonlSource(path)
|
|
867
1013
|
|
|
868
1014
|
|
|
869
|
-
|
|
1015
|
+
READ_MAX_LINES = 2000 # 单次 read 返回行数上限(Pi⑦② 截断)
|
|
1016
|
+
READ_MAX_BYTES = 50 * 1024 # 单次 read 返回字节上限(Pi⑦② 截断)
|
|
1017
|
+
|
|
1018
|
+
|
|
1019
|
+
# 生效条件:text 先按 text or "" 归一,start 由 offset 定(offset 为假值取 0,否则 max(0,int(offset)-1));start≥total_lines 时返回空 text、next_offset=None 的窗口结果;否则从 start 起按 max_lines 行收集(max_lines=0 时 got 为空),且仅当已收集非空且 used+b>max_bytes 时提前 break(首行即便超 max_bytes 也收),end<total_lines 时 truncated=True、next_offset=end+1 并写续读 note。
|
|
1020
|
+
def _clip_text(text: str, *, offset: int = 0, max_lines: int = READ_MAX_LINES,
|
|
1021
|
+
max_bytes: int = READ_MAX_BYTES) -> dict:
|
|
1022
|
+
"""行窗口 + 双阈值截断(Pi⑦② 截断必带续读提示)。
|
|
1023
|
+
|
|
1024
|
+
offset 为 1 基起始行(续读传上次 next_offset)。不静默丢内容——截断时
|
|
1025
|
+
返回 total_lines / total_bytes / next_offset / note,调用方按 offset 续读。
|
|
1026
|
+
"""
|
|
1027
|
+
text = text or ""
|
|
1028
|
+
lines = text.split("\n")
|
|
1029
|
+
total_lines = len(lines)
|
|
1030
|
+
total_bytes = len(text.encode("utf-8"))
|
|
1031
|
+
start = max(0, int(offset) - 1) if offset else 0
|
|
1032
|
+
if start >= total_lines:
|
|
1033
|
+
return {"text": "", "offset": start + 1, "next_offset": None,
|
|
1034
|
+
"returned_lines": 0, "total_lines": total_lines,
|
|
1035
|
+
"total_bytes": total_bytes, "truncated": False,
|
|
1036
|
+
"note": f"offset={start + 1} 超出总行数 {total_lines},返回空"}
|
|
1037
|
+
got, used = [], 0
|
|
1038
|
+
for ln in lines[start:start + max_lines]:
|
|
1039
|
+
b = len(ln.encode("utf-8")) + 1
|
|
1040
|
+
if got and used + b > max_bytes:
|
|
1041
|
+
break
|
|
1042
|
+
got.append(ln)
|
|
1043
|
+
used += b
|
|
1044
|
+
end = start + len(got)
|
|
1045
|
+
truncated = end < total_lines
|
|
1046
|
+
out = {"text": "\n".join(got), "offset": start + 1,
|
|
1047
|
+
"next_offset": end + 1 if truncated else None,
|
|
1048
|
+
"returned_lines": len(got), "total_lines": total_lines,
|
|
1049
|
+
"total_bytes": total_bytes, "truncated": truncated, "note": ""}
|
|
1050
|
+
if truncated:
|
|
1051
|
+
out["note"] = (f"内容已截断(单次上限 {max_lines} 行 / {max_bytes} 字节):"
|
|
1052
|
+
f"共 {total_lines} 行 / {total_bytes} 字节,本次返回第 "
|
|
1053
|
+
f"{start + 1}–{end} 行;续读传 offset={end + 1}。")
|
|
1054
|
+
return out
|
|
1055
|
+
|
|
1056
|
+
|
|
1057
|
+
# 生效条件:node 为假值时返回 None;否则用 _clip_text(node.get("content") or "", offset=offset) 构造 {id,path,frontmatter,content},且当 clip["truncated"] 为真或 offset 为真值时追加 truncated/content_lines/content_bytes/offset/next_offset/note。
|
|
1058
|
+
def _trust_state(fm):
|
|
1059
|
+
"""节点验证态(缺字段按 unverified;导入失败不拖垮读面)。"""
|
|
1060
|
+
try:
|
|
1061
|
+
from . import trust
|
|
1062
|
+
return trust.state_of(fm)
|
|
1063
|
+
except Exception: # noqa: BLE001
|
|
1064
|
+
return None
|
|
1065
|
+
|
|
1066
|
+
|
|
1067
|
+
def _node_view(node, offset: int = 0):
|
|
870
1068
|
if not node:
|
|
871
1069
|
return None
|
|
872
|
-
|
|
873
|
-
|
|
1070
|
+
clip = _clip_text(node.get("content") or "", offset=offset)
|
|
1071
|
+
out = {"id": node.get("id"), "path": node.get("path"),
|
|
1072
|
+
"frontmatter": node.get("frontmatter"), "content": clip["text"],
|
|
1073
|
+
# 可验证记忆单元:读面 additive 透出验证态(**不改排序权重**,保基准)
|
|
1074
|
+
"verification_state": _trust_state(node.get("frontmatter"))}
|
|
1075
|
+
if clip["truncated"] or offset:
|
|
1076
|
+
out.update({"truncated": clip["truncated"],
|
|
1077
|
+
"content_lines": clip["total_lines"],
|
|
1078
|
+
"content_bytes": clip["total_bytes"],
|
|
1079
|
+
"offset": clip["offset"], "next_offset": clip["next_offset"],
|
|
1080
|
+
"note": clip["note"]})
|
|
1081
|
+
return out
|
|
874
1082
|
|
|
875
1083
|
|
|
876
1084
|
# --------------------------------------------------------------------------
|
|
877
1085
|
# 基元实现
|
|
878
1086
|
# --------------------------------------------------------------------------
|
|
879
1087
|
|
|
1088
|
+
# 生效条件:当 cg、a 传入时,按 a.get('action') or 'stats'(空串/None 回退 'stats')并 strip().lower() 分派:action=stats 返回 cg.protect_stats();action 为 forgetting 或 forgetting_history 返回 {'records': cg.forgetting_history(limit=int(a.get('limit') or 100))}(a.get('limit') 为 0/空串/None 时回落 100);action=check 时 node_id 取 a.get('node_id') or ''(空串/None 回落 ''),返回包含 node_id、exists(nid in (cg.index.get('nodes') or {}))、protected、reason、immutable、immutable_reason 的 dict;action=history 返回 {'node_id': nid, 'versions': protect.history(cg, nid)};action=snapshot 返回 {'node_id': nid, 'snapshot': protect.snapshot(cg, nid)};action 为 mark 或 protect 时若 cg.principal 非 None 则先调用 cg.principal.require_admin('protect_mark'),再返回 protect.mark(cg, nid, a.get('reason') or '显式保护标记')(reason 空串/None 回落 '显式保护标记');其他 action 抛 ValueError;
|
|
880
1089
|
def _protect_call(cg, a):
|
|
881
1090
|
"""写保护 / 遗忘留痕的统一入口(cg op=protect 与 mdcg_protect 共用)。"""
|
|
882
1091
|
from . import protect
|
|
@@ -904,6 +1113,7 @@ def _protect_call(cg, a):
|
|
|
904
1113
|
raise ValueError(f"protect 未知 action:{act}")
|
|
905
1114
|
|
|
906
1115
|
|
|
1116
|
+
# 生效条件:当 cg、a 传入时,按 a.get('action') or 'profile'(空串/None 回退 'profile')并 strip().lower() 分派,subject_id 取 a.get('subject_id') or ''(空串/None 回落 ''):action=catalog 返回 identity.catalog();action=positions 返回 {'positions': cg.identity_positions(limit=int(a.get('limit') or 0))}(a.get('limit') 假值回落 0);action=profile 时若 sid 为假值返回 {'subjects': cg.identity_positions(limit=0), 'hint': '指定 subject_id 可获取完整画像(锚点+位置+特征)'},否则返回 cg.identity_profile(sid);action=observe 时以 sid 和 a.get('content') or a.get('text') or '' 调用 cg.identity_observe(含 kind=a.get('subject_kind')、role=a.get('role')、layer=a.get('layer')、tags=a.get('tags')、condition_space=a.get('condition_space')、importance=float(a.get('importance', 0.5))、verification_basis=a.get('verification_basis')、evidence=a.get('evidence')、override=bool(a.get('override')));action=trait 时以 sid 和 a.get('trait') or a.get('content') or '' 调用 cg.identity_trait(含 condition_space=a.get('condition_space')、importance=float(a.get('importance', 0.6))、position=a.get('position')、kind=a.get('subject_kind')、verification_basis=a.get('verification_basis') or 'data'、override=bool(a.get('override')));action=anchor 时若 cg.principal 非 None 先调用 cg.principal.require_admin('identity_anchor'),再以 sid 和 a.get('content') or a.get('text') or '' 调用 cg.identity_anchor(含 kind=a.get('subject_kind')、condition_space=a.get('condition_space')、importance=float(a.get('importance', 0.9))、override=bool(a.get('override'))、requested_layer=a.get('requested_layer'));action=history 返回 {'records': cg.identity_history(limit=int(a.get('limit') or 100))}(a.get('limit') 假值回落 100);其他 action 抛 ValueError;
|
|
907
1117
|
def _identity_call(cg, a):
|
|
908
1118
|
"""身份特征识别统一入口(cg op=identity 与 mdcg_identity 共用)。
|
|
909
1119
|
|
|
@@ -954,6 +1164,7 @@ def _identity_call(cg, a):
|
|
|
954
1164
|
raise ValueError(f"identity 未知 action:{act}")
|
|
955
1165
|
|
|
956
1166
|
|
|
1167
|
+
# 生效条件:act=(a.get("action") or "check").strip().lower();"check" 时以 content/text、layer、condition_space、non_applicable_conditions、tags、exclude、limit=int(a.get("limit") or consistency.MAX_SCAN)、depth(非 None 时 int(depth),否则 consistency.MAX_DEPTH)、auto_flywheel 调 cg.check_consistency;"history" 返回 {"records": cg.consistency_history(limit=int(a.get("limit") or 100))};"stats" 返回 cg.consistency_stats();"catalog" 返回 consistency.catalog();其余 act 抛 ValueError。
|
|
957
1168
|
def _consistency_call(cg, a):
|
|
958
1169
|
"""节点间自动冲突检测统一入口(cg op=consistency 与 mdcg_consistency 共用)。
|
|
959
1170
|
|
|
@@ -982,6 +1193,7 @@ def _consistency_call(cg, a):
|
|
|
982
1193
|
raise ValueError(f"consistency 未知 action:{act}")
|
|
983
1194
|
|
|
984
1195
|
|
|
1196
|
+
# 生效条件:当 cg、a 传入时,按 a.get('action') or 'report'(空串/None 回退 'report')分派,window=int(a.get('window') or 50)(a.get('window') 假值回落 50):action=report 返回 cg.metacognition_report(window=window);action=trace 返回 cg.metacognition_trace(window=window);action=calibration 返回 cg.metacognition_calibration(max_scan=int(a.get('limit') or 2000))(a.get('limit') 假值回落 2000);action=blindspots 返回 cg.metacognition_blindspots(limit=int(a.get('limit') or 20), window=window)(a.get('limit') 假值回落 20);action=trust 返回 cg.metacognition_trust(window=window);action=self_check 返回 cg.self_check(a.get('query') or a.get('text') or '', k=int(a.get('k') or 5))(query/text 假值回落 '',k 假值回落 5);action=history 返回 cg.metacognition_history(limit=int(a.get('limit') or 100))(a.get('limit') 假值回落 100);action=catalog 返回 metacognition.catalog();action=d_meta 返回 cg.metacognition_d_meta(window=window)(边界压力向量,三代理各自 [0,1]、不合成单值);其他 action 抛 ValueError;
|
|
985
1197
|
def _metacognition_call(cg, a):
|
|
986
1198
|
"""独立元认知统一入口(cg op=metacognition 与 mdcg_metacognition 共用)。
|
|
987
1199
|
|
|
@@ -1011,9 +1223,12 @@ def _metacognition_call(cg, a):
|
|
|
1011
1223
|
if act == "catalog":
|
|
1012
1224
|
from . import metacognition
|
|
1013
1225
|
return metacognition.catalog()
|
|
1226
|
+
if act == "d_meta": # D_meta 观测面(只读,不合成单值)
|
|
1227
|
+
return cg.metacognition_d_meta(window=window)
|
|
1014
1228
|
raise ValueError(f"metacognition 未知 action:{act}")
|
|
1015
1229
|
|
|
1016
1230
|
|
|
1231
|
+
# 生效条件:当 cg、a 传入时,按 a.get('action') or 'snapshot'(空串/None 回退 'snapshot')分派,subject=a.get('subject') or self_state.DEFAULT_SUBJECT(subject 假值回落常量),session=a.get('session') or getattr(getattr(cg, 'principal', None), 'session', None)(session 假值回落 principal.session):action 为 snapshot/read/get 返回 {'state': self_state.snapshot(cg, subject)};action=refresh 返回 self_state.refresh(cg, subject, window=int(a.get('window') or self_state.RECENT_WINDOW), importance=a.get('importance'), important_refs=a.get('important_refs'), dimensions=a.get('dimensions'), links=a.get('links'), actor=a.get('actor') or getattr(cg, 'actor', 'self_state'), force=bool(a.get('force')), strict=bool(a.get('strict')), session=session)(window 假值回落 self_state.RECENT_WINDOW);action=bootstrap 返回 self_state.bootstrap(cg, subject, window=int(a.get('window') or self_state.RECENT_WINDOW), actor=a.get('actor') or 'bootstrap');action=relate 返回 self_state.relate(cg, a.get('frm') or subject, a.get('to') or '', relation_type=a.get('relation_type') or 'collaborator', strength=a.get('strength', 0.5), condition=a.get('condition') or '', note=a.get('note') or '', reciprocal=bool(a.get('reciprocal')), actor=a.get('actor') or getattr(cg, 'actor', 'self_state'));action=relations 返回 {'relations': self_state.relations(cg, subject=a.get('subject'), direction=(a.get('direction') or 'both'))};action=index 时 dim,value=a.get('dim'),a.get('value'),若 dim 假值且 session 真值则 dim='session' 且 value=value or session,返回 self_state.index(cg, dim, value, limit=int(a.get('limit') or 50), with_content=bool(a.get('with_content')))(limit 假值回落 50);action=dimensions 返回 self_state.dimensions(cg, subject);action=audit 返回 self_state.audit(cg, subject, window=int(a.get('window') or self_state.RECENT_WINDOW));action=history 返回 {'records': self_state.history(cg, limit=int(a.get('limit') or 100), subject=a.get('subject'))}(limit 假值回落 100);action=summary 返回 self_state.summary(cg, subject, session=session);action=catalog 返回 self_state.catalog();其他 action 抛 ValueError;
|
|
1017
1232
|
def _self_state_call(cg, a):
|
|
1018
1233
|
"""自我状态层统一入口(cg op=self_state 与 mdcg_self_state 共用)。
|
|
1019
1234
|
|
|
@@ -1075,6 +1290,7 @@ def _self_state_call(cg, a):
|
|
|
1075
1290
|
raise ValueError(f"self_state 未知 action:{act}")
|
|
1076
1291
|
|
|
1077
1292
|
|
|
1293
|
+
# 生效条件:act=(a.get("action") or "routes").strip().lower();act 属 routes/route/predict 时以 start_id=a.get("start_id") or a.get("node_id")、blindspot_id、horizon=int(a.get("horizon") or predict.HORIZON_DEFAULT)、max_branches=int(a.get("max_branches") or predict.MAX_BRANCHES_DEFAULT)、sort=a.get("sort") or "composite"、limit=int(a.get("limit") or 0)、semantic=bool(a.get("semantic", True)) 调 cg.predict_routes;act 属 feedback/rate 时调 cg.predict_feedback;act=="stats" 时调 cg.predict_stats(limit=int(a.get("limit") or 20));act=="catalog" 时返回 predict.catalog();其余 act 抛 ValueError。
|
|
1078
1294
|
def _predict_call(cg, a):
|
|
1079
1295
|
"""生成式预测统一入口(cg op=predict 与 mdcg_predict 共用)。
|
|
1080
1296
|
|
|
@@ -1108,6 +1324,7 @@ def _predict_call(cg, a):
|
|
|
1108
1324
|
raise ValueError(f"predict 未知 action:{act}")
|
|
1109
1325
|
|
|
1110
1326
|
|
|
1327
|
+
# 生效条件:当 cg、a 传入时,按 a.get('action') or 'path'(空串/None 回退 'path')分派,a_id=a.get('a') or a.get('a_id') or a.get('from') or ''(假值链回落 ''),b_id=a.get('b') or a.get('b_id') or a.get('to') or '':action 为 path/reach/reachable 返回 predict.causal_path(cg, a_id, b_id, max_depth=int(a.get('max_depth') or 5))(a.get('max_depth') 假值回落 5);action 为 gate/filter 返回 {'ok': True, 'admitted': predict.causal_gate(cg, a_id, b_id) 的 ok, 'reason': why, 'a': a_id, 'b': b_id, 'note': '语义邻近须能说清关系(因果链/共同父节点/偏好权重>0.5)'};action=chain 返回 cg.causal_chain(a.get('node_id') or a_id, relation_types=a.get('relation_types'), max_depth=int(a.get('max_depth') or chain.MAX_DEPTH_DEFAULT), direction=a.get('direction') or 'out', sort=a.get('sort') or 'strength');action=explain 返回 cg.explain_chain(a.get('node_id') or a_id);action=catalog 返回包含 module/types/chain_types_default/edge_weights/max_depth_default/note/gate/actions 的 dict(gate 取 predict.catalog()['decisions']['D-002']);其他 action 抛 ValueError;
|
|
1111
1328
|
def _causal_call(cg, a):
|
|
1112
1329
|
"""因果推理统一入口(cg op=causal 与 mdcg_causal 共用)。
|
|
1113
1330
|
|
|
@@ -1146,6 +1363,7 @@ def _causal_call(cg, a):
|
|
|
1146
1363
|
raise ValueError(f"causal 未知 action:{act}")
|
|
1147
1364
|
|
|
1148
1365
|
|
|
1366
|
+
# 生效条件:当 cg、a 传入时,按 a.get('action') or 'summary'(空串/None 回退 'summary')分派:action 为 record/add/log 返回 {'entry': cg.evolution_record(node_id=a.get('node_id'), pattern=a.get('rule') or a.get('pattern') or '', missing=a.get('missing') or '', action=a.get('change') or a.get('note') or '', evidence=a.get('evidence') or '', source=a.get('source') or '', kind=a.get('kind') or evolution.KIND_CONDITION_GAP)}(各字段假值回落);action 为 entries/list 返回 cg.evolution_entries(limit=int(a.get('limit') or 50), node_id=a.get('node_id'), kind=a.get('kind'))(a.get('limit') 假值回落 50);action 为 show/get 返回 cg.evolution_show(a.get('entry_id') or '');action=history 返回 cg.evolution_history(a.get('node_id') or '', limit=int(a.get('limit') or 50))(a.get('limit') 假值回落 50);action 为 patterns/regularities 返回 cg.evolution_patterns(limit=int(a.get('limit') or 10))(a.get('limit') 假值回落 10);action=summary 返回 cg.evolution_summary();action 为 rollback/revert/undo 时若 cg.principal 非 None 先调用 cg.principal.require_admin('evolution_rollback'),再返回 cg.evolution_rollback(a.get('entry_id') or '', dry_run=bool(a.get('dry_run')), note=a.get('note') or '');action=catalog 返回 evolution.catalog();其他 action 抛 ValueError;
|
|
1149
1367
|
def _evolution_call(cg, a):
|
|
1150
1368
|
"""演化账本统一入口(cg op=evolution 与 mdcg_evolution 共用)。
|
|
1151
1369
|
|
|
@@ -1188,6 +1406,7 @@ def _evolution_call(cg, a):
|
|
|
1188
1406
|
raise ValueError(f"evolution 未知 action:{act}")
|
|
1189
1407
|
|
|
1190
1408
|
|
|
1409
|
+
# 生效条件:value 为 None 时返回 [],value 为 list/tuple/set 时按其元素、其它类型按 str(value).replace(",", " ").split() 取项,再对每项 str(x).strip(),非空且未出现过才按序追加并返回去重列表。
|
|
1191
1410
|
def _split_ids(value):
|
|
1192
1411
|
"""把 'a,b c' / ['a','b'] / 'a' 统一成去空白的 id 列表(None → [])。
|
|
1193
1412
|
|
|
@@ -1208,6 +1427,7 @@ def _split_ids(value):
|
|
|
1208
1427
|
return out
|
|
1209
1428
|
|
|
1210
1429
|
|
|
1430
|
+
# 生效条件:始终构造 ex(verify=a.get("verify")、importance=float(a["importance"]) 当 a.get("importance") is not None 否则 None、verification_basis=a.get("verification_basis") or (verdict or {}).get("basis")、non_applicable_conditions、role、derived_from=_split_ids(a.get("derived_from")) or None、relation),返回其中值不属于 (None, [], '', {}) 的键值对。
|
|
1211
1431
|
def _proposal_extras(a, verdict=None):
|
|
1212
1432
|
"""入队时保全 write 的落盘要素,避免裁决 accept 后退化成默认值。
|
|
1213
1433
|
|
|
@@ -1235,6 +1455,7 @@ def _proposal_extras(a, verdict=None):
|
|
|
1235
1455
|
return {k: v for k, v in ex.items() if v not in (None, [], "", {})}
|
|
1236
1456
|
|
|
1237
1457
|
|
|
1458
|
+
# 生效条件:act 取 a.get("action") 转 str 去空白并 lower 后缺省 "status",name 取 a.get("name") 或环境变量 MDCG_SUSTAIN_NAME 或 "md_cg";status/info 只读诊断,自愈类 act 只回收派生物(索引重扫、临时分片、日志轮转、心跳戳),永不删除节点、不代签密钥;
|
|
1238
1459
|
def _sustain_call(cg, a):
|
|
1239
1460
|
"""持续性自维持统一入口(常驻 / 心跳 / 自愈 / 会话续接)。
|
|
1240
1461
|
|
|
@@ -1343,6 +1564,7 @@ def _sustain_call(cg, a):
|
|
|
1343
1564
|
raise ValueError(f"sustain 未知 action:{act}")
|
|
1344
1565
|
|
|
1345
1566
|
|
|
1567
|
+
# 生效条件:当 cg、a 传入时,按 a.get('action') or 'sweep'(空串/None 回退 'sweep')分派,ids/kinds 若为字符串则按逗号或空白拆成列表,node_id=a.get('node_id') or a.get('node'),target=ids or ([node_id] if node_id else None)(ids 假值回落 node_id 列表或 None):action 为 sample/spot_check 返回 scrub.sample(cg, int(a.get('k') or a.get('n') or scrub.DEFAULT_SAMPLE), strategy=a.get('strategy') or 'stratified', seed=a.get('seed'))(k/n 假值链回落 scrub.DEFAULT_SAMPLE);action 为 associate/related 时若 node_id 假值抛 ValueError,否则返回 scrub.associate(cg, node_id, hops=int(a.get('hops') or scrub.DEFAULT_HOPS), limit=int(a.get('k') or 30), lexical=bool(a.get('lexical', True)))(hops 假值回落常量,k 假值回落 30,lexical 缺键为 True);action 为 audit/check 返回 scrub.audit(cg, target, hops=int(a.get('hops') or 1), min_severity=a.get('min_severity') or 'info');action 为 decontaminate/repair 返回 scrub.decontaminate(cg, target, kinds=kinds, dry_run=bool(a.get('dry_run', True)), min_severity=a.get('min_severity') or 'medium', hops=int(a.get('hops') or 1), actor=a.get('actor'), override=bool(a.get('override')));action 为 calibrate/calibration 返回 scrub.calibrate(cg, apply=bool(a.get('apply')), override=bool(a.get('override')), actor=a.get('actor'));action 为 sweep/run 返回 scrub.sweep(cg, n=int(a.get('k') or a.get('n') or scrub.DEFAULT_SAMPLE), seed=a.get('seed'), dry_run=bool(a.get('dry_run', True)), hops=int(a.get('hops') or scrub.DEFAULT_HOPS), strategy=a.get('strategy') or 'stratified', apply_calibration=bool(a.get('apply')), actor=a.get('actor'));action 为 history/log 返回 scrub.history(cg, limit=int(a.get('k') or 100))(k 假值回落 100);action=summary 返回 scrub.summary(cg);action=catalog 返回 scrub.catalog();其他 action 抛 ValueError;
|
|
1346
1568
|
def _scrub_call(cg, a):
|
|
1347
1569
|
"""记忆自净统一入口(抽查 / 联想 / 去污染 / 校准偏差)。
|
|
1348
1570
|
|
|
@@ -1400,8 +1622,77 @@ def _scrub_call(cg, a):
|
|
|
1400
1622
|
raise ValueError(f"scrub 未知 action:{act}")
|
|
1401
1623
|
|
|
1402
1624
|
|
|
1625
|
+
# ---- action 缺省防呆(2026-09-16)------------------------------------------
|
|
1626
|
+
# 与「op 缺省静默降级」同构的第二类静默失败:op 传了、action 漏了 → 各分支按
|
|
1627
|
+
# 字面量默认 action 执行。若默认恰是**读类**,写意图会被静默吞掉且返回形似正常
|
|
1628
|
+
# 的结果——最典型是文档化契约 `cg(op=review, pid, decision, reason)`(不带
|
|
1629
|
+
# action)实际静默走 review_list,裁决从未落盘(契约与实现漂移)。
|
|
1630
|
+
# 处置:签名明确指向非默认 action → 按签名推导并透出 action_derived/hint_action;
|
|
1631
|
+
# 无签名可依 → 维持默认执行但同样透出标记,让「按默认走」可见而非静默。
|
|
1632
|
+
# 判据用「键存在且非 None」(False / 0 / "" 属显式传入),避免真值判断误吞。
|
|
1633
|
+
_ACTION_SIGS = {
|
|
1634
|
+
"review": (("decision", "decide"), ("node_id", "verify_record")),
|
|
1635
|
+
"recent": (("text", "add"), ("content", "add")),
|
|
1636
|
+
"goal": (("goal", "add"), ("action_hint", "add")),
|
|
1637
|
+
# task:**写意图优先、读意图最后**。name→open 先命中——open(upsert)本身
|
|
1638
|
+
# 兼容 plan/result/change 全字段,故「name+change」同传也不会丢信息;把
|
|
1639
|
+
# change→plan_add 放其后,只在「只给 change」时才是纯追加变更。node_id→get
|
|
1640
|
+
# 置于末位:否则「node_id+change」会被静默当成只读(写意图被吞,
|
|
1641
|
+
# 与 review 的 `pid+decision` 静默走 list 同构)。
|
|
1642
|
+
"task": (("name", "open"), ("task_status", "status"),
|
|
1643
|
+
("result", "status"), ("change", "plan_add"),
|
|
1644
|
+
("node_id", "get")),
|
|
1645
|
+
"predict": (("hit", "feedback"), ("predicted_node_id", "feedback"),
|
|
1646
|
+
("actual_node_id", "feedback")),
|
|
1647
|
+
"session": (("summary", "note"), ("text", "note"), ("content", "note")),
|
|
1648
|
+
"insight": (("statement", "record"),),
|
|
1649
|
+
"whitebox": (("questions", "verify_existing"), ("question", "ask"),
|
|
1650
|
+
("message", "ask"), ("query", "ask"),
|
|
1651
|
+
("marker", "verify_encoding"),
|
|
1652
|
+
("content", "remember"), ("text", "remember")),
|
|
1653
|
+
}
|
|
1654
|
+
|
|
1655
|
+
# op → 分支内缺省 action 字面量。**仅供缺省透出提示,不参与执行**;与各
|
|
1656
|
+
# _xxx_call / 分支里的 `a.get("action") or "<默认>"` 保持同步(同源守卫见
|
|
1657
|
+
# test_action_derive.py)。
|
|
1658
|
+
_ACTION_DEFAULT = {
|
|
1659
|
+
"theory": "check", "link": "ls", "scrub": "sweep", "forget": "forget",
|
|
1660
|
+
"protect": "stats", "identity": "profile", "consistency": "check",
|
|
1661
|
+
"metacognition": "report", "self_state": "snapshot", "predict": "routes",
|
|
1662
|
+
"causal": "path", "evolution": "summary", "sustain": "status",
|
|
1663
|
+
"goal": "list", "task": "list", "recent": "list", "review": "list", "session": "recall",
|
|
1664
|
+
"ingest": "stat", "export": "stat", "maintain": "stat",
|
|
1665
|
+
"consolidate": "promote", "insight": "outlook",
|
|
1666
|
+
"ccg": "compile", "ref": "read", "whitebox": "ping",
|
|
1667
|
+
}
|
|
1668
|
+
|
|
1669
|
+
|
|
1670
|
+
# 生效条件:op == "ingest" 时若 str(a.get("path") or "").strip() 非空,则按 a.get("patterns") 为真值→("dir","patterns")、该 path 小写以 ".jsonl" 结尾→("jsonl","path(*.jsonl)")、否则→("file","path");其他 op 按常量 _ACTION_SIGS.get(op, ()) 的顺序取第一个 key 存在于 a 且 a.get(key) is not None 的项返回 (act, key),无匹配则返回 (None, None);
|
|
1671
|
+
def _action_sig(a, op):
|
|
1672
|
+
"""action 缺省时的签名推导 → (action, 依据键);无签名可依 → (None, None)。
|
|
1673
|
+
|
|
1674
|
+
`ingest` 单独处理:其 op 语义是**写**(摄入),缺省 action 却是**读**(stat)
|
|
1675
|
+
——「传了 path 却静默 stat」会把摄入整件事吞掉。类型按**保守优先**推导:
|
|
1676
|
+
patterns→dir、`*.jsonl`→jsonl、其余 path→file(file 最保守:若实为目录会
|
|
1677
|
+
报错可见,而不会误把整棵目录树摄进来)。
|
|
1678
|
+
"""
|
|
1679
|
+
if op == "ingest":
|
|
1680
|
+
path = str(a.get("path") or "").strip()
|
|
1681
|
+
if path:
|
|
1682
|
+
if a.get("patterns"):
|
|
1683
|
+
return "dir", "patterns"
|
|
1684
|
+
if path.lower().endswith(".jsonl"):
|
|
1685
|
+
return "jsonl", "path(*.jsonl)"
|
|
1686
|
+
return "file", "path"
|
|
1687
|
+
for key, act in _ACTION_SIGS.get(op, ()):
|
|
1688
|
+
if key in a and a.get(key) is not None:
|
|
1689
|
+
return act, key
|
|
1690
|
+
return None, None
|
|
1691
|
+
|
|
1692
|
+
|
|
1693
|
+
# 生效条件:op0=(a.get("op") or "").strip().lower(),op0 为空时按 a.get("content")→"write"、a.get("query") 或 a.get("node_id")→"read"、a.get("intent")→"route"、都无→"read" 推导 op;act0=(args.get("action") or "").strip().lower(),act0 为空时用 _action_sig(args, op) 推导且推导出时写回 args["action"];args["op"]=op 后调 _cg_dispatch,返回 dict 且 op0 为空时补 out["op"]、out["op_derived"]=True 与 hint,act0 为空且 (act_derived 或 op in _ACTION_DEFAULT) 时 setdefault("action", eff)、out["action_derived"]=True 并按是否有 act_derived 写 hint_action。
|
|
1403
1694
|
def _cg_call(cg, a):
|
|
1404
|
-
"""认知图唯一入口(外层:op 缺省推导兜底 +
|
|
1695
|
+
"""认知图唯一入口(外层:op/action 缺省推导兜底 + 推导透出;主体见 _cg_dispatch)。"""
|
|
1405
1696
|
op0 = (a.get("op") or "").strip().lower()
|
|
1406
1697
|
op = op0
|
|
1407
1698
|
if not op:
|
|
@@ -1416,23 +1707,222 @@ def _cg_call(cg, a):
|
|
|
1416
1707
|
else:
|
|
1417
1708
|
op = "read" # 无任何签名可依:维持旧缺省 read
|
|
1418
1709
|
args = dict(a)
|
|
1710
|
+
act0 = (args.get("action") or "").strip().lower()
|
|
1711
|
+
act_sig = act_derived = None
|
|
1712
|
+
if not act0:
|
|
1713
|
+
act_derived, act_sig = _action_sig(args, op)
|
|
1714
|
+
if act_derived:
|
|
1715
|
+
args["action"] = act_derived # 按签名补 action:避免写意图被默认吞掉
|
|
1419
1716
|
args["op"] = op
|
|
1420
1717
|
out = _cg_dispatch(cg, args)
|
|
1421
|
-
if isinstance(out, dict)
|
|
1422
|
-
|
|
1423
|
-
|
|
1424
|
-
|
|
1425
|
-
|
|
1718
|
+
if isinstance(out, dict):
|
|
1719
|
+
if not op0:
|
|
1720
|
+
out["op"] = op
|
|
1721
|
+
out["op_derived"] = True
|
|
1722
|
+
out["hint"] = ("op 未显式传入,已按参数签名推导(本次按 %s 执行);op 为必填参数,"
|
|
1723
|
+
"复杂任务中也请始终显式传 op,避免静默执行错误意图" % op)
|
|
1724
|
+
if not act0 and (act_derived or op in _ACTION_DEFAULT):
|
|
1725
|
+
eff = act_derived or _ACTION_DEFAULT[op]
|
|
1726
|
+
out.setdefault("action", eff)
|
|
1727
|
+
out["action_derived"] = True
|
|
1728
|
+
if act_derived:
|
|
1729
|
+
out["hint_action"] = (
|
|
1730
|
+
"action 未显式传入,已按参数 %s 推导为 action=%s(旧行为会静默走默认 %s,"
|
|
1731
|
+
"意图被吞);建议显式传 action" % (act_sig, act_derived,
|
|
1732
|
+
_ACTION_DEFAULT.get(op, "?")))
|
|
1733
|
+
else:
|
|
1734
|
+
out["hint_action"] = (
|
|
1735
|
+
"action 未显式传入,本次按 %s 的默认 action=%s 执行;"
|
|
1736
|
+
"若意图是其它 action 请显式传 action" % (op, eff))
|
|
1737
|
+
# 状态摘要协议(**单出口挂载**,控制爆炸半径——不逐 op 改造):
|
|
1738
|
+
# 把「它还成不成立」(验证态/存疑/异常/时效)以状态头透出,并把既有
|
|
1739
|
+
# hint 升级为状态头格式(MDCG_STATUS_HEAD=0 回退旧文本)。挂载失败不阻断读面。
|
|
1740
|
+
try:
|
|
1741
|
+
from . import statushdr
|
|
1742
|
+
statushdr.annotate(cg, out)
|
|
1743
|
+
except Exception as exc: # noqa: BLE001
|
|
1744
|
+
out.setdefault("status_head_error", type(exc).__name__)
|
|
1426
1745
|
return out
|
|
1427
1746
|
|
|
1428
1747
|
|
|
1748
|
+
def _status_call(cg, a):
|
|
1749
|
+
"""验证态 / 依赖 / 双时间轴 / 履历查询(op=status,**只读**)。
|
|
1750
|
+
|
|
1751
|
+
真源 `md_cg/trust.py`。三形态(`cg(op="status")` 取摘要,`node_id=` 取单节点):
|
|
1752
|
+
· 给 `node_id` → 单节点全貌(describe + 履历 + 状态头渲染);
|
|
1753
|
+
· 不给 / patrol → 全库摘要(存疑 / 过期 / 未生效 / 悬空四类计数);
|
|
1754
|
+
· `action=ledger` → 读验证态台账(`_trust.jsonl`,可按节点过滤)。
|
|
1755
|
+
"""
|
|
1756
|
+
from . import statushdr, trust
|
|
1757
|
+
nid = str(a.get("node_id") or a.get("id") or "").strip()
|
|
1758
|
+
act = str(a.get("action") or "").strip().lower()
|
|
1759
|
+
limit = int(a.get("limit") or 20)
|
|
1760
|
+
if act in ("ledger", "log"):
|
|
1761
|
+
rows = trust.load_ledger(cg, node_id=nid or None, limit=limit)
|
|
1762
|
+
return {"op": "status", "action": "ledger", "node_id": nid or None,
|
|
1763
|
+
"count": len(rows), "rows": rows, "readonly": True}
|
|
1764
|
+
if nid and act not in ("patrol", "summary"):
|
|
1765
|
+
de = trust.describe(cg, nid)
|
|
1766
|
+
de.update({"op": "status", "action": "describe", "readonly": True,
|
|
1767
|
+
"status_head": statushdr.render(cg, nid),
|
|
1768
|
+
"ledger": trust.load_ledger(cg, node_id=nid, limit=limit)})
|
|
1769
|
+
return de
|
|
1770
|
+
rep = trust.patrol(cg, limit=limit)
|
|
1771
|
+
rep.update({"op": "status", "action": act or "summary",
|
|
1772
|
+
"summary": trust.summary(cg), "catalog": trust.catalog(cg.root)})
|
|
1773
|
+
# 摘要形态主动挂全库级状态头(annotate 的 _collect_ids 找不到 node_id 不会自动注入)
|
|
1774
|
+
s = rep.get("summary") or {}
|
|
1775
|
+
bits = []
|
|
1776
|
+
dc = s.get("doubted", 0)
|
|
1777
|
+
ec = s.get("expired", 0)
|
|
1778
|
+
nc = s.get("not_yet", 0)
|
|
1779
|
+
uc = s.get("unverified", 0)
|
|
1780
|
+
vc = s.get("verified", 0)
|
|
1781
|
+
if ec:
|
|
1782
|
+
bits.append(f"{statushdr.MARK_ABNORMAL} 异常({ec})")
|
|
1783
|
+
if dc:
|
|
1784
|
+
bits.append(f"{statushdr.MARK_DOUBTED} 存疑({dc})")
|
|
1785
|
+
if nc:
|
|
1786
|
+
bits.append(f"{statushdr.MARK_MODIFIED} 未生效({nc})")
|
|
1787
|
+
if vc:
|
|
1788
|
+
bits.append(f"{statushdr.MARK_VERIFIED} 已验证({vc})")
|
|
1789
|
+
if uc:
|
|
1790
|
+
bits.append(f"{statushdr.MARK_UNVERIFIED} 未验证({uc})")
|
|
1791
|
+
rep["status_head"] = " · ".join(bits) if bits else statushdr.MARK_UNVERIFIED + " 空"
|
|
1792
|
+
# 冷路径队列状态(2026-09-19 热温冷分层)
|
|
1793
|
+
try:
|
|
1794
|
+
from . import coldverify as _cv
|
|
1795
|
+
q = _cv.get(cg)
|
|
1796
|
+
if q is not None:
|
|
1797
|
+
rep["coldverify"] = q.status()
|
|
1798
|
+
except Exception: # noqa: BLE001
|
|
1799
|
+
pass
|
|
1800
|
+
return rep
|
|
1801
|
+
|
|
1802
|
+
|
|
1803
|
+
# 生效条件:a 的 child/parent/relation/batch/时间五参/ordering/aggregation/offset/limit/expand_nodes 原样透传给 provenance.find_edges(本层不校验、不填默认,合法性单点在库层);始终返回该只读结果字典(含 edges/total/matched/returned/aggregates/time_filter 审计块)。
|
|
1804
|
+
def _edges_call(cg, a):
|
|
1805
|
+
"""三元组反查(op=edges,**只读**):按任意端 / 谓词 / 时间反查派生边。
|
|
1806
|
+
|
|
1807
|
+
三元组术语 `subject / predicate / object` 在本层就是 `child / rel / parent`
|
|
1808
|
+
(即 `derived_from` 派生边)——**不新造第二套参数**:`cg` 工具面是扁平
|
|
1809
|
+
schema,`subject` 已被 `identity`(主体语义)占用,同名异义会把两处口径搅在
|
|
1810
|
+
一起;且 `relation`/`child`/`parent`/`batch` 已是 `link derive` 的既有谓词面。
|
|
1811
|
+
|
|
1812
|
+
参数**原样透传、不填默认、不做二次校验**,与 `_read_call` 同一策略:
|
|
1813
|
+
合法性判定单点在库层(`provenance._ordering_of/_aggregation_of` 与
|
|
1814
|
+
`trust.check_time_args`)。本层若自补默认,缺省轴(边 = `observed`,检索 =
|
|
1815
|
+
`effective`)与枚举集就会两处分叉,日后必然漂移。
|
|
1816
|
+
|
|
1817
|
+
不暴露 `path`(库层测试用注入点):MCP 面不接受文件系统路径。
|
|
1818
|
+
"""
|
|
1819
|
+
from . import provenance as _pv
|
|
1820
|
+
return _pv.find_edges(
|
|
1821
|
+
cg,
|
|
1822
|
+
child=a.get("child"), parent=a.get("parent"),
|
|
1823
|
+
relation=a.get("relation"), batch=a.get("batch"),
|
|
1824
|
+
start_time=a.get("start_time"), end_time=a.get("end_time"),
|
|
1825
|
+
start_operator=a.get("start_operator"), end_operator=a.get("end_operator"),
|
|
1826
|
+
time_axis=a.get("time_axis"),
|
|
1827
|
+
ordering=a.get("ordering"), offset=a.get("offset") or 0,
|
|
1828
|
+
limit=a.get("limit"), aggregation=a.get("aggregation"),
|
|
1829
|
+
expand_nodes=bool(a.get("expand_nodes")))
|
|
1830
|
+
|
|
1831
|
+
|
|
1832
|
+
# 生效条件:始终调 help_text(ALL_TOOLS, query=a.get("query") or a.get("intent"), limit=int(a.get("limit") or a.get("k") or 40)) 并返回其结果。
|
|
1833
|
+
def _help_call(cg, a):
|
|
1834
|
+
"""按需披露入口(工具面渐进披露的读取面,见 md_cg/tool_face.py)。
|
|
1835
|
+
|
|
1836
|
+
常驻上下文只留「一行职责 + 参数短提示」;被投影掉的完整 op/参数语义
|
|
1837
|
+
在此从真源无损取回——所以瘦身不损失能力,只把「随时付费」换成「按需取」。
|
|
1838
|
+
只读元信息(工具 schema 本身对客户端可见),故不过角色权限闸。
|
|
1839
|
+
"""
|
|
1840
|
+
from .tool_face import help_text
|
|
1841
|
+
return help_text(ALL_TOOLS, query=a.get("query") or a.get("intent"),
|
|
1842
|
+
limit=int(a.get("limit") or a.get("k") or 40))
|
|
1843
|
+
|
|
1844
|
+
|
|
1845
|
+
# 生效条件:当 cg、a 传入时,act=(a.get('action') or '').strip().lower()(空串/None 得空串),若 act 空则 act=_action_sig(a, 'task')[0] or 'list',name=a.get('name') or a.get('task_name') or a.get('task') or '',nid=a.get('node_id') or a.get('task_id') or '',tstat=a.get('task_status') or a.get('new_status') or ''(各假值链回落 ''):act 为 open/add/upsert 时 importance 取 a.get('importance'),非 None 则 float、转换失败置 None,返回 _t.upsert(cg, name or nid, plan=a.get('plan'), status=tstat or None, result=a.get('result'), condition=a.get('condition'), goal=a.get('goal_text') or a.get('goal'), acceptance=a.get('acceptance'), boundary=a.get('boundary'), change=a.get('change'), note=a.get('note'), tags=a.get('tags'), importance=imp, actor=a.get('actor'));act 为 status/set_status 时若 tstat 假值返回 {'ok': False, 'error': '缺 task_status', 'hint': '可选 active|blocked|done|dropped;迁 done 必须同时给 result'},否则返回 _t.set_status(cg, nid or name, tstat, result=a.get('result'), note=a.get('note'), actor=a.get('actor'));act=plan_add 返回 _t.plan_add(cg, nid or name, a.get('change') or a.get('text'), actor=a.get('actor'));act=get 返回 _t.get_task(cg, nid or name);act=find 返回 _t.find_similar(cg, name, k=int(a.get('k') or a.get('limit') or 5))(k/limit 假值链回落 5);act=session 返回 _t.session_tasks(cg, active_limit=int(a.get('active_limit') or 5), done_limit=int(a.get('done_limit') or 5))(各假值回落 5);act 非 list 时返回 {'ok': False, 'error': '未知 task action:%r' % act, 'hint': '可选 open|status|plan_add|get|list|find|session'};act=list 返回 _t.list_tasks(cg, status=tstat or None, limit=a.get('limit'));
|
|
1846
|
+
def _task_call(cg, a):
|
|
1847
|
+
"""结构层任务实体(op=task)——跨会话的工程台账。
|
|
1848
|
+
|
|
1849
|
+
action:
|
|
1850
|
+
open / add 登记或更新任务卡(**同名即同卡**;未给字段沿用旧值,不静默清空)
|
|
1851
|
+
status 状态迁移(active|blocked|done|dropped;迁 done 时「结果」必填)
|
|
1852
|
+
plan_add 追加计划变更(执行中发现的偏差与新问题)
|
|
1853
|
+
get 单卡全字段读回
|
|
1854
|
+
list 任务清单(默认;可按 task_status 过滤)
|
|
1855
|
+
find 同族任务提示(**只提示,不自动合并**)
|
|
1856
|
+
session 会话装配面(进行中 + 近期完成)——供上下文召回
|
|
1857
|
+
|
|
1858
|
+
:param name: 任务名(身份判据:同名即同任务,slug 归一后落节点 id)
|
|
1859
|
+
"""
|
|
1860
|
+
from . import tasks as _t
|
|
1861
|
+
act = (a.get("action") or "").strip().lower()
|
|
1862
|
+
if not act:
|
|
1863
|
+
act = _action_sig(a, "task")[0] or "list"
|
|
1864
|
+
name = a.get("name") or a.get("task_name") or a.get("task") or ""
|
|
1865
|
+
nid = a.get("node_id") or a.get("task_id") or ""
|
|
1866
|
+
tstat = a.get("task_status") or a.get("new_status") or ""
|
|
1867
|
+
|
|
1868
|
+
if act in ("open", "add", "upsert"):
|
|
1869
|
+
imp = a.get("importance")
|
|
1870
|
+
try:
|
|
1871
|
+
imp = float(imp) if imp is not None else None
|
|
1872
|
+
except (TypeError, ValueError):
|
|
1873
|
+
imp = None
|
|
1874
|
+
return _t.upsert(cg, name or nid,
|
|
1875
|
+
plan=a.get("plan"), status=tstat or None,
|
|
1876
|
+
result=a.get("result"), condition=a.get("condition"),
|
|
1877
|
+
goal=a.get("goal_text") or a.get("goal"),
|
|
1878
|
+
acceptance=a.get("acceptance"), boundary=a.get("boundary"),
|
|
1879
|
+
change=a.get("change"), note=a.get("note"),
|
|
1880
|
+
tags=a.get("tags"), importance=imp, actor=a.get("actor"))
|
|
1881
|
+
|
|
1882
|
+
if act in ("status", "set_status"):
|
|
1883
|
+
if not tstat:
|
|
1884
|
+
return {"ok": False, "error": "缺 task_status",
|
|
1885
|
+
"hint": "可选 active|blocked|done|dropped;迁 done 必须同时给 result"}
|
|
1886
|
+
return _t.set_status(cg, nid or name, tstat, result=a.get("result"),
|
|
1887
|
+
note=a.get("note"), actor=a.get("actor"))
|
|
1888
|
+
|
|
1889
|
+
if act == "plan_add":
|
|
1890
|
+
return _t.plan_add(cg, nid or name, a.get("change") or a.get("text"),
|
|
1891
|
+
actor=a.get("actor"))
|
|
1892
|
+
|
|
1893
|
+
if act == "get":
|
|
1894
|
+
return _t.get_task(cg, nid or name)
|
|
1895
|
+
|
|
1896
|
+
if act == "find":
|
|
1897
|
+
return _t.find_similar(cg, name, k=int(a.get("k") or a.get("limit") or 5))
|
|
1898
|
+
|
|
1899
|
+
if act == "session":
|
|
1900
|
+
return _t.session_tasks(cg, active_limit=int(a.get("active_limit") or 5),
|
|
1901
|
+
done_limit=int(a.get("done_limit") or 5))
|
|
1902
|
+
|
|
1903
|
+
if act != "list":
|
|
1904
|
+
return {"ok": False, "error": "未知 task action:%r" % act,
|
|
1905
|
+
"hint": "可选 open|status|plan_add|get|list|find|session"}
|
|
1906
|
+
|
|
1907
|
+
return _t.list_tasks(cg, status=tstat or None, limit=a.get("limit"))
|
|
1908
|
+
|
|
1909
|
+
|
|
1910
|
+
# 生效条件:op 取 a.get("op") 转 str 去空白并 lower;缺失时按参数签名回推(含 content→write / query|node_id→read / intent→route;无签名可推时维持 read),op=="help" 在角色闸门之前直通 _help_call;其余 op 先经 cg.principal.require_op(op)(越权即 AccessDenied)再按 alias→内联名→cli 表分派;未识别 op 抛 ValueError;
|
|
1429
1911
|
def _cg_dispatch(cg, a):
|
|
1430
1912
|
"""认知图唯一入口的 op 分发主体。"""
|
|
1431
1913
|
op = (a.get("op") or "read").strip().lower()
|
|
1914
|
+
if op == "help":
|
|
1915
|
+
return _help_call(cg, a)
|
|
1432
1916
|
_p = getattr(cg, "principal", None)
|
|
1433
1917
|
if _p is not None and hasattr(_p, "require_op"):
|
|
1434
1918
|
_p.require_op(op) # 角色作用域闸门:越权即 AccessDenied
|
|
1435
1919
|
|
|
1920
|
+
if op == "status":
|
|
1921
|
+
return _status_call(cg, a)
|
|
1922
|
+
|
|
1923
|
+
if op == "edges":
|
|
1924
|
+
return _edges_call(cg, a)
|
|
1925
|
+
|
|
1436
1926
|
if op == "theory":
|
|
1437
1927
|
from . import theory as _th
|
|
1438
1928
|
act = (a.get("action") or "check").strip().lower()
|
|
@@ -1561,12 +2051,15 @@ def _cg_dispatch(cg, a):
|
|
|
1561
2051
|
|
|
1562
2052
|
if op == "info":
|
|
1563
2053
|
from . import audit
|
|
2054
|
+
from . import nodefile
|
|
1564
2055
|
from . import theory as _th
|
|
1565
2056
|
from . import links as _lk
|
|
1566
2057
|
h = cg.health_os()
|
|
1567
2058
|
h.update({"surface": SURFACE,
|
|
1568
2059
|
"tools": [t["name"] for t in tools_for_surface()],
|
|
1569
|
-
"audit_kinds": audit.kinds(), "whoami": cg.whoami()
|
|
2060
|
+
"audit_kinds": audit.kinds(), "whoami": cg.whoami(),
|
|
2061
|
+
# 裁定 B:CCG 六要素的契约角色(术语真源在 nodefile,此处只透出)
|
|
2062
|
+
"ccg_contract": dict(nodefile.CCG_CONTRACT_ROLES)})
|
|
1570
2063
|
# 能力外置可观测:本进程实际注入了哪些外部验证器(含失败原因)
|
|
1571
2064
|
h["external_verifiers"] = audit.load_external_verifiers()
|
|
1572
2065
|
h["theory"] = _th.check()
|
|
@@ -1576,7 +2069,8 @@ def _cg_dispatch(cg, a):
|
|
|
1576
2069
|
if op == "route":
|
|
1577
2070
|
intent = a.get("intent") or a.get("query") or ""
|
|
1578
2071
|
res, meta = cg.search(intent, k=int(a.get("k") or 10),
|
|
1579
|
-
context=a.get("context"), record=False
|
|
2072
|
+
context=a.get("context"), record=False,
|
|
2073
|
+
view=a.get("view"))
|
|
1580
2074
|
knowledge, caps = [], []
|
|
1581
2075
|
for n, s, q in res:
|
|
1582
2076
|
fm = n.get("frontmatter") or {}
|
|
@@ -1594,8 +2088,20 @@ def _cg_dispatch(cg, a):
|
|
|
1594
2088
|
"note": "认知图只给知识与建议能力名,不执行;由调用方决定"}
|
|
1595
2089
|
|
|
1596
2090
|
if op == "read":
|
|
2091
|
+
# 时间算子(阶段二 4.1):**原样透传**五个时间入参——本层不做校验也不填
|
|
2092
|
+
# 默认值,合法性判定单点在库层 `trust.check_time_args`(默认轴 effective
|
|
2093
|
+
# 亦由库层 `time_axis_of` 决定)。本层若自填默认值,两处口径就会分叉。
|
|
2094
|
+
_tkw = {"start_time": a.get("start_time"), "end_time": a.get("end_time"),
|
|
2095
|
+
"start_operator": a.get("start_operator"),
|
|
2096
|
+
"end_operator": a.get("end_operator"),
|
|
2097
|
+
"time_axis": a.get("time_axis"),
|
|
2098
|
+
# 角色化读取视图(第四阶段 6.1):原样透传,合法性判定单点在
|
|
2099
|
+
# roleviews.ROLE_VIEWS(非法 view 库层 ValueError),与时间算子
|
|
2100
|
+
# 同一透传纪律——本层不做校验也不填默认值。
|
|
2101
|
+
"view": a.get("view")}
|
|
1597
2102
|
if a.get("node_id"):
|
|
1598
|
-
return _node_view(cg.get(a["node_id"])
|
|
2103
|
+
return _node_view(cg.get(a["node_id"]),
|
|
2104
|
+
offset=int(a.get("offset") or 0))
|
|
1599
2105
|
q = a.get("query") or a.get("intent") or ""
|
|
1600
2106
|
if a.get("budget_tokens"):
|
|
1601
2107
|
return cg.recall(q, budget_tokens=int(a["budget_tokens"]),
|
|
@@ -1603,121 +2109,25 @@ def _cg_dispatch(cg, a):
|
|
|
1603
2109
|
goal_text=a.get("goal"),
|
|
1604
2110
|
include_recent=bool(a.get("include_recent")),
|
|
1605
2111
|
recent_limit=int(a.get("limit") or 10),
|
|
1606
|
-
session=a.get("session")
|
|
2112
|
+
session=a.get("session"),
|
|
2113
|
+
validity=a.get("validity"), **_tkw)
|
|
1607
2114
|
from . import refindex
|
|
1608
2115
|
res, meta = cg.search(q, layer=a.get("layer"), k=int(a.get("k") or 20),
|
|
1609
2116
|
context=a.get("context"),
|
|
1610
|
-
session=a.get("session")
|
|
2117
|
+
session=a.get("session"),
|
|
2118
|
+
validity=a.get("validity"), **_tkw)
|
|
1611
2119
|
return {"meta": meta, "results": [
|
|
1612
2120
|
{"node": _node_view(n), "score": s, "state": q2.get("state"),
|
|
1613
2121
|
"reason": q2.get("reason"), **refindex.ref_fields(n)}
|
|
1614
2122
|
for n, s, q2 in res]}
|
|
1615
2123
|
|
|
1616
2124
|
if op == "write":
|
|
1617
|
-
|
|
1618
|
-
|
|
1619
|
-
|
|
1620
|
-
|
|
1621
|
-
|
|
1622
|
-
|
|
1623
|
-
{"cg": cg, "principal": getattr(cg, "principal", None)})
|
|
1624
|
-
nid = a.get("node_id") or ("mem_" + str(int(__import__("time").time() * 1000)))
|
|
1625
|
-
st = verdict["state"]
|
|
1626
|
-
if st == audit.ACCEPT:
|
|
1627
|
-
# 节点间自动冲突检测(三级决策:情绪→反思→递归反思):
|
|
1628
|
-
# 写入前与既有条件/纪律校验;不通过则不落盘(可进审核队列)。
|
|
1629
|
-
# 与 mdcg_remember 同源、默认开启——「信息的修改必须先通过校验」。
|
|
1630
|
-
cvd = None
|
|
1631
|
-
if bool(a.get("consistency", True)):
|
|
1632
|
-
oc = (a.get("on_conflict") or "defer").strip().lower()
|
|
1633
|
-
cvd = cg.check_consistency(
|
|
1634
|
-
a.get("content", ""),
|
|
1635
|
-
layer=a.get("layer") or ("contextual" if a.get("gated")
|
|
1636
|
-
else "knowledge"),
|
|
1637
|
-
condition_space=a.get("condition_space"),
|
|
1638
|
-
non_applicable_conditions=a.get("non_applicable_conditions"),
|
|
1639
|
-
tags=a.get("tags"), exclude=nid, auto_flywheel=True)
|
|
1640
|
-
v = cvd.get("verdict")
|
|
1641
|
-
blocked = ((v == "REJECT" and oc == "reject")
|
|
1642
|
-
or (v in ("REJECT", "BLINDSPOT") and oc == "defer"))
|
|
1643
|
-
if blocked:
|
|
1644
|
-
if oc == "reject":
|
|
1645
|
-
return {"ok": False, "id": nid, "committed": False,
|
|
1646
|
-
"moved_to": "conflict_rejected",
|
|
1647
|
-
"consistency": cvd, "verdict": verdict}
|
|
1648
|
-
pid = cg.propose(nid, a.get("content", ""),
|
|
1649
|
-
layer=a.get("layer") or "knowledge",
|
|
1650
|
-
tags=a.get("tags"),
|
|
1651
|
-
condition_space=a.get("condition_space"),
|
|
1652
|
-
**_proposal_extras(a, verdict))
|
|
1653
|
-
return {"ok": False, "id": nid, "pid": pid, "committed": False,
|
|
1654
|
-
"moved_to": "review_queue", "consistency": cvd,
|
|
1655
|
-
"verdict": verdict,
|
|
1656
|
-
"hint": "这是冲突闸门的正常行为:本次写入与既有条件/纪律冲突"
|
|
1657
|
-
"(on_conflict=defer),已转入审核队列待裁决——"
|
|
1658
|
-
"不是工具故障,重试同样结果;"
|
|
1659
|
-
"落盘须由设计者权限(can_admin)裁决,转告使用者:"
|
|
1660
|
-
"python scripts/review_cli.py list 后 accept/reject,"
|
|
1661
|
-
"或 cg(op=review, pid=<pid>, decision=accept|reject|"
|
|
1662
|
-
"edit|merge, reason=<理由>)"}
|
|
1663
|
-
if a.get("gated"):
|
|
1664
|
-
hint = a.get("importance_hint")
|
|
1665
|
-
if hint is None and a.get("importance") is not None:
|
|
1666
|
-
hint = float(a["importance"])
|
|
1667
|
-
res = cg.remember_gated(
|
|
1668
|
-
nid, a.get("content", ""), layer=a.get("layer") or "contextual",
|
|
1669
|
-
role=a.get("role"), tags=a.get("tags"),
|
|
1670
|
-
condition_space=a.get("condition_space"),
|
|
1671
|
-
verification_basis=(a.get("verification_basis")
|
|
1672
|
-
or verdict.get("basis")),
|
|
1673
|
-
non_applicable_conditions=a.get("non_applicable_conditions"),
|
|
1674
|
-
importance_hint=hint, override=bool(a.get("override")),
|
|
1675
|
-
consistency=False,
|
|
1676
|
-
derived_from=_split_ids(a.get("derived_from")),
|
|
1677
|
-
relation=a.get("relation"))
|
|
1678
|
-
v = res.get("verdict")
|
|
1679
|
-
committed = v == "ACCEPT"
|
|
1680
|
-
out = {"ok": committed, "id": nid, "committed": committed,
|
|
1681
|
-
"gate": res, "verdict": verdict}
|
|
1682
|
-
if cvd is not None:
|
|
1683
|
-
out["consistency"] = cvd
|
|
1684
|
-
if v == "MERGE":
|
|
1685
|
-
out["moved_to"] = "merged_into:" + str(res.get("merged_into"))
|
|
1686
|
-
elif v in ("DROP", "DEFER"):
|
|
1687
|
-
out["moved_to"] = v.lower()
|
|
1688
|
-
return out
|
|
1689
|
-
cg.add(nid, a.get("content", ""), layer=a.get("layer") or "knowledge",
|
|
1690
|
-
tags=a.get("tags"), condition_space=a.get("condition_space"),
|
|
1691
|
-
importance=float(a.get("importance", 0.5)),
|
|
1692
|
-
verification_basis=a.get("verification_basis") or verdict.get("basis"),
|
|
1693
|
-
non_applicable_conditions=a.get("non_applicable_conditions"),
|
|
1694
|
-
override=bool(a.get("override")), consistency=False,
|
|
1695
|
-
derived_from=_split_ids(a.get("derived_from")),
|
|
1696
|
-
relation=a.get("relation"))
|
|
1697
|
-
out = {"ok": True, "id": nid, "committed": True, "verdict": verdict}
|
|
1698
|
-
if cvd is not None:
|
|
1699
|
-
out["consistency"] = cvd
|
|
1700
|
-
return out
|
|
1701
|
-
if st == audit.REJECT:
|
|
1702
|
-
rid = cg.add_rejected((a.get("content") or "")[:200], verdict["evidence"],
|
|
1703
|
-
verification_basis=verdict.get("basis") or "test",
|
|
1704
|
-
tags=a.get("tags"))
|
|
1705
|
-
return {"ok": False, "id": rid, "committed": False,
|
|
1706
|
-
"moved_to": "rejected", "verdict": verdict,
|
|
1707
|
-
"hint": "这是审核闸门的正常行为:内容未过内容政策审核(REJECT),"
|
|
1708
|
-
"已记入负记忆——不是工具故障,重试同样结果;"
|
|
1709
|
-
"拒绝依据见 verdict.evidence"}
|
|
1710
|
-
pid = cg.propose(nid, a.get("content", ""), layer=a.get("layer") or "knowledge",
|
|
1711
|
-
tags=a.get("tags"), condition_space=a.get("condition_space"),
|
|
1712
|
-
**_proposal_extras(a, verdict))
|
|
1713
|
-
return {"ok": True, "id": nid, "pid": pid, "committed": False,
|
|
1714
|
-
"moved_to": "review_queue", "verdict": verdict,
|
|
1715
|
-
"hint": "这是校验闸门的正常行为(verdict=%s):内容未达 ACCEPT,"
|
|
1716
|
-
"已入审核队列——不需要重试;落盘须由设计者权限(can_admin)"
|
|
1717
|
-
"对提案 pid 裁决(agent 端无裁决权是设计),转告使用者:"
|
|
1718
|
-
"python scripts/review_cli.py list 后 accept/reject,"
|
|
1719
|
-
"或 cg(op=review, pid=<pid>, decision=accept|reject|"
|
|
1720
|
-
"edit|merge, reason=<理由>)" % verdict.get("state")}
|
|
2125
|
+
# 写入路径拦截器链(Pi 钩子化移植,writepipe.py):六道闸以扩展
|
|
2126
|
+
# 形态注册于 writepipe.default_pipeline(),次序/启停不再硬编码于
|
|
2127
|
+
# 本文件;新增闸门 = register_before 一行,即插即拔。
|
|
2128
|
+
# 角色/层权限校验在 MdCGSecure.add 库层,结构上不可被拦截器绕过。
|
|
2129
|
+
from .writepipe import default_pipeline
|
|
2130
|
+
return default_pipeline().execute(cg, a)
|
|
1721
2131
|
|
|
1722
2132
|
if op == "goal":
|
|
1723
2133
|
act = (a.get("action") or "list").strip().lower()
|
|
@@ -1738,6 +2148,9 @@ def _cg_dispatch(cg, a):
|
|
|
1738
2148
|
limit=int(a.get("limit") or 20)),
|
|
1739
2149
|
"active": cg.active_goals(limit=int(a.get("limit") or 5))}
|
|
1740
2150
|
|
|
2151
|
+
if op == "task":
|
|
2152
|
+
return _task_call(cg, a)
|
|
2153
|
+
|
|
1741
2154
|
if op == "recent":
|
|
1742
2155
|
act = (a.get("action") or "list").strip().lower()
|
|
1743
2156
|
if act in ("add", "append", "remember"):
|
|
@@ -1758,6 +2171,10 @@ def _cg_dispatch(cg, a):
|
|
|
1758
2171
|
act = (a.get("action") or "list").strip().lower()
|
|
1759
2172
|
if act == "list":
|
|
1760
2173
|
return {"pending": cg.review_list()}
|
|
2174
|
+
if act == "stats":
|
|
2175
|
+
# 裁决动作分布(含 noop):无此出口则「已评估、判定无需改动」这类
|
|
2176
|
+
# 裁决只在 jsonl 里躺着,治理面看不到——与「静默忽略」等价。
|
|
2177
|
+
return cg.review_stats()
|
|
1761
2178
|
if act == "rounds":
|
|
1762
2179
|
pid = a.get("pid", "")
|
|
1763
2180
|
return {"pid": pid, "rounds": cg.review_rounds(pid)}
|
|
@@ -1898,9 +2315,184 @@ def _cg_dispatch(cg, a):
|
|
|
1898
2315
|
if op == "insight":
|
|
1899
2316
|
return _insight_call(cg, a)
|
|
1900
2317
|
|
|
2318
|
+
if op == "ccg":
|
|
2319
|
+
return _ccg_call(cg, a)
|
|
2320
|
+
|
|
1901
2321
|
raise ValueError(f"cg 未知 op:{op}")
|
|
1902
2322
|
|
|
1903
2323
|
|
|
2324
|
+
# 生效条件:由 _cg_dispatch 在 op=="ccg" 时进入;action 取 a.get("action") 缺省 "compile";compile 只产出候选(落 _ccgc_pending/ 待复核、不当场写库),link 才准入落库,attest/recalibrate 须编外验证方且 verifier != compiled_by(E041/E042/E043 机械把关);
|
|
2325
|
+
def _ccg_call(cg, a):
|
|
2326
|
+
"""CCG 六要素编译器(op=ccg):对话记录 → 六要素候选 → **编外复核** → 落库。
|
|
2327
|
+
|
|
2328
|
+
定位:**记忆可靠性闸**——不是又一个写入通道,而是写入前「条件是否成立」的检查。
|
|
2329
|
+
裁定 A(LLM 不得自己验证自己)由 ccgc 的 E041 **机械执行**,不依赖 prompt 自觉。
|
|
2330
|
+
|
|
2331
|
+
action(缺省 compile):
|
|
2332
|
+
compile 对话记录 → 六要素候选(五环编译);候选+签章槽落
|
|
2333
|
+
`_ccgc_pending/<node_id>.json`(**不当场写库**)
|
|
2334
|
+
review 派发编外复核单元:**蜂巢 reflect/verify 优先** → 不可用则提示配置
|
|
2335
|
+
→ 显式 allow_degrade 才降级 harness 端子代理;拿到裁决即自动签章
|
|
2336
|
+
attest 外部裁决签章(verifier 须 != compiled_by;E041/E042 机械把关)
|
|
2337
|
+
link 读回候选+签章 → 准入校验 → apply=True 落库(成功后清 pending)
|
|
2338
|
+
recalibrate 四槽修正(须编外验证方;E043 只放开 condition_space 四槽)
|
|
2339
|
+
units 复核通道体检/计划(hive → 提示配置 → 子代理 三级链)
|
|
2340
|
+
catalog 引擎自描述(错误码/契约角色/动作清单)
|
|
2341
|
+
|
|
2342
|
+
入参集中在 `ccg` 对象里(与 `redteam`/`verify` 同风格)——避免与既有扁平参数
|
|
2343
|
+
重名(如 `verdict` 在 verify 面是 confirmed|weakened|falsified,语义不同)。
|
|
2344
|
+
|
|
2345
|
+
返回语义:`ok` 表示**本次请求本身**是否成立;`verdict` 是单元给出的裁决
|
|
2346
|
+
(未复核为 None);`passed` = 裁决为 ACCEPT。三者分开,避免「派发成功」
|
|
2347
|
+
被误读成「复核通过」。
|
|
2348
|
+
|
|
2349
|
+
权限:编译器属写路径 → 记录/设计者角色可用(见 tokens.ALL_OPS 的 ccg 条目)。
|
|
2350
|
+
attest/link 的准入**不靠 admin 闸**,而靠签章机械闸(E040/E041/E042)——理由:
|
|
2351
|
+
默认部署(未设 MDCG_CAN_ADMIN)下再加 admin 会让编译器对使用者不可见
|
|
2352
|
+
(「权限到位但通路不可见」是既有教训),而裁定 A 的保证本就在机械闸里。
|
|
2353
|
+
"""
|
|
2354
|
+
from . import ccgc
|
|
2355
|
+
from . import units as _units
|
|
2356
|
+
|
|
2357
|
+
o = a.get("ccg") or {}
|
|
2358
|
+
if not isinstance(o, dict):
|
|
2359
|
+
return {"ok": False, "op": "ccg",
|
|
2360
|
+
"error": "ccg 参数须为对象:{action, node_id, dialog, ...}"}
|
|
2361
|
+
act = str(o.get("action") or a.get("action") or "compile").strip().lower()
|
|
2362
|
+
node_id = str(o.get("node_id") or a.get("node_id") or "").strip()
|
|
2363
|
+
actor = str(getattr(getattr(cg, "principal", None), "actor", "") or o.get("actor") or "agent")
|
|
2364
|
+
jobs = str(o.get("jobs") or "")
|
|
2365
|
+
|
|
2366
|
+
if act == "catalog":
|
|
2367
|
+
return {"ok": True, "op": "ccg", "action": "catalog",
|
|
2368
|
+
"actions": ["compile", "review", "attest", "link", "recalibrate",
|
|
2369
|
+
"units", "catalog"],
|
|
2370
|
+
"states": list(ccgc.STATES), "contract_roles": list(ccgc.CONTRACT_ROLES),
|
|
2371
|
+
"errors": dict(ccgc.E_CODES),
|
|
2372
|
+
"rule": "裁定 A:验证方标识不得等于编译执行者(E041);缺签章不写库(E040);"
|
|
2373
|
+
"未通过不写库(E042)"}
|
|
2374
|
+
|
|
2375
|
+
if act == "units":
|
|
2376
|
+
if o.get("doctor"):
|
|
2377
|
+
return {"ok": True, "op": "ccg", "action": "units", **_units.doctor(jobs)}
|
|
2378
|
+
p = _units.plan(jobs=jobs, model=o.get("model") or "",
|
|
2379
|
+
allow_degrade=bool(o.get("allow_degrade")),
|
|
2380
|
+
channel=o.get("channel") or "")
|
|
2381
|
+
return {"ok": True, "op": "ccg", "action": "units", **p}
|
|
2382
|
+
|
|
2383
|
+
if act == "compile":
|
|
2384
|
+
dialog = str(o.get("dialog") or o.get("content") or a.get("content") or "")
|
|
2385
|
+
if not dialog.strip():
|
|
2386
|
+
return {"ok": False, "op": "ccg", "action": "compile",
|
|
2387
|
+
"error": "缺对话记录:传 ccg.dialog(或顶层 content)"}
|
|
2388
|
+
if not node_id:
|
|
2389
|
+
return {"ok": False, "op": "ccg", "action": "compile",
|
|
2390
|
+
"error": "缺 node_id:六要素候选须指明目标节点"}
|
|
2391
|
+
res = ccgc.compile_dialog(dialog, node_id, actor,
|
|
2392
|
+
marks=o.get("marks"), slots=o.get("slots"),
|
|
2393
|
+
strict_spans=bool(o.get("strict_spans", True)), cg=cg)
|
|
2394
|
+
saved = ccgc.save_pending(cg, res)
|
|
2395
|
+
return {"ok": bool(res.success), "op": "ccg", "action": "compile",
|
|
2396
|
+
"compiled": ccgc.asdict(res), "pending": saved,
|
|
2397
|
+
"actor": actor, "compiled_by": actor,
|
|
2398
|
+
"hint": ("候选已落 pending;下一步 cg(op=ccg, action=review, "
|
|
2399
|
+
"ccg={node_id, blocking:true}) 交编外单元复核"
|
|
2400
|
+
"——编译者不得自证(E041)" if res.success else
|
|
2401
|
+
"编译未通过:" + (res.errors[0] if res.errors else "未知错误"))}
|
|
2402
|
+
|
|
2403
|
+
if act == "review":
|
|
2404
|
+
got = ccgc.load_pending(cg, node_id)
|
|
2405
|
+
if not got.get("ok") or not got.get("hash_ok"):
|
|
2406
|
+
return {"ok": False, "op": "ccg", "action": "review",
|
|
2407
|
+
"error": got.get("error") or "pending 产物与编译时不一致(hash 不符)",
|
|
2408
|
+
"hint": "先 cg(op=ccg, action=compile, ccg={node_id, dialog}) 生成候选"}
|
|
2409
|
+
compiled = got["compiled"]
|
|
2410
|
+
role = str(o.get("role") or _units.REFLECT).strip().lower()
|
|
2411
|
+
prompt = _units.prompt_for(role, compiled, dialog=str(o.get("dialog") or ""))
|
|
2412
|
+
r = _units.review(prompt=prompt, role=role, node_id=node_id, jobs=jobs,
|
|
2413
|
+
model=o.get("model") or "",
|
|
2414
|
+
timeout_s=int(o.get("timeout_s") or _units.DEFAULT_TIMEOUT_S),
|
|
2415
|
+
allow_degrade=bool(o.get("allow_degrade")),
|
|
2416
|
+
channel=o.get("channel") or "",
|
|
2417
|
+
wait_s=float(o.get("wait_s") or _units.DEFAULT_TIMEOUT_S),
|
|
2418
|
+
blocking=bool(o.get("blocking")), cg=cg, actor=actor,
|
|
2419
|
+
autostart=bool(o.get("autostart")))
|
|
2420
|
+
unit = r.get("unit")
|
|
2421
|
+
out = {"ok": True, "op": "ccg", "action": "review", "state": r["state"],
|
|
2422
|
+
"role": role, "node_id": node_id, "job_id": r.get("job_id"),
|
|
2423
|
+
"transport": r.get("transport"), "verdict": (unit or {}).get("verdict"),
|
|
2424
|
+
"passed": bool((unit or {}).get("verdict") == ccgc.ACCEPT),
|
|
2425
|
+
"unit": unit, "channel": r.get("channel") or "",
|
|
2426
|
+
"blocking": bool(o.get("blocking")), "hint": r.get("hint") or ""}
|
|
2427
|
+
if r["state"] != _units.HIVE:
|
|
2428
|
+
out["ok"] = False
|
|
2429
|
+
out["prompt"] = r.get("prompt") # 降级/配置路径:把复核请求包交回调用方
|
|
2430
|
+
return out
|
|
2431
|
+
if unit: # 已获编外裁决 → 自动签章
|
|
2432
|
+
args = r.get("attest") or {}
|
|
2433
|
+
at = ccgc.attest(node_id, args.get("verdict") or ccgc.DEFER,
|
|
2434
|
+
args.get("verifier") or "", compiled.actor or actor,
|
|
2435
|
+
slot_corrections=args.get("slot_corrections"),
|
|
2436
|
+
evidence=args.get("evidence") or "", cg=cg)
|
|
2437
|
+
out["attest"] = ccgc.asdict(at)
|
|
2438
|
+
out["pending"] = ccgc.save_pending(cg, compiled, at)
|
|
2439
|
+
out["hint"] = ("已签章(%s);下一步 cg(op=ccg, action=link, "
|
|
2440
|
+
"ccg={node_id, apply:true}) 落库"
|
|
2441
|
+
% (args.get("verifier") or "-") if at.ok else
|
|
2442
|
+
"签章未通过:" + (at.error or "DEFER/REJECT 不构成准入"))
|
|
2443
|
+
return out
|
|
2444
|
+
|
|
2445
|
+
if act == "attest":
|
|
2446
|
+
got = ccgc.load_pending(cg, node_id)
|
|
2447
|
+
if not got.get("ok") or not got.get("hash_ok"):
|
|
2448
|
+
return {"ok": False, "op": "ccg", "action": "attest",
|
|
2449
|
+
"error": got.get("error") or "pending 产物与编译时不一致(hash 不符)",
|
|
2450
|
+
"hint": "先 cg(op=ccg, action=compile, ...) 生成候选"}
|
|
2451
|
+
compiled = got["compiled"]
|
|
2452
|
+
at = ccgc.attest(node_id, str(o.get("verdict") or ""),
|
|
2453
|
+
str(o.get("verifier") or ""),
|
|
2454
|
+
str(o.get("compiled_by") or compiled.actor or actor),
|
|
2455
|
+
slot_corrections=o.get("slot_corrections"),
|
|
2456
|
+
evidence=str(o.get("evidence") or ""), cg=cg)
|
|
2457
|
+
return {"ok": bool(at.ok), "op": "ccg", "action": "attest",
|
|
2458
|
+
"attest": ccgc.asdict(at),
|
|
2459
|
+
"pending": ccgc.save_pending(cg, compiled, at),
|
|
2460
|
+
"hint": ("签章通过;下一步 cg(op=ccg, action=link, ccg={node_id, apply:true})"
|
|
2461
|
+
if at.ok else "签章未通过:" + (at.error or "DEFER/REJECT 不构成准入"))}
|
|
2462
|
+
|
|
2463
|
+
if act == "link":
|
|
2464
|
+
apply = bool(o.get("apply"))
|
|
2465
|
+
res = ccgc.link_pending(cg, node_id, apply=apply, actor=actor,
|
|
2466
|
+
basis=str(o.get("basis") or "ccgc link"))
|
|
2467
|
+
return {"ok": bool(res.ok), "op": "ccg", "action": "link", "apply": apply,
|
|
2468
|
+
"link": ccgc.asdict(res),
|
|
2469
|
+
"hint": ("已落库(entry_id=%s,written=%s)" % (res.entry_id, res.written)
|
|
2470
|
+
if res.ok and apply else
|
|
2471
|
+
("准入通过(dry_run 未写库);apply=true 才落库" if res.ok else
|
|
2472
|
+
";".join(res.errors or []) or "准入未通过"))}
|
|
2473
|
+
|
|
2474
|
+
if act == "recalibrate":
|
|
2475
|
+
corr = o.get("slot_corrections") or o.get("corrections") or {}
|
|
2476
|
+
verifier = str(o.get("verifier") or "").strip()
|
|
2477
|
+
compiled_by = str(o.get("compiled_by") or "").strip()
|
|
2478
|
+
if not verifier or verifier == compiled_by:
|
|
2479
|
+
return {"ok": False, "op": "ccg", "action": "recalibrate",
|
|
2480
|
+
"error": "E041 自证拒绝:recalibrate 须由编外验证方给出"
|
|
2481
|
+
"(verifier 必填且 != compiled_by)"}
|
|
2482
|
+
res = ccgc.recalibrate(node_id, corr, verifier, compiled_by,
|
|
2483
|
+
evidence=str(o.get("evidence") or ""), cg=cg,
|
|
2484
|
+
apply=bool(o.get("apply")))
|
|
2485
|
+
return {"ok": bool(res.ok), "op": "ccg", "action": "recalibrate",
|
|
2486
|
+
"recalibrate": ccgc.asdict(res),
|
|
2487
|
+
"hint": (";".join(res.errors or []) or "修正已应用(apply=true)" if res.ok
|
|
2488
|
+
else ";".join(res.errors or []) or "修正未通过")}
|
|
2489
|
+
|
|
2490
|
+
return {"ok": False, "op": "ccg", "action": act,
|
|
2491
|
+
"error": "ccg 未知 action:%s(可选 compile|review|attest|link|recalibrate|"
|
|
2492
|
+
"units|catalog)" % act}
|
|
2493
|
+
|
|
2494
|
+
|
|
2495
|
+
# 生效条件:act=(a.get("action") or "recall").strip().lower();act=="note" 时若 principal 非 None 且其 can_write 为假先 require_admin("session_note"),再调 cg.session_note(summary/text/content 之一或 "",importance=float(0.6 if a.get("importance") is None else a.get("importance")) 等);act=="recall" 时调 cg.session_recall(...);act=="compact" 时若 a.get("note") 为真且 principal 非 None 且无写权先 require_admin("session_compact"),再调 cg.session_compact(...);其余 act 抛 ValueError。
|
|
1904
2496
|
def _session_call(cg, a):
|
|
1905
2497
|
"""会话三件套(P0):note 写要点 / recall 续接 / compact 压摘要。
|
|
1906
2498
|
|
|
@@ -1939,6 +2531,7 @@ def _session_call(cg, a):
|
|
|
1939
2531
|
raise ValueError(f"session 未知 action:{act}(允许 note/recall/compact)")
|
|
1940
2532
|
|
|
1941
2533
|
|
|
2534
|
+
# 生效条件:flag=a.get("prune", True),flag 为字符串时重算为 flag.strip().lower() not in ("false","0","no","off","");若 not flag 或 stats.get("truncated") 为真则返回 None;否则返回 refindex.prune_orphans(cg, kind=kind, root=root, items=items, dry_run=bool(a.get("prune_dry_run"))).
|
|
1942
2535
|
def _prune_after_index(cg, a, *, kind, root, items, stats):
|
|
1943
2536
|
"""索引后的**节点级对账**:清退「同 root + 同 path 的过期代」。
|
|
1944
2537
|
|
|
@@ -1961,6 +2554,7 @@ def _prune_after_index(cg, a, *, kind, root, items, stats):
|
|
|
1961
2554
|
dry_run=bool(a.get("prune_dry_run")))
|
|
1962
2555
|
|
|
1963
2556
|
|
|
2557
|
+
# 生效条件:sd=list(stats.get("skipped_dirs") or []),返回 {"skipped_dirs": sd[:limit], "skipped_dirs_count": len(sd), "skip_dirs": list(stats.get("skip_dirs") or [])},且仅当 len(sd)>limit 时追加 skipped_dirs_note。
|
|
1964
2558
|
def _skip_dirs_report(stats, limit=20):
|
|
1965
2559
|
"""把「本次被 skip_dirs 排掉的目录」压成可审计字段。
|
|
1966
2560
|
|
|
@@ -1975,6 +2569,7 @@ def _skip_dirs_report(stats, limit=20):
|
|
|
1975
2569
|
return out
|
|
1976
2570
|
|
|
1977
2571
|
|
|
2572
|
+
# 生效条件:act=(a.get("action") or "stat").strip().lower();act 属 ("file","dir","jsonl") 且 principal 非 None 且其 can_write 为假时先 require_admin(f"ingest_{act}"),随后以 action=act 及各透传参数调 sources.run 并返回。
|
|
1978
2573
|
def _ingest_call(cg, a):
|
|
1979
2574
|
"""文件摄取分派(P0):file / dir / jsonl / stat。
|
|
1980
2575
|
|
|
@@ -1995,6 +2590,7 @@ def _ingest_call(cg, a):
|
|
|
1995
2590
|
max_events=a.get("max_events"))
|
|
1996
2591
|
|
|
1997
2592
|
|
|
2593
|
+
# 生效条件:act=(a.get("action") or "stat").strip().lower();principal 非 None 时一律先 require_admin(f"export_{act}"),随后以 include_content=True if a.get("include_content") is None else bool(a.get("include_content")) 等参数调 _ex.run 并返回。
|
|
1998
2594
|
def _export_call(cg, a):
|
|
1999
2595
|
"""全库导出(P0):graph / nodes / slice / stat。
|
|
2000
2596
|
|
|
@@ -2013,8 +2609,9 @@ def _export_call(cg, a):
|
|
|
2013
2609
|
include_content=True if inc is None else bool(inc))
|
|
2014
2610
|
|
|
2015
2611
|
|
|
2612
|
+
# 生效条件:act=(a.get("action") or "stat").strip().lower(),apply=bool(a.get("apply")),mode=str(a.get("mode") or "").strip().lower();principal 非 None 时对 act=="rollback"、act in ("importance","separate") 且 apply、act=="longterm" 且 apply、act=="prefeed" 且 a.get("write") 真且无写权、act in ("backfill","cap","exempt") 且 apply、act in ("backfill_rollback","cap_rollback","exempt_rollback")、act=="vision_evidence" 且 apply、act=="vision_evidence_rollback"、act=="refine" 且 apply 分别 require_admin;随后 act=="longterm" 且 mode in ("list","ls","show","read") 时仅以 action/mode/limit/snapshot_id 调 cg.maintain,否则以全部参数调 cg.maintain。
|
|
2016
2613
|
def _maintain_call(cg, a):
|
|
2017
|
-
"""记忆维护(P1):importance / longterm / prefeed / separate / rollback / stat。
|
|
2614
|
+
"""记忆维护(P1):importance / longterm / prefeed / separate / rollback / stat / propagate。
|
|
2018
2615
|
|
|
2019
2616
|
权限**按 action 分档**(比整 op 收窄更贴合语义):
|
|
2020
2617
|
· 只读(stat / history / longterm mode=list|show)→ 不额外拦截;
|
|
@@ -2029,6 +2626,19 @@ def _maintain_call(cg, a):
|
|
|
2029
2626
|
apply = bool(a.get("apply"))
|
|
2030
2627
|
mode = str(a.get("mode") or "").strip().lower()
|
|
2031
2628
|
actor = getattr(principal, "actor", None) if principal is not None else None
|
|
2629
|
+
# P4 可验证记忆单元(2026-09-19):**多跳**失效传播巡检(写路径只做一跳同步,
|
|
2630
|
+
# 保写入延迟恒定——多跳的重算成本交给巡检面)。
|
|
2631
|
+
# · 预演(默认 apply=False)→ 只出可达集报表,放行写层角色先看影响面;
|
|
2632
|
+
# · apply=True → 直接改写下游验证态(同步写盘)→ 管理操作。
|
|
2633
|
+
if act == "propagate":
|
|
2634
|
+
from . import trust as _trust
|
|
2635
|
+
if apply and principal is not None:
|
|
2636
|
+
principal.require_admin("maintain_propagate")
|
|
2637
|
+
rep = _trust.propagate(cg, apply=apply,
|
|
2638
|
+
max_nodes=int(a.get("max_nodes") or 500),
|
|
2639
|
+
actor=actor or "patrol")
|
|
2640
|
+
rep.update({"op": "maintain", "action": "propagate"})
|
|
2641
|
+
return rep
|
|
2032
2642
|
if principal is not None and act == "rollback":
|
|
2033
2643
|
principal.require_admin("maintain_rollback")
|
|
2034
2644
|
if principal is not None and act in ("importance", "separate") and apply:
|
|
@@ -2077,6 +2687,7 @@ def _maintain_call(cg, a):
|
|
|
2077
2687
|
verdicts=a.get("verdicts"), reason=a.get("reason"))
|
|
2078
2688
|
|
|
2079
2689
|
|
|
2690
|
+
# 生效条件:act=(a.get("action") or "promote").strip().lower();principal 非 None 时一律先 require_admin(f"consolidate_{act}");imp=a.get("min_importance"),为 None 时回落为 a.get("importance"),随后以 imp 等参数调 cg.consolidate_run 并返回。
|
|
2080
2691
|
def _consolidate_call(cg, a):
|
|
2081
2692
|
"""离线固化(P1):promote / promote_rollback / promote_history。
|
|
2082
2693
|
|
|
@@ -2101,15 +2712,20 @@ def _consolidate_call(cg, a):
|
|
|
2101
2712
|
actor=getattr(principal, "actor", None) if principal is not None else None)
|
|
2102
2713
|
|
|
2103
2714
|
|
|
2715
|
+
# 生效条件:act=(a.get("action") or "outlook").strip().lower(),apply=bool(a.get("apply"));principal 非 None 时 can_write=bool(principal.can_write),对 act in ("record","verify") 且无写权、act in ("fork","branch_rewrite","branch_merge") 且无写权、act in ("reconstruct","learn") 且 apply、act=="branch_discard" 分别 require_admin;随后以 action=act 等参数调 cg.insight 并返回。
|
|
2104
2716
|
def _insight_call(cg, a):
|
|
2105
2717
|
"""洞察(P2):window / record / verify / list / report / reconstruct / learn /
|
|
2106
|
-
outlook / catalog
|
|
2718
|
+
outlook / catalog / fork / branch_rewrite / branch_search / branch_merge /
|
|
2719
|
+
branch_discard / branches / tickets。
|
|
2107
2720
|
|
|
2108
2721
|
权限**按 action 分档**(与 maintain 同构,比整 op 收窄更贴合语义):
|
|
2109
|
-
· 只读(window / list / report / reconstruct 预演 / outlook / catalog
|
|
2110
|
-
|
|
2111
|
-
· 条件层记账(record / verify
|
|
2112
|
-
|
|
2722
|
+
· 只读(window / list / report / reconstruct 预演 / outlook / catalog /
|
|
2723
|
+
branch_search / branches / fork 预演 / tickets 预演)→ 不额外拦截;
|
|
2724
|
+
· 条件层记账(record / verify)与分支写操作(fork / branch_rewrite /
|
|
2725
|
+
branch_merge)→ 需 can_write;
|
|
2726
|
+
· 落库(reconstruct apply / learn apply / tickets apply 批量建卡)与
|
|
2727
|
+
分支弃置(branch_discard,改变库可见性)→ require_admin
|
|
2728
|
+
(discard 库层还有第二道闸)。
|
|
2113
2729
|
这样 output 角色能读洞察但不能记;reflect 能重构与学习预演;批量落库须请示。
|
|
2114
2730
|
"""
|
|
2115
2731
|
act = (a.get("action") or "outlook").strip().lower()
|
|
@@ -2119,23 +2735,34 @@ def _insight_call(cg, a):
|
|
|
2119
2735
|
actor = getattr(principal, "actor", None) if principal is not None else None
|
|
2120
2736
|
if principal is not None and act in ("record", "verify") and not can_write:
|
|
2121
2737
|
principal.require_admin(f"insight_{act}") # 无写权 → 抛 AccessDenied
|
|
2122
|
-
if principal is not None and act in ("
|
|
2123
|
-
|
|
2738
|
+
if principal is not None and act in ("fork", "branch_rewrite",
|
|
2739
|
+
"branch_merge") and not can_write:
|
|
2740
|
+
principal.require_admin(f"insight_{act}") # 分支写 → 需写权
|
|
2741
|
+
if principal is not None and act in ("reconstruct", "learn",
|
|
2742
|
+
"tickets") and apply:
|
|
2743
|
+
principal.require_admin(f"insight_{act}") # 批量落库 → 需 admin
|
|
2744
|
+
if principal is not None and act == "branch_discard":
|
|
2745
|
+
principal.require_admin("branch_discard") # 弃置:分发层+库层双闸
|
|
2124
2746
|
return cg.insight(
|
|
2125
2747
|
action=act, layer=a.get("layer"), limit=a.get("limit"),
|
|
2126
2748
|
conditions=a.get("conditions"), apply=apply, actor=actor,
|
|
2127
2749
|
statement=a.get("statement"), category=a.get("category"),
|
|
2128
2750
|
source=a.get("source"), tags=a.get("tags"),
|
|
2129
2751
|
importance=a.get("importance"), node_id=a.get("node_id"),
|
|
2752
|
+
content=a.get("content"),
|
|
2130
2753
|
evidence=a.get("evidence"), v_types=a.get("v_types"),
|
|
2131
2754
|
verdict=a.get("verdict"), state=a.get("state"),
|
|
2132
2755
|
window_days=a.get("window_days"), clues=a.get("clues"),
|
|
2133
2756
|
ids=a.get("ids"), neighbors=a.get("neighbors"),
|
|
2757
|
+
branch_id=a.get("branch_id"), note=a.get("note"),
|
|
2758
|
+
reason=a.get("reason"),
|
|
2134
2759
|
blindspot_id=a.get("blindspot_id"), horizon=a.get("horizon"),
|
|
2135
2760
|
max_branches=a.get("max_branches"), recent_days=a.get("recent_days"),
|
|
2136
|
-
sample_limit=a.get("sample_limit"), max_nodes=a.get("max_nodes")
|
|
2761
|
+
sample_limit=a.get("sample_limit"), max_nodes=a.get("max_nodes"),
|
|
2762
|
+
types=a.get("types"), min_blindspot=a.get("min_blindspot"))
|
|
2137
2763
|
|
|
2138
2764
|
|
|
2765
|
+
# 生效条件:当 cg、a 传入时,按 a.get('action') or 'read'(空串/None 回退 'read')分派:action=stat 返回 {'ok': True, 'action': 'stat', 'ledger': refindex.Ledger(cg.root).summary(), 'note': 'ref 索引水位(_refindex.json):files/nodes 是已登记量;last_index.truncated=true 表示最近一次索引被截断。'};action=check 返回 refindex.check_refs(cg, ledger=refindex.Ledger(cg.root), max_nodes=int(a.get('max_nodes') or refindex.MAX_CHECK)) 的结果并补 action='check' 与 note(max_nodes 假值回落 refindex.MAX_CHECK);action 为 prune/prune_dangling 返回 refindex.prune_dangling(cg, only_roots=a.get('roots'), dry_run=bool(a.get('dry_run')), max_nodes=int(a.get('max_nodes') or refindex.MAX_CHECK)) 的结果并补 action='prune' 与 note(max_nodes 假值回落常量,dry_run 缺键为 False);action 为 read/get 时 nid=(a.get('node_id') or '').strip(),若 nid 非空但 cg.get(nid) 为假返回 {'ok': False, 'error': '节点不存在:nid'},ref 取 a.get('ref') 当且仅当它是 dict,否则若 node 非 None 用 refindex.ref_of(node),若 ref 仍为假返回 {'ok': False, 'error': '该节点没有 code_ref/doc_ref(不是索引节点)'},否则返回 refindex.read_ref(ref, root=a.get('root'), ref_kind=ref_kind) 的结果并设 out['node_id']=nid or None;其他 action 抛 ValueError;
|
|
2139
2766
|
def _ref_call(cg, a):
|
|
2140
2767
|
"""按 ref 回读被索引的源位置(认知图只存注释/接口,正文在这里取回)。
|
|
2141
2768
|
|
|
@@ -2204,39 +2831,57 @@ def _ref_call(cg, a):
|
|
|
2204
2831
|
return out
|
|
2205
2832
|
|
|
2206
2833
|
|
|
2834
|
+
# 生效条件:始终 import 白箱模块并返回 whitebox.dispatch(cg, a)。
|
|
2207
2835
|
def _whitebox_call(cg, a):
|
|
2208
2836
|
"""显式调用白箱能力库(AEIS 降为本地库后的唯一入口)。
|
|
2209
2837
|
|
|
2210
2838
|
显式调用映射:md_cg.whitebox.dispatch
|
|
2211
|
-
见 docs/功能调用映射表_v0.1.md。
|
|
2839
|
+
见 docs/mdcg/功能调用映射表_v0.1.md。
|
|
2212
2840
|
"""
|
|
2213
2841
|
from . import whitebox
|
|
2214
2842
|
return whitebox.dispatch(cg, a)
|
|
2215
2843
|
|
|
2216
2844
|
|
|
2845
|
+
# 生效条件:op=(a.get("op") or "").strip().lower();op=="relation" 时返回 stg.relation(cg, a.get("a",""), a.get("b",""));op=="timeline" 时返回 stg.timeline(cg, layer=a.get("layer"), limit=int(a.get("limit") or 50), desc=bool(a.get("desc", True)));op=="anchors" 时返回 stg.anchors(cg, time_window=a.get("time_window"), bbox=a.get("bbox"), layer=a.get("layer"), limit=int(a.get("limit") or 50));op=="consistency" 时返回 stg.consistency(cg, layer=a.get("layer"), limit=int(a.get("limit") or 50));op 为空或其它的值抛 ValueError。
|
|
2217
2846
|
def _stg_call(cg, a):
|
|
2218
|
-
"""语义时空图唯一入口。
|
|
2847
|
+
"""语义时空图唯一入口。
|
|
2848
|
+
|
|
2849
|
+
四个 op 均支持 `time_axis`:**缺省 `observed`**(与旧行为逐位一致;stg 的
|
|
2850
|
+
时间语义历来是观察轴),`effective` 走效力轴端点比较。此处与 `cg(op=read)`
|
|
2851
|
+
的透传策略**相反**——`cg` 侧缺省由库层定(不启用的时间算子),`stg` 侧轴
|
|
2852
|
+
决定「排序/关系依据」必须**恒有值**,故在此填默认;非法轴仍由
|
|
2853
|
+
`trust.time_axis_of` fail-closed 抛错(本层不预先白名单,避免两套枚举)。
|
|
2854
|
+
"""
|
|
2219
2855
|
from . import stg
|
|
2220
2856
|
op = (a.get("op") or "").strip().lower()
|
|
2857
|
+
axis = a.get("time_axis") or "observed"
|
|
2221
2858
|
if op == "relation":
|
|
2222
|
-
return stg.relation(cg, a.get("a", ""), a.get("b", ""))
|
|
2859
|
+
return stg.relation(cg, a.get("a", ""), a.get("b", ""), time_axis=axis)
|
|
2223
2860
|
if op == "timeline":
|
|
2224
2861
|
return stg.timeline(cg, layer=a.get("layer"),
|
|
2225
2862
|
limit=int(a.get("limit") or 50),
|
|
2226
|
-
desc=bool(a.get("desc", True)))
|
|
2863
|
+
desc=bool(a.get("desc", True)), time_axis=axis)
|
|
2227
2864
|
if op == "anchors":
|
|
2228
2865
|
return stg.anchors(cg, time_window=a.get("time_window"), bbox=a.get("bbox"),
|
|
2229
|
-
layer=a.get("layer"), limit=int(a.get("limit") or 50)
|
|
2866
|
+
layer=a.get("layer"), limit=int(a.get("limit") or 50),
|
|
2867
|
+
time_axis=axis)
|
|
2230
2868
|
if op == "consistency":
|
|
2231
2869
|
return stg.consistency(cg, layer=a.get("layer"),
|
|
2232
|
-
limit=int(a.get("limit") or 50))
|
|
2233
|
-
|
|
2870
|
+
limit=int(a.get("limit") or 50), time_axis=axis)
|
|
2871
|
+
if not op:
|
|
2872
|
+
# fail-closed 且给出可操作提示:stg 的 op 四值签名区分度低于 cg(relation 需
|
|
2873
|
+
# a+b、timeline/anchors/consistency 皆以 layer+limit 为主),**不做签名推导**
|
|
2874
|
+
# ——猜错会静默返回错误视图,比报错更贵。
|
|
2875
|
+
raise ValueError("stg 的 op 为必填参数(缺失即报错,不静默降级);"
|
|
2876
|
+
"允许 op:relation | timeline | anchors | consistency")
|
|
2877
|
+
raise ValueError(f"stg 未知 op:{op}(允许 relation | timeline | anchors | consistency)")
|
|
2234
2878
|
|
|
2235
2879
|
|
|
2236
2880
|
# --------------------------------------------------------------------------
|
|
2237
2881
|
# 工具实现
|
|
2238
2882
|
# --------------------------------------------------------------------------
|
|
2239
2883
|
|
|
2884
|
+
# 生效条件:a=args or {},unit=(a.get("as_unit") or "").strip();unit 为空或 cg.principal 为 None 时直接返回 _dispatch(cg,name,a);否则先 narrowed_principal(cg.principal, unit),TokenError 时返回 {"ok":False,"error":f"as_unit 非法:{e}"},成功则暂存 cg.principal、置为 narrowed、try 返回 _dispatch、finally 还原。
|
|
2240
2885
|
def call_tool(cg, name, args):
|
|
2241
2886
|
"""MCP tools/call 入口:按 `as_unit` 做**请求级身份收窄**(单进程多身份)。
|
|
2242
2887
|
|
|
@@ -2269,6 +2914,7 @@ def call_tool(cg, name, args):
|
|
|
2269
2914
|
cg.principal = saved
|
|
2270
2915
|
|
|
2271
2916
|
|
|
2917
|
+
# 生效条件:name 为已注册工具名之一(cg / stg / mdcg_whitebox / mdcg_service_info / mdcg_remember 等);未识别的 name 返回含 error 的响应字典而不抛异常,进程不因此中断;
|
|
2272
2918
|
def _dispatch(cg, name, args):
|
|
2273
2919
|
a = args or {}
|
|
2274
2920
|
if name == "cg":
|
|
@@ -2355,7 +3001,8 @@ def _dispatch(cg, name, args):
|
|
|
2355
3001
|
include_recent=bool(a.get("include_recent")),
|
|
2356
3002
|
recent_limit=int(a.get("recent_limit") or 10),
|
|
2357
3003
|
query_expand=_make_query_expand(a.get("expand")),
|
|
2358
|
-
session=a.get("session")
|
|
3004
|
+
session=a.get("session"),
|
|
3005
|
+
validity=a.get("validity"))
|
|
2359
3006
|
|
|
2360
3007
|
if name == "mdcg_search":
|
|
2361
3008
|
from . import refindex
|
|
@@ -2364,14 +3011,16 @@ def _dispatch(cg, name, args):
|
|
|
2364
3011
|
roles=tuple(a["roles"]) if a.get("roles") else None,
|
|
2365
3012
|
include_work=bool(a.get("include_work")),
|
|
2366
3013
|
pools=a.get("pools"),
|
|
2367
|
-
session=a.get("session")
|
|
3014
|
+
session=a.get("session"),
|
|
3015
|
+
validity=a.get("validity"))
|
|
2368
3016
|
return {"meta": meta,
|
|
2369
3017
|
"results": [{"node": _node_view(n), "score": s, "state": q.get("state"),
|
|
2370
3018
|
"reason": q.get("reason"), **refindex.ref_fields(n)}
|
|
2371
3019
|
for n, s, q in res]}
|
|
2372
3020
|
|
|
2373
3021
|
if name == "mdcg_get":
|
|
2374
|
-
return _node_view(cg.get(a.get("node_id", ""))
|
|
3022
|
+
return _node_view(cg.get(a.get("node_id", "")),
|
|
3023
|
+
offset=int(a.get("offset") or 0))
|
|
2375
3024
|
|
|
2376
3025
|
if name == "mdcg_reflect":
|
|
2377
3026
|
res, _ = cg.search(a.get("query", ""), k=int(a.get("k") or 10), record=False)
|
|
@@ -2396,10 +3045,18 @@ def _dispatch(cg, name, args):
|
|
|
2396
3045
|
a.get("goal", ""))}
|
|
2397
3046
|
|
|
2398
3047
|
if name == "mdcg_propose":
|
|
2399
|
-
|
|
2400
|
-
|
|
2401
|
-
|
|
2402
|
-
|
|
3048
|
+
pr = cg.propose(a.get("node_id", ""), a.get("content", ""), info=True,
|
|
3049
|
+
layer=a.get("layer") or "knowledge",
|
|
3050
|
+
tags=a.get("tags"), condition_space=a.get("condition_space"),
|
|
3051
|
+
**_proposal_extras(a))
|
|
3052
|
+
out = {"pid": pr["pid"], "dedup": bool(pr.get("dedup"))}
|
|
3053
|
+
if pr.get("dedup"):
|
|
3054
|
+
out["dup_of"] = pr["pid"]
|
|
3055
|
+
out["dup_status"] = pr.get("dup_status")
|
|
3056
|
+
out["hint"] = ("同内容提案已存在(pid=%s,状态=%s),幂等返回既有提案、"
|
|
3057
|
+
"未重复入队,无需重试"
|
|
3058
|
+
% (pr["pid"], pr.get("dup_status") or "pending"))
|
|
3059
|
+
return out
|
|
2403
3060
|
|
|
2404
3061
|
if name == "mdcg_review_list":
|
|
2405
3062
|
return {"pending": cg.review_list()}
|
|
@@ -2483,6 +3140,7 @@ def _dispatch(cg, name, args):
|
|
|
2483
3140
|
# JSON-RPC / stdio 主循环
|
|
2484
3141
|
# --------------------------------------------------------------------------
|
|
2485
3142
|
|
|
3143
|
+
# 生效条件:error 非 None 时 msg 含 "error"=error、否则含 "result"=result,随后向 sys.stdout 写 _j(msg)+"\n" 并 flush,无返回值。
|
|
2486
3144
|
def _reply(rid, result=None, error=None):
|
|
2487
3145
|
msg = {"jsonrpc": "2.0", "id": rid}
|
|
2488
3146
|
if error is not None:
|
|
@@ -2493,6 +3151,7 @@ def _reply(rid, result=None, error=None):
|
|
|
2493
3151
|
sys.stdout.flush()
|
|
2494
3152
|
|
|
2495
3153
|
|
|
3154
|
+
# 生效条件:os.environ.get("MDCG_SUSTAIN","1") 取值属 ("0","false","False") 时返回 None;否则以 name=os.environ.get("MDCG_SUSTAIN_NAME") or "md_cg"、各 interval=float(os.environ.get(...) or sustain.DEFAULT_*)(空串回落默认)、各 auto_* 取 os.environ.get 默认值且值属 ("0","false","False") 时为关,调 sustain.ensure_loop 后 lp.start() 并返回 lp。
|
|
2496
3155
|
def _start_sustain(cg):
|
|
2497
3156
|
"""启动常驻自维持循环(MDCG_SUSTAIN=0 关闭;间隔可用环境变量调)。"""
|
|
2498
3157
|
if os.environ.get("MDCG_SUSTAIN", "1") in ("0", "false", "False"):
|
|
@@ -2525,6 +3184,7 @@ def _start_sustain(cg):
|
|
|
2525
3184
|
return lp
|
|
2526
3185
|
|
|
2527
3186
|
|
|
3187
|
+
# 生效条件:s=str(s or "").strip();不以 "session-" 开头、或去前缀按 "-" 分组后长度不等于 [8,4,4,4,12]、或某组字符不都在 "0123456789abcdef" 时返回 False,三者皆过返回 True。
|
|
2528
3188
|
def _is_dsh_session(s: str) -> bool:
|
|
2529
3189
|
"""DSH 会话 id 形态判定:session-<8>-<4>-<4>-<4>-<12>(uuid4)。"""
|
|
2530
3190
|
s = str(s or "").strip()
|
|
@@ -2536,6 +3196,7 @@ def _is_dsh_session(s: str) -> bool:
|
|
|
2536
3196
|
return all(all(c in "0123456789abcdef" for c in g) for g in groups)
|
|
2537
3197
|
|
|
2538
3198
|
|
|
3199
|
+
# 生效条件:s=str(raw or "").strip();s 为空返回 "anonymous";非 DSH 形态返回 s;DSH 形态时以 root=os.environ.get("MDCG_DSH_SESSIONS_ROOT") or ~/.dsh/sessions 遍历条目,存在 root/<name>/s 目录则返回 s,os.listdir 抛 OSError 时返回 s,否则返回 "anonymous"。
|
|
2539
3200
|
def _normalize_session(raw):
|
|
2540
3201
|
"""会话 id 归一 + 轻校验(只影响归因,不影响写入)。
|
|
2541
3202
|
|
|
@@ -2563,6 +3224,7 @@ def _normalize_session(raw):
|
|
|
2563
3224
|
return "anonymous"
|
|
2564
3225
|
|
|
2565
3226
|
|
|
3227
|
+
# 生效条件:环境变量 MDCG_SESSION(优先)或 DSH_SESSION_ID 去空白后非空时把 p.session 设为 _normalize_session(raw),MDCG_HARNESS 去空白后非空时把 p.harness 设为该值,MDCG_UNIT 去空白后非空时把 p.unit 设为该值,三者均为空串或未设置时 p 的对应字段保持原值;
|
|
2566
3228
|
def _apply_attribution(p):
|
|
2567
3229
|
"""归因维度注入(嵌套身份:(harness, session)),**不参与授权**。
|
|
2568
3230
|
|
|
@@ -2583,6 +3245,7 @@ def _apply_attribution(p):
|
|
|
2583
3245
|
p.unit = unit
|
|
2584
3246
|
|
|
2585
3247
|
|
|
3248
|
+
# 生效条件:环境变量 MDCG_TOKEN 去空白后非空时经 verify_token(token, tenant=os.environ.get("MDCG_TENANT")) 构造——抛 TokenError 则返回 (None, f"令牌校验失败:{e}"),成功则返回 (_attach_theory(p), None);否则 MDCG_LEGACY_ENV_AUTH 值为 "1"/"true"/"True" 时按 MDCG_CAN_ADMIN/MDCG_CAN_WRITE 落到 designer/recorder/output 角色的 legacy_env 身份,两者都不满足时构造 can_write=False、can_admin=False、auth_mode="anonymous" 的 guest 身份,后两条路径同样返回 (_attach_theory(p), None);
|
|
2586
3249
|
def _build_principal():
|
|
2587
3250
|
"""构造 Principal(令牌优先,fail-closed)。返回 (principal, error)。
|
|
2588
3251
|
|
|
@@ -2633,6 +3296,7 @@ def _build_principal():
|
|
|
2633
3296
|
return _attach_theory(p), None
|
|
2634
3297
|
|
|
2635
3298
|
|
|
3299
|
+
# 生效条件:p 传入后调用 theory.ensure() 得到 st,把 p.theory_ok 置为 bool(st.get("theory_ok"))(缺键或假值均为 False,而非保留原值或 None),p.theory_version 置为 st.get("version")(缺键为 None),返回 p,且校验过程不抛异常;
|
|
2636
3300
|
def _attach_theory(p):
|
|
2637
3301
|
"""附加版本层状态(theory_ok / theory_version)。校验永不抛异常。
|
|
2638
3302
|
|
|
@@ -2645,6 +3309,7 @@ def _attach_theory(p):
|
|
|
2645
3309
|
return p
|
|
2646
3310
|
|
|
2647
3311
|
|
|
3312
|
+
# 生效条件:环境变量 MDCG_ROOT 非空且其 os.path.abspath 规范化后的 basename 小写不以 "_md_cg_" 开头、且 _build_principal() 返回的 err 为空时,构造 MdCGSecure(root, principal=principal, autoflush=1) 并对 sys.stdin 逐行 method 分派(initialize 回 protocolVersion=PROTOCOL_VERSION 与 SERVER_NAME/SERVER_VERSION,tools/list 回 tools_for_surface(),tools/call 经 call_tool 后回 content,shutdown 跳出循环),遍历结束后调用 sustain.stop_all() 与 cg.close() 并返回 0;MDCG_ROOT 为空或 basename 命中 "_md_cg_" 前缀返回 2,令牌校验失败返回 3;
|
|
2648
3313
|
def main():
|
|
2649
3314
|
root = os.environ.get("MDCG_ROOT")
|
|
2650
3315
|
if not root:
|
|
@@ -2664,6 +3329,24 @@ def main():
|
|
|
2664
3329
|
"[mdcg-mcp] 请指向主认知图目录(如仓库内 md_cg/)。\n")
|
|
2665
3330
|
return 2
|
|
2666
3331
|
from .mdcos import MdCGSecure
|
|
3332
|
+
# 数据面迁出插件包(issue #18 相邻问题):旧版把运行时数据与路径配置写在包内
|
|
3333
|
+
# `<pkg>/data`,pnpm 更新会连目录一起替换(实机实证 data/ 54 文件 → 0)。首启把
|
|
3334
|
+
# 「旧位置仍有货」的数据**复制**到用户级数据根——node 侧插件启动时已做过一次,
|
|
3335
|
+
# 这里是 python 独立使用(不经插件)时的同口径兜底。fail-safe:迁移只是增益,
|
|
3336
|
+
# 任何失败都不阻塞启动,但不静默(走 stderr)。
|
|
3337
|
+
try:
|
|
3338
|
+
from .datapath import migrate_legacy_data as _migrate_legacy
|
|
3339
|
+
_mig = _migrate_legacy()
|
|
3340
|
+
if _mig.get("ran"):
|
|
3341
|
+
sys.stderr.write(
|
|
3342
|
+
"[mdcg-mcp] 数据面已迁出插件包(旧位置只复制未删除):%s → %s"
|
|
3343
|
+
"(%d 项)\n" % (_mig["from"], _mig["to"], _mig["copied"]))
|
|
3344
|
+
elif _mig.get("failed"):
|
|
3345
|
+
sys.stderr.write("[mdcg-mcp] 数据面迁移部分失败(不阻塞启动):%s\n"
|
|
3346
|
+
% (_mig["failed"],))
|
|
3347
|
+
except Exception as _mig_exc: # 迁移故障不得影响服务可用性
|
|
3348
|
+
sys.stderr.write("[mdcg-mcp] 数据面迁移检查失败(不阻塞启动): %r\n"
|
|
3349
|
+
% (_mig_exc,))
|
|
2667
3350
|
principal, err = _build_principal()
|
|
2668
3351
|
if err:
|
|
2669
3352
|
sys.stderr.write(
|
|
@@ -2678,7 +3361,14 @@ def main():
|
|
|
2678
3361
|
_p_session = os.environ.get("MDCG_SESSION", "").strip()
|
|
2679
3362
|
if _p_session:
|
|
2680
3363
|
principal.session = _p_session
|
|
2681
|
-
|
|
3364
|
+
# 索引可见性(2026-09-16):autoflush=1 —— 逐条写入立即落分片日志
|
|
3365
|
+
# `_index_log/`。根因(第4条取证):默认 autoflush=64 且常驻进程不 close,
|
|
3366
|
+
# 单条写入在达阈值前**对其他进程不可见**(`_load_index` = 快照 + 分片日志
|
|
3367
|
+
# 重放;`_index.json` 只在 compact/rebuild 时重写),表现为「写入返回
|
|
3368
|
+
# committed=true 但第16条读回确认在跨进程读面上不可检索」。本参数是
|
|
3369
|
+
# server 级兜底:覆盖不经 writepipe 写链的路径(propose / remember_gated /
|
|
3370
|
+
# add_rejected 等);写链另有显式提交边界(writepipe._commit_visibility)。
|
|
3371
|
+
cg = MdCGSecure(root, principal=principal, autoflush=1)
|
|
2682
3372
|
# 外部验证器注入(**能力外置**):识图/实测/验收等能力不在认知图内,
|
|
2683
3373
|
# 由 MDCG_VERIFIER_MODULES(逗号分隔 import 路径)声明的外部模块注入,
|
|
2684
3374
|
# 通常位于私有运行时仓。加载失败不阻塞启动——失败原因写进 stderr 与
|
|
@@ -2688,6 +3378,42 @@ def main():
|
|
|
2688
3378
|
if _verifiers.get("loaded") or _verifiers.get("failed"):
|
|
2689
3379
|
sys.stderr.write("[mdcg-mcp] 外部验证器: loaded=%s failed=%s\n"
|
|
2690
3380
|
% (_verifiers.get("loaded"), _verifiers.get("failed")))
|
|
3381
|
+
# ③ 两段式对账:上个进程若被杀在「落盘前后」之间,账本里会留下「有意图
|
|
3382
|
+
# 无结果」的写入——启动即清账(内容确已落盘 → 补账 committed;没落上 →
|
|
3383
|
+
# 如实标记 interrupted)。失败**不阻塞启动**:对账是增益,不是服务前提,
|
|
3384
|
+
# 但必须上报(stderr),不静默。
|
|
3385
|
+
try:
|
|
3386
|
+
_rep = cg.reconcile_writes()
|
|
3387
|
+
if _rep.get("unpaired"):
|
|
3388
|
+
sys.stderr.write("[mdcg-mcp] 写入两段式对账: 未结清=%s 补账=%s "
|
|
3389
|
+
"中断=%s\n" % (_rep.get("unpaired"),
|
|
3390
|
+
_rep.get("committed"),
|
|
3391
|
+
_rep.get("interrupted")))
|
|
3392
|
+
except Exception as _exc: # 对账故障不得影响服务可用性
|
|
3393
|
+
sys.stderr.write("[mdcg-mcp] 两段式对账失败(不阻塞启动): %r\n"
|
|
3394
|
+
% (_exc,))
|
|
3395
|
+
# 进程自报(诊断设施,fail-safe):把「md_cg 实际加载源 + render 契约代际」
|
|
3396
|
+
# 落成 `<tempdir>/md_cg_servers/<pid>.json`,供 `scripts/mdcg_stale_servers.py`
|
|
3397
|
+
# 机械判定**活进程代际**。根因(第4条取证):原先只能比「进程启动时间 vs
|
|
3398
|
+
# md_cg/*.py 最新 mtime」,该判据有活体盲区——npm 副本进程启动于 11:37~11:39
|
|
3399
|
+
# 而源码 mtime 为 09:24,故 stale=False,却持插件包 0.4.8 的旧契约
|
|
3400
|
+
# `codeindex.render`,把全量重建成果刷回 old_synth(AGENTS.md §5 运维注记)。
|
|
3401
|
+
# 自报给的是**绝对事实**(进程自己报出实际加载源),不再依赖相对量推断。
|
|
3402
|
+
# 失败不阻塞启动:自报是增益,不是服务前提,但必须上报(stderr),不静默。
|
|
3403
|
+
try:
|
|
3404
|
+
from . import selfreport
|
|
3405
|
+
_sr = selfreport.report(tag="mcp_server")
|
|
3406
|
+
if _sr:
|
|
3407
|
+
sys.stderr.write(
|
|
3408
|
+
"[mdcg-mcp] 自报: source=%s render_version=%s\n"
|
|
3409
|
+
"[mdcg-mcp] 自报文件: %s\n"
|
|
3410
|
+
% (_sr.get("source_dir"), _sr.get("render_version"),
|
|
3411
|
+
_sr.get("self_report_path")))
|
|
3412
|
+
else:
|
|
3413
|
+
sys.stderr.write("[mdcg-mcp] 自报写入失败(不阻塞启动;"
|
|
3414
|
+
"该进程的代际将无法被外部机械判定)\n")
|
|
3415
|
+
except Exception as _exc: # noqa: BLE001 —— 自报不得阻塞启动
|
|
3416
|
+
sys.stderr.write("[mdcg-mcp] 自报异常(不阻塞启动): %r\n" % (_exc,))
|
|
2691
3417
|
_start_sustain(cg)
|
|
2692
3418
|
|
|
2693
3419
|
for line in sys.stdin:
|