@furongjun1999/dsh-memory 0.4.8 → 0.4.10
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 +54 -26
- package/codebuddy/CODEBUDDY.md +196 -195
- 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/README.md +1 -1
- package/docs/discipline/harnesses.yaml +18 -7
- package/docs/discipline/templates/full.md.tmpl +4 -3
- 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/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/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/mdcg/README/350/257/246/347/273/206/347/211/210_v0.4.5.md +631 -625
- 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 +47 -45
- 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.4.md → 206_v0.5.md} +92 -4
- 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//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/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 +2 -2
- 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 +3 -3
- 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 +2 -2
- 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 -433
- 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/dsh/README.md +33 -0
- 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 +3 -0
- package/lib/hooks.js +17 -23
- 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 +40 -3
- package/lib/lib/mdcg_client.js +46 -22
- package/lib/lib/mutual.js +4 -4
- package/lib/lib/token_store.js +4 -5
- package/md_cg/audit.py +17 -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 +27 -1
- package/md_cg/bench_p0.py +4 -1
- package/md_cg/bench_progressive.py +13 -1
- 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 +12 -1
- package/md_cg/build_postings.py +73 -0
- package/md_cg/ccgc.py +67 -2
- 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 +69 -4
- package/md_cg/consistency.py +24 -1
- package/md_cg/consolidate.py +53 -2
- package/md_cg/corpus.py +4 -0
- 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 +29 -1
- 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 +23 -1
- package/md_cg/fsutil.py +18 -1
- package/md_cg/hotcache.py +214 -0
- package/md_cg/hyperedge.py +251 -0
- package/md_cg/identity.py +18 -1
- package/md_cg/insight.py +17 -1
- 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 +12 -1
- package/md_cg/linkref.py +281 -0
- package/md_cg/links.py +29 -1
- package/md_cg/mcp_server.py +362 -43
- package/md_cg/md_whitebox.py +53 -1
- package/md_cg/mdcg.py +1003 -27
- package/md_cg/mdcos.py +558 -36
- package/md_cg/metacognition.py +37 -2
- 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/__main__.py +3 -0
- package/md_cg/mreview/bundle.py +8 -0
- package/md_cg/mreview/candidates.py +9 -0
- package/md_cg/mreview/govern.py +21 -1
- package/md_cg/mreview/locate.py +34 -0
- package/md_cg/mreview/pipeline.py +29 -1
- package/md_cg/mreview/ruleset.py +16 -1
- package/md_cg/nodefile.py +233 -3
- package/md_cg/pooling.py +23 -1
- package/md_cg/postings.py +298 -0
- package/md_cg/predict.py +89 -9
- package/md_cg/progressive.py +3 -0
- package/md_cg/protect.py +14 -1
- 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 +47 -2
- 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 +63 -2
- package/md_cg/security.py +26 -1
- package/md_cg/self_state.py +64 -1
- package/md_cg/selfreport.py +151 -0
- package/md_cg/semantic/canonical.py +5 -0
- package/md_cg/semantic/en_normalizer.py +364 -355
- 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 +56 -1
- package/md_cg/tasks.py +26 -2
- 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_ccgc.py +10 -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_d_meta.py +412 -0
- package/md_cg/test_datapath_root.py +188 -0
- package/md_cg/test_gain_gate.py +47 -1
- package/md_cg/test_hot_cold.py +187 -0
- package/md_cg/test_hyperedge.py +245 -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 +108 -18
- package/md_cg/test_mr_m3.py +8 -1
- package/md_cg/test_p26_refindex.py +49 -20
- package/md_cg/test_p27_docindex.py +236 -2
- package/md_cg/test_p2_mcp.py +1 -1
- package/md_cg/test_p31_insight.py +24 -0
- 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 +8 -4
- 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 +59 -2
- package/md_cg/test_role_views.py +354 -0
- package/md_cg/test_subproc_encoding.py +188 -0
- package/md_cg/test_trust.py +361 -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 +5 -1
- package/md_cg/theory.py +16 -1
- package/md_cg/tokens.py +40 -8
- package/md_cg/tool_face.py +13 -2
- package/md_cg/trust.py +943 -0
- package/md_cg/twophase.py +12 -1
- package/md_cg/units.py +132 -10
- package/md_cg/vision_evidence.py +24 -1
- package/md_cg/weights.py +24 -1
- package/md_cg/whitebox.py +32 -1
- package/md_cg/whitebox_kb/data/verify_cache.json +21210 -365
- package/md_cg/whitebox_kb/data/verify_savings.jsonl +5078 -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 +18 -4
- package/md_cg/writepipe.py +178 -7
- 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 +17 -21
- package/src/index.ts +33 -6
- package/src/lib/datapath.ts +211 -13
- package/src/lib/mdcg_client.ts +64 -25
- package/src/lib/mutual.ts +411 -411
- package/src/lib/token_store.ts +4 -5
- package/zcode/AGENTS.md +196 -195
- package/zcode/README.md +4 -0
- package/md_cg/whitebox_kb/wisdom/wisdom-book-cloud.db-shm +0 -0
- package/md_cg/whitebox_kb/wisdom/wisdom-book-cloud.db-wal +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", "轨迹/信任的滚动窗口"),
|
|
@@ -579,28 +596,43 @@ KERNEL_TOOLS = [
|
|
|
579
596
|
"op=export:全库导出(action=graph|nodes|slice|stat;导出整库属管理"
|
|
580
597
|
"操作,一律 require_admin);"
|
|
581
598
|
"op=maintain:记忆维护(action=stat|history|importance|longterm|"
|
|
582
|
-
"prefeed|separate|rollback|backfill|cap|exempt|vision_evidence|refine
|
|
583
|
-
"及其 *_history
|
|
584
|
-
"
|
|
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 只出报表不改盘);"
|
|
585
603
|
"op=consolidate:离线固化(action=promote 提升 | induce 归纳 | "
|
|
586
604
|
"contextualize 语境化,及其 _rollback/_history;批量提升属管理操作,"
|
|
587
605
|
"一律 require_admin);"
|
|
588
606
|
"op=insight:洞察(action=window|record|verify|list|report|"
|
|
589
607
|
"reconstruct|learn|outlook|catalog|fork|branch_rewrite|branch_search|"
|
|
590
|
-
"branch_merge|branch_discard|branches;权限按 action 分档:只读放行、"
|
|
608
|
+
"branch_merge|branch_discard|branches|tickets;权限按 action 分档:只读放行、"
|
|
591
609
|
"条件记账与分支写需 can_write、落库 apply 与分支弃置需 admin);"
|
|
592
610
|
"op=ccg:CCG 六要素编译器(action=compile|review|attest|link|"
|
|
593
611
|
"recalibrate|units|catalog;入参统一在 ccg 对象里)。"
|
|
594
612
|
"把对话记录编译为六要素候选 → **编外复核**(裁定 A:编译者不得自证,"
|
|
595
613
|
"E041 机械拒绝)→ 落库;复核优先走蜂巢 reflect/verify 单元,"
|
|
596
|
-
"蜂巢不可用则提示配置,或显式 allow_degrade 降级 harness 端子代理。"
|
|
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 缺省效力轴**有意不同**,由库层单点校验。",
|
|
597
629
|
"inputSchema": _s("",
|
|
598
630
|
op=_p("string", "route|read|write|verify|review|protect|identity|"
|
|
599
631
|
"consistency|metacognition|self_state|evolution|sustain|"
|
|
600
632
|
"scrub|predict|causal|"
|
|
601
633
|
"forget|goal|task|recent|info|index_code|index_doc|ref|whitebox|"
|
|
602
634
|
"theory|link|session|ingest|export|maintain|consolidate|"
|
|
603
|
-
"insight|ccg|help", True),
|
|
635
|
+
"insight|ccg|status|edges|help", True),
|
|
604
636
|
ccg=_p("object", "CCG 六要素编译器入参:{action, node_id, dialog, marks, "
|
|
605
637
|
"slots, strict_spans, role, verdict, verifier, compiled_by, "
|
|
606
638
|
"evidence, slot_corrections, model, jobs, blocking, wait_s, "
|
|
@@ -619,11 +651,34 @@ KERNEL_TOOLS = [
|
|
|
619
651
|
meta=_p("object", "recent op:附加元数据"),
|
|
620
652
|
window=_p("integer", "recent op:滚动窗口大小(默认 200)"),
|
|
621
653
|
include_recent=_p("boolean", "read:是否附近期事件窗口(默认否)"),
|
|
622
|
-
limit=_p("integer", "goal/recent 的返回条数;read
|
|
654
|
+
limit=_p("integer", "goal/recent 的返回条数;read 的近期事件条数;"
|
|
655
|
+
"edges 分页条数(缺省 50、上限 500,0/负数报错不当「全部」)"),
|
|
623
656
|
node_id=_p("string", "节点 id"),
|
|
624
|
-
offset=_p("integer", "read 的续读起始行(1 基;传上次返回的 next_offset
|
|
657
|
+
offset=_p("integer", "read 的续读起始行(1 基;传上次返回的 next_offset);"
|
|
658
|
+
"edges 的分页偏移(排序后切片,默认 0)"),
|
|
625
659
|
content=_p("string", "write 的内容(建议含 CCG 5 要素注释)"),
|
|
626
|
-
content_kind=_p("string", "write 的内容类型:code|image_desc|text|permission|work_done|work_wip|ccg_marks"),
|
|
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 的缺省轴**——派生边只有记录时刻,无效力声明)"),
|
|
627
682
|
layer=_p("string", "层:anchor|structural|knowledge|contextual|self"),
|
|
628
683
|
tags=_p("array", "标签(cap:xxx 会作为 route 的建议能力名)"),
|
|
629
684
|
importance=_p("number", "重要性 0-1"),
|
|
@@ -647,6 +702,11 @@ KERNEL_TOOLS = [
|
|
|
647
702
|
non_applicable_conditions=_p("array", "不适用条件"),
|
|
648
703
|
context=_p("object", "当前情境"),
|
|
649
704
|
k=_p("integer", "返回条数(sustain pool_bench 亦用)"),
|
|
705
|
+
view=_p("string", "read/route 的角色化读取视图(第四阶段 6.1,缺省关):"
|
|
706
|
+
"main(主代理:结论与修正历史)|"
|
|
707
|
+
"verifier(验证端:判据面与环境陷阱)|"
|
|
708
|
+
"receipt(回执审计:命令与预期输出);"
|
|
709
|
+
"非法值库层报错(fail-closed)"),
|
|
650
710
|
budget_tokens=_p("integer", "read 的 token 预算"),
|
|
651
711
|
evidence=_p("string", "verify 的证据"),
|
|
652
712
|
verdict=_p("string", "verify 裁决:confirmed|weakened|falsified;"
|
|
@@ -657,7 +717,7 @@ KERNEL_TOOLS = [
|
|
|
657
717
|
marker=_p("string", "whitebox verify_encoding:唯一口令标记(缺省自动生成)"),
|
|
658
718
|
fact=_p("string", "whitebox verify_encoding:待编码事实"),
|
|
659
719
|
questions=_p("array", "whitebox verify_existing:探针问题列表"),
|
|
660
|
-
action=_p("string", "review: list|decide|rounds;forget: forget|restore;"
|
|
720
|
+
action=_p("string", "review: list|decide|rounds|stats;forget: forget|restore;"
|
|
661
721
|
"protect: stats|check|mark|snapshot|history|forgetting;"
|
|
662
722
|
"identity: observe|anchor|trait|profile|positions|catalog;"
|
|
663
723
|
"consistency: check|history|stats|catalog;"
|
|
@@ -691,9 +751,13 @@ KERNEL_TOOLS = [
|
|
|
691
751
|
"insight: window|record|verify|list|report|"
|
|
692
752
|
"reconstruct|learn|outlook|catalog|"
|
|
693
753
|
"fork|branch_rewrite|branch_search|"
|
|
694
|
-
"branch_merge|branch_discard|branches
|
|
754
|
+
"branch_merge|branch_discard|branches|"
|
|
755
|
+
"tickets;"
|
|
695
756
|
"分支六 act:node_ids/branch_id/note/content/"
|
|
696
|
-
"reason 按 act 取用(rewrite 传 node_id+content
|
|
757
|
+
"reason 按 act 取用(rewrite 传 node_id+content);"
|
|
758
|
+
"tickets:盲区→四类消解票据任务卡"
|
|
759
|
+
"(types=[research|prototype|grilling|task],"
|
|
760
|
+
"min_blindspot 资格线;apply=True 落库需 admin)"),
|
|
697
761
|
pid=_p("string", "review decide 的提案 id"),
|
|
698
762
|
decision=_p("string", "review 裁决:accept|reject|edit|merge"),
|
|
699
763
|
edits=_p("object", "review edit 的覆盖字段(不可含 verify)"),
|
|
@@ -732,6 +796,10 @@ KERNEL_TOOLS = [
|
|
|
732
796
|
session=_p("string", "read(search/recall 分支):会话归属过滤"
|
|
733
797
|
"(frontmatter.session;缺省不过滤);"
|
|
734
798
|
"sustain:会话 id(resume/note 用)"),
|
|
799
|
+
validity=_p("boolean", "read(search/recall 分支):时效过滤(显式启用,"
|
|
800
|
+
"缺省不过滤)——仅排除**已过期**(valid_until 已过)"
|
|
801
|
+
"节点;**未生效(valid_from 未到)保留**"
|
|
802
|
+
"(两者语义相反,预约/计划类记忆生效前仍可召回)"),
|
|
735
803
|
ts=_p("number", "sustain note:事件时间戳"),
|
|
736
804
|
seq=_p("integer", "sustain note:事件序号"),
|
|
737
805
|
task_running=_p("boolean", "sustain:任务执行中(心跳阈值放宽)"),
|
|
@@ -811,14 +879,22 @@ KERNEL_TOOLS = [
|
|
|
811
879
|
verdicts=_p("array", "maintain refine apply:人工核对裁决 "
|
|
812
880
|
"[{concept_id, faithful, added_info, note}];"
|
|
813
881
|
"缺省只落抽检留痕(不改节点)"),
|
|
814
|
-
batch=_p("string", "maintain/consolidate
|
|
882
|
+
batch=_p("string", "maintain/consolidate:批次号(回滚用);"
|
|
883
|
+
"edges:按派生边批次号过滤"),
|
|
815
884
|
derived_from=_p("string", "write/remember:派生来源节点 id(G8,可用逗号/空格"
|
|
816
885
|
"分隔多个);声明后写入 frontmatter 并建派生边"),
|
|
817
|
-
relation=_p("string", "write/remember/link derive
|
|
886
|
+
relation=_p("string", "write/remember/link derive/edges:派生关系名(**谓词**),"
|
|
818
887
|
"默认 derived_from(split_from|extracted_from|"
|
|
819
888
|
"merged_from|refined_from|source)"),
|
|
820
|
-
child=_p("string", "link derive:按子节点 id 过滤派生边"
|
|
821
|
-
|
|
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(默认否;只读索引快照)"),
|
|
822
898
|
ledger_only=_p("boolean", "link derive_dangling:只看台账、忽略索引声明"),
|
|
823
899
|
pools=_p("object", "search/sustain pool_bench:召回分池表"
|
|
824
900
|
"{knowledge:{cap_ratio,weight},index:{…},"
|
|
@@ -873,14 +949,17 @@ KERNEL_TOOLS = [
|
|
|
873
949
|
"description": "语义时空图接口:精确得到信息的时间/空间关系。"
|
|
874
950
|
"op=relation:两节点时空关系(Allen 时间 6 态 + RCC 空间 7 态);"
|
|
875
951
|
"op=timeline:按时间排序;op=anchors:落在时间窗/空间范围的节点;"
|
|
876
|
-
"op=consistency:时空字段自洽性检查。"
|
|
952
|
+
"op=consistency:时空字段自洽性检查。"
|
|
953
|
+
"四个 op 均可用 time_axis 切换时间轴(缺省 observed)。",
|
|
877
954
|
"inputSchema": _s("",
|
|
878
955
|
op=_p("string", "relation|timeline|anchors|consistency", True),
|
|
879
956
|
a=_p("string", "relation 的节点 a"), b=_p("string", "relation 的节点 b"),
|
|
880
957
|
time_window=_p("array", "anchors 的时间窗 [t1,t2]"),
|
|
881
958
|
bbox=_p("array", "anchors 的包围盒 [x1,y1,x2,y2]"),
|
|
882
959
|
layer=_p("string", "限定层"), limit=_p("integer", "返回条数"),
|
|
883
|
-
desc=_p("boolean", "timeline 是否倒序(默认是)")
|
|
960
|
+
desc=_p("boolean", "timeline 是否倒序(默认是)"),
|
|
961
|
+
time_axis=_p("string", "时间轴:observed(观察轴 temporal/time_window,"
|
|
962
|
+
"缺省)| effective(效力轴 effective_from/until)")),
|
|
884
963
|
},
|
|
885
964
|
]
|
|
886
965
|
|
|
@@ -888,6 +967,7 @@ ALL_TOOLS = KERNEL_TOOLS + TOOLS
|
|
|
888
967
|
SURFACE = os.environ.get("MDCG_MCP_SURFACE", "kernel").strip().lower()
|
|
889
968
|
|
|
890
969
|
|
|
970
|
+
# 生效条件:模块级 SURFACE 等于 "full" 时以 ALL_TOOLS、否则以 KERNEL_TOOLS 调 slim_tools 并返回其结果。
|
|
891
971
|
def tools_for_surface():
|
|
892
972
|
"""kernel:只暴露 2 个基元;full:2 个基元 + 31 个细粒度工具(兼容/调试)。
|
|
893
973
|
|
|
@@ -905,10 +985,12 @@ def tools_for_surface():
|
|
|
905
985
|
# 序列化
|
|
906
986
|
# --------------------------------------------------------------------------
|
|
907
987
|
|
|
988
|
+
# 生效条件:始终返回 json.dumps(obj, ensure_ascii=False, default=str)。
|
|
908
989
|
def _j(obj) -> str:
|
|
909
990
|
return json.dumps(obj, ensure_ascii=False, default=str)
|
|
910
991
|
|
|
911
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)。
|
|
912
994
|
def _pick_source(path):
|
|
913
995
|
"""按内容嗅探源类型:DSH 会话格式 vs 通用 JSONL。"""
|
|
914
996
|
from .sources import DSHSessionSource, JsonlSource
|
|
@@ -934,6 +1016,7 @@ READ_MAX_LINES = 2000 # 单次 read 返回行数上限(Pi⑦② 截
|
|
|
934
1016
|
READ_MAX_BYTES = 50 * 1024 # 单次 read 返回字节上限(Pi⑦② 截断)
|
|
935
1017
|
|
|
936
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。
|
|
937
1020
|
def _clip_text(text: str, *, offset: int = 0, max_lines: int = READ_MAX_LINES,
|
|
938
1021
|
max_bytes: int = READ_MAX_BYTES) -> dict:
|
|
939
1022
|
"""行窗口 + 双阈值截断(Pi⑦② 截断必带续读提示)。
|
|
@@ -971,12 +1054,24 @@ def _clip_text(text: str, *, offset: int = 0, max_lines: int = READ_MAX_LINES,
|
|
|
971
1054
|
return out
|
|
972
1055
|
|
|
973
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
|
+
|
|
974
1067
|
def _node_view(node, offset: int = 0):
|
|
975
1068
|
if not node:
|
|
976
1069
|
return None
|
|
977
1070
|
clip = _clip_text(node.get("content") or "", offset=offset)
|
|
978
1071
|
out = {"id": node.get("id"), "path": node.get("path"),
|
|
979
|
-
"frontmatter": node.get("frontmatter"), "content": clip["text"]
|
|
1072
|
+
"frontmatter": node.get("frontmatter"), "content": clip["text"],
|
|
1073
|
+
# 可验证记忆单元:读面 additive 透出验证态(**不改排序权重**,保基准)
|
|
1074
|
+
"verification_state": _trust_state(node.get("frontmatter"))}
|
|
980
1075
|
if clip["truncated"] or offset:
|
|
981
1076
|
out.update({"truncated": clip["truncated"],
|
|
982
1077
|
"content_lines": clip["total_lines"],
|
|
@@ -990,6 +1085,7 @@ def _node_view(node, offset: int = 0):
|
|
|
990
1085
|
# 基元实现
|
|
991
1086
|
# --------------------------------------------------------------------------
|
|
992
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;
|
|
993
1089
|
def _protect_call(cg, a):
|
|
994
1090
|
"""写保护 / 遗忘留痕的统一入口(cg op=protect 与 mdcg_protect 共用)。"""
|
|
995
1091
|
from . import protect
|
|
@@ -1017,6 +1113,7 @@ def _protect_call(cg, a):
|
|
|
1017
1113
|
raise ValueError(f"protect 未知 action:{act}")
|
|
1018
1114
|
|
|
1019
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;
|
|
1020
1117
|
def _identity_call(cg, a):
|
|
1021
1118
|
"""身份特征识别统一入口(cg op=identity 与 mdcg_identity 共用)。
|
|
1022
1119
|
|
|
@@ -1067,6 +1164,7 @@ def _identity_call(cg, a):
|
|
|
1067
1164
|
raise ValueError(f"identity 未知 action:{act}")
|
|
1068
1165
|
|
|
1069
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。
|
|
1070
1168
|
def _consistency_call(cg, a):
|
|
1071
1169
|
"""节点间自动冲突检测统一入口(cg op=consistency 与 mdcg_consistency 共用)。
|
|
1072
1170
|
|
|
@@ -1095,6 +1193,7 @@ def _consistency_call(cg, a):
|
|
|
1095
1193
|
raise ValueError(f"consistency 未知 action:{act}")
|
|
1096
1194
|
|
|
1097
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;
|
|
1098
1197
|
def _metacognition_call(cg, a):
|
|
1099
1198
|
"""独立元认知统一入口(cg op=metacognition 与 mdcg_metacognition 共用)。
|
|
1100
1199
|
|
|
@@ -1124,9 +1223,12 @@ def _metacognition_call(cg, a):
|
|
|
1124
1223
|
if act == "catalog":
|
|
1125
1224
|
from . import metacognition
|
|
1126
1225
|
return metacognition.catalog()
|
|
1226
|
+
if act == "d_meta": # D_meta 观测面(只读,不合成单值)
|
|
1227
|
+
return cg.metacognition_d_meta(window=window)
|
|
1127
1228
|
raise ValueError(f"metacognition 未知 action:{act}")
|
|
1128
1229
|
|
|
1129
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;
|
|
1130
1232
|
def _self_state_call(cg, a):
|
|
1131
1233
|
"""自我状态层统一入口(cg op=self_state 与 mdcg_self_state 共用)。
|
|
1132
1234
|
|
|
@@ -1188,6 +1290,7 @@ def _self_state_call(cg, a):
|
|
|
1188
1290
|
raise ValueError(f"self_state 未知 action:{act}")
|
|
1189
1291
|
|
|
1190
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。
|
|
1191
1294
|
def _predict_call(cg, a):
|
|
1192
1295
|
"""生成式预测统一入口(cg op=predict 与 mdcg_predict 共用)。
|
|
1193
1296
|
|
|
@@ -1221,6 +1324,7 @@ def _predict_call(cg, a):
|
|
|
1221
1324
|
raise ValueError(f"predict 未知 action:{act}")
|
|
1222
1325
|
|
|
1223
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;
|
|
1224
1328
|
def _causal_call(cg, a):
|
|
1225
1329
|
"""因果推理统一入口(cg op=causal 与 mdcg_causal 共用)。
|
|
1226
1330
|
|
|
@@ -1259,6 +1363,7 @@ def _causal_call(cg, a):
|
|
|
1259
1363
|
raise ValueError(f"causal 未知 action:{act}")
|
|
1260
1364
|
|
|
1261
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;
|
|
1262
1367
|
def _evolution_call(cg, a):
|
|
1263
1368
|
"""演化账本统一入口(cg op=evolution 与 mdcg_evolution 共用)。
|
|
1264
1369
|
|
|
@@ -1301,6 +1406,7 @@ def _evolution_call(cg, a):
|
|
|
1301
1406
|
raise ValueError(f"evolution 未知 action:{act}")
|
|
1302
1407
|
|
|
1303
1408
|
|
|
1409
|
+
# 生效条件:value 为 None 时返回 [],value 为 list/tuple/set 时按其元素、其它类型按 str(value).replace(",", " ").split() 取项,再对每项 str(x).strip(),非空且未出现过才按序追加并返回去重列表。
|
|
1304
1410
|
def _split_ids(value):
|
|
1305
1411
|
"""把 'a,b c' / ['a','b'] / 'a' 统一成去空白的 id 列表(None → [])。
|
|
1306
1412
|
|
|
@@ -1321,6 +1427,7 @@ def _split_ids(value):
|
|
|
1321
1427
|
return out
|
|
1322
1428
|
|
|
1323
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, [], '', {}) 的键值对。
|
|
1324
1431
|
def _proposal_extras(a, verdict=None):
|
|
1325
1432
|
"""入队时保全 write 的落盘要素,避免裁决 accept 后退化成默认值。
|
|
1326
1433
|
|
|
@@ -1348,6 +1455,7 @@ def _proposal_extras(a, verdict=None):
|
|
|
1348
1455
|
return {k: v for k, v in ex.items() if v not in (None, [], "", {})}
|
|
1349
1456
|
|
|
1350
1457
|
|
|
1458
|
+
# 生效条件:act 取 a.get("action") 转 str 去空白并 lower 后缺省 "status",name 取 a.get("name") 或环境变量 MDCG_SUSTAIN_NAME 或 "md_cg";status/info 只读诊断,自愈类 act 只回收派生物(索引重扫、临时分片、日志轮转、心跳戳),永不删除节点、不代签密钥;
|
|
1351
1459
|
def _sustain_call(cg, a):
|
|
1352
1460
|
"""持续性自维持统一入口(常驻 / 心跳 / 自愈 / 会话续接)。
|
|
1353
1461
|
|
|
@@ -1456,6 +1564,7 @@ def _sustain_call(cg, a):
|
|
|
1456
1564
|
raise ValueError(f"sustain 未知 action:{act}")
|
|
1457
1565
|
|
|
1458
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;
|
|
1459
1568
|
def _scrub_call(cg, a):
|
|
1460
1569
|
"""记忆自净统一入口(抽查 / 联想 / 去污染 / 校准偏差)。
|
|
1461
1570
|
|
|
@@ -1558,6 +1667,7 @@ _ACTION_DEFAULT = {
|
|
|
1558
1667
|
}
|
|
1559
1668
|
|
|
1560
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);
|
|
1561
1671
|
def _action_sig(a, op):
|
|
1562
1672
|
"""action 缺省时的签名推导 → (action, 依据键);无签名可依 → (None, None)。
|
|
1563
1673
|
|
|
@@ -1580,6 +1690,7 @@ def _action_sig(a, op):
|
|
|
1580
1690
|
return None, None
|
|
1581
1691
|
|
|
1582
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。
|
|
1583
1694
|
def _cg_call(cg, a):
|
|
1584
1695
|
"""认知图唯一入口(外层:op/action 缺省推导兜底 + 推导透出;主体见 _cg_dispatch)。"""
|
|
1585
1696
|
op0 = (a.get("op") or "").strip().lower()
|
|
@@ -1623,9 +1734,102 @@ def _cg_call(cg, a):
|
|
|
1623
1734
|
out["hint_action"] = (
|
|
1624
1735
|
"action 未显式传入,本次按 %s 的默认 action=%s 执行;"
|
|
1625
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__)
|
|
1626
1745
|
return out
|
|
1627
1746
|
|
|
1628
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)) 并返回其结果。
|
|
1629
1833
|
def _help_call(cg, a):
|
|
1630
1834
|
"""按需披露入口(工具面渐进披露的读取面,见 md_cg/tool_face.py)。
|
|
1631
1835
|
|
|
@@ -1638,6 +1842,7 @@ def _help_call(cg, a):
|
|
|
1638
1842
|
limit=int(a.get("limit") or a.get("k") or 40))
|
|
1639
1843
|
|
|
1640
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'));
|
|
1641
1846
|
def _task_call(cg, a):
|
|
1642
1847
|
"""结构层任务实体(op=task)——跨会话的工程台账。
|
|
1643
1848
|
|
|
@@ -1702,6 +1907,7 @@ def _task_call(cg, a):
|
|
|
1702
1907
|
return _t.list_tasks(cg, status=tstat or None, limit=a.get("limit"))
|
|
1703
1908
|
|
|
1704
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;
|
|
1705
1911
|
def _cg_dispatch(cg, a):
|
|
1706
1912
|
"""认知图唯一入口的 op 分发主体。"""
|
|
1707
1913
|
op = (a.get("op") or "read").strip().lower()
|
|
@@ -1711,6 +1917,12 @@ def _cg_dispatch(cg, a):
|
|
|
1711
1917
|
if _p is not None and hasattr(_p, "require_op"):
|
|
1712
1918
|
_p.require_op(op) # 角色作用域闸门:越权即 AccessDenied
|
|
1713
1919
|
|
|
1920
|
+
if op == "status":
|
|
1921
|
+
return _status_call(cg, a)
|
|
1922
|
+
|
|
1923
|
+
if op == "edges":
|
|
1924
|
+
return _edges_call(cg, a)
|
|
1925
|
+
|
|
1714
1926
|
if op == "theory":
|
|
1715
1927
|
from . import theory as _th
|
|
1716
1928
|
act = (a.get("action") or "check").strip().lower()
|
|
@@ -1857,7 +2069,8 @@ def _cg_dispatch(cg, a):
|
|
|
1857
2069
|
if op == "route":
|
|
1858
2070
|
intent = a.get("intent") or a.get("query") or ""
|
|
1859
2071
|
res, meta = cg.search(intent, k=int(a.get("k") or 10),
|
|
1860
|
-
context=a.get("context"), record=False
|
|
2072
|
+
context=a.get("context"), record=False,
|
|
2073
|
+
view=a.get("view"))
|
|
1861
2074
|
knowledge, caps = [], []
|
|
1862
2075
|
for n, s, q in res:
|
|
1863
2076
|
fm = n.get("frontmatter") or {}
|
|
@@ -1875,6 +2088,17 @@ def _cg_dispatch(cg, a):
|
|
|
1875
2088
|
"note": "认知图只给知识与建议能力名,不执行;由调用方决定"}
|
|
1876
2089
|
|
|
1877
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")}
|
|
1878
2102
|
if a.get("node_id"):
|
|
1879
2103
|
return _node_view(cg.get(a["node_id"]),
|
|
1880
2104
|
offset=int(a.get("offset") or 0))
|
|
@@ -1885,11 +2109,13 @@ def _cg_dispatch(cg, a):
|
|
|
1885
2109
|
goal_text=a.get("goal"),
|
|
1886
2110
|
include_recent=bool(a.get("include_recent")),
|
|
1887
2111
|
recent_limit=int(a.get("limit") or 10),
|
|
1888
|
-
session=a.get("session")
|
|
2112
|
+
session=a.get("session"),
|
|
2113
|
+
validity=a.get("validity"), **_tkw)
|
|
1889
2114
|
from . import refindex
|
|
1890
2115
|
res, meta = cg.search(q, layer=a.get("layer"), k=int(a.get("k") or 20),
|
|
1891
2116
|
context=a.get("context"),
|
|
1892
|
-
session=a.get("session")
|
|
2117
|
+
session=a.get("session"),
|
|
2118
|
+
validity=a.get("validity"), **_tkw)
|
|
1893
2119
|
return {"meta": meta, "results": [
|
|
1894
2120
|
{"node": _node_view(n), "score": s, "state": q2.get("state"),
|
|
1895
2121
|
"reason": q2.get("reason"), **refindex.ref_fields(n)}
|
|
@@ -1945,6 +2171,10 @@ def _cg_dispatch(cg, a):
|
|
|
1945
2171
|
act = (a.get("action") or "list").strip().lower()
|
|
1946
2172
|
if act == "list":
|
|
1947
2173
|
return {"pending": cg.review_list()}
|
|
2174
|
+
if act == "stats":
|
|
2175
|
+
# 裁决动作分布(含 noop):无此出口则「已评估、判定无需改动」这类
|
|
2176
|
+
# 裁决只在 jsonl 里躺着,治理面看不到——与「静默忽略」等价。
|
|
2177
|
+
return cg.review_stats()
|
|
1948
2178
|
if act == "rounds":
|
|
1949
2179
|
pid = a.get("pid", "")
|
|
1950
2180
|
return {"pid": pid, "rounds": cg.review_rounds(pid)}
|
|
@@ -2091,6 +2321,7 @@ def _cg_dispatch(cg, a):
|
|
|
2091
2321
|
raise ValueError(f"cg 未知 op:{op}")
|
|
2092
2322
|
|
|
2093
2323
|
|
|
2324
|
+
# 生效条件:由 _cg_dispatch 在 op=="ccg" 时进入;action 取 a.get("action") 缺省 "compile";compile 只产出候选(落 _ccgc_pending/ 待复核、不当场写库),link 才准入落库,attest/recalibrate 须编外验证方且 verifier != compiled_by(E041/E042/E043 机械把关);
|
|
2094
2325
|
def _ccg_call(cg, a):
|
|
2095
2326
|
"""CCG 六要素编译器(op=ccg):对话记录 → 六要素候选 → **编外复核** → 落库。
|
|
2096
2327
|
|
|
@@ -2261,6 +2492,7 @@ def _ccg_call(cg, a):
|
|
|
2261
2492
|
"units|catalog)" % act}
|
|
2262
2493
|
|
|
2263
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。
|
|
2264
2496
|
def _session_call(cg, a):
|
|
2265
2497
|
"""会话三件套(P0):note 写要点 / recall 续接 / compact 压摘要。
|
|
2266
2498
|
|
|
@@ -2299,6 +2531,7 @@ def _session_call(cg, a):
|
|
|
2299
2531
|
raise ValueError(f"session 未知 action:{act}(允许 note/recall/compact)")
|
|
2300
2532
|
|
|
2301
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"))).
|
|
2302
2535
|
def _prune_after_index(cg, a, *, kind, root, items, stats):
|
|
2303
2536
|
"""索引后的**节点级对账**:清退「同 root + 同 path 的过期代」。
|
|
2304
2537
|
|
|
@@ -2321,6 +2554,7 @@ def _prune_after_index(cg, a, *, kind, root, items, stats):
|
|
|
2321
2554
|
dry_run=bool(a.get("prune_dry_run")))
|
|
2322
2555
|
|
|
2323
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。
|
|
2324
2558
|
def _skip_dirs_report(stats, limit=20):
|
|
2325
2559
|
"""把「本次被 skip_dirs 排掉的目录」压成可审计字段。
|
|
2326
2560
|
|
|
@@ -2335,6 +2569,7 @@ def _skip_dirs_report(stats, limit=20):
|
|
|
2335
2569
|
return out
|
|
2336
2570
|
|
|
2337
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 并返回。
|
|
2338
2573
|
def _ingest_call(cg, a):
|
|
2339
2574
|
"""文件摄取分派(P0):file / dir / jsonl / stat。
|
|
2340
2575
|
|
|
@@ -2355,6 +2590,7 @@ def _ingest_call(cg, a):
|
|
|
2355
2590
|
max_events=a.get("max_events"))
|
|
2356
2591
|
|
|
2357
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 并返回。
|
|
2358
2594
|
def _export_call(cg, a):
|
|
2359
2595
|
"""全库导出(P0):graph / nodes / slice / stat。
|
|
2360
2596
|
|
|
@@ -2373,8 +2609,9 @@ def _export_call(cg, a):
|
|
|
2373
2609
|
include_content=True if inc is None else bool(inc))
|
|
2374
2610
|
|
|
2375
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。
|
|
2376
2613
|
def _maintain_call(cg, a):
|
|
2377
|
-
"""记忆维护(P1):importance / longterm / prefeed / separate / rollback / stat。
|
|
2614
|
+
"""记忆维护(P1):importance / longterm / prefeed / separate / rollback / stat / propagate。
|
|
2378
2615
|
|
|
2379
2616
|
权限**按 action 分档**(比整 op 收窄更贴合语义):
|
|
2380
2617
|
· 只读(stat / history / longterm mode=list|show)→ 不额外拦截;
|
|
@@ -2389,6 +2626,19 @@ def _maintain_call(cg, a):
|
|
|
2389
2626
|
apply = bool(a.get("apply"))
|
|
2390
2627
|
mode = str(a.get("mode") or "").strip().lower()
|
|
2391
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
|
|
2392
2642
|
if principal is not None and act == "rollback":
|
|
2393
2643
|
principal.require_admin("maintain_rollback")
|
|
2394
2644
|
if principal is not None and act in ("importance", "separate") and apply:
|
|
@@ -2437,6 +2687,7 @@ def _maintain_call(cg, a):
|
|
|
2437
2687
|
verdicts=a.get("verdicts"), reason=a.get("reason"))
|
|
2438
2688
|
|
|
2439
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 并返回。
|
|
2440
2691
|
def _consolidate_call(cg, a):
|
|
2441
2692
|
"""离线固化(P1):promote / promote_rollback / promote_history。
|
|
2442
2693
|
|
|
@@ -2461,18 +2712,20 @@ def _consolidate_call(cg, a):
|
|
|
2461
2712
|
actor=getattr(principal, "actor", None) if principal is not None else None)
|
|
2462
2713
|
|
|
2463
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 并返回。
|
|
2464
2716
|
def _insight_call(cg, a):
|
|
2465
2717
|
"""洞察(P2):window / record / verify / list / report / reconstruct / learn /
|
|
2466
2718
|
outlook / catalog / fork / branch_rewrite / branch_search / branch_merge /
|
|
2467
|
-
branch_discard / branches。
|
|
2719
|
+
branch_discard / branches / tickets。
|
|
2468
2720
|
|
|
2469
2721
|
权限**按 action 分档**(与 maintain 同构,比整 op 收窄更贴合语义):
|
|
2470
2722
|
· 只读(window / list / report / reconstruct 预演 / outlook / catalog /
|
|
2471
|
-
branch_search / branches / fork 预演)→ 不额外拦截;
|
|
2723
|
+
branch_search / branches / fork 预演 / tickets 预演)→ 不额外拦截;
|
|
2472
2724
|
· 条件层记账(record / verify)与分支写操作(fork / branch_rewrite /
|
|
2473
2725
|
branch_merge)→ 需 can_write;
|
|
2474
|
-
· 落库(reconstruct apply / learn apply
|
|
2475
|
-
|
|
2726
|
+
· 落库(reconstruct apply / learn apply / tickets apply 批量建卡)与
|
|
2727
|
+
分支弃置(branch_discard,改变库可见性)→ require_admin
|
|
2728
|
+
(discard 库层还有第二道闸)。
|
|
2476
2729
|
这样 output 角色能读洞察但不能记;reflect 能重构与学习预演;批量落库须请示。
|
|
2477
2730
|
"""
|
|
2478
2731
|
act = (a.get("action") or "outlook").strip().lower()
|
|
@@ -2485,8 +2738,9 @@ def _insight_call(cg, a):
|
|
|
2485
2738
|
if principal is not None and act in ("fork", "branch_rewrite",
|
|
2486
2739
|
"branch_merge") and not can_write:
|
|
2487
2740
|
principal.require_admin(f"insight_{act}") # 分支写 → 需写权
|
|
2488
|
-
if principal is not None and act in ("reconstruct", "learn"
|
|
2489
|
-
|
|
2741
|
+
if principal is not None and act in ("reconstruct", "learn",
|
|
2742
|
+
"tickets") and apply:
|
|
2743
|
+
principal.require_admin(f"insight_{act}") # 批量落库 → 需 admin
|
|
2490
2744
|
if principal is not None and act == "branch_discard":
|
|
2491
2745
|
principal.require_admin("branch_discard") # 弃置:分发层+库层双闸
|
|
2492
2746
|
return cg.insight(
|
|
@@ -2504,9 +2758,11 @@ def _insight_call(cg, a):
|
|
|
2504
2758
|
reason=a.get("reason"),
|
|
2505
2759
|
blindspot_id=a.get("blindspot_id"), horizon=a.get("horizon"),
|
|
2506
2760
|
max_branches=a.get("max_branches"), recent_days=a.get("recent_days"),
|
|
2507
|
-
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"))
|
|
2508
2763
|
|
|
2509
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;
|
|
2510
2766
|
def _ref_call(cg, a):
|
|
2511
2767
|
"""按 ref 回读被索引的源位置(认知图只存注释/接口,正文在这里取回)。
|
|
2512
2768
|
|
|
@@ -2575,6 +2831,7 @@ def _ref_call(cg, a):
|
|
|
2575
2831
|
return out
|
|
2576
2832
|
|
|
2577
2833
|
|
|
2834
|
+
# 生效条件:始终 import 白箱模块并返回 whitebox.dispatch(cg, a)。
|
|
2578
2835
|
def _whitebox_call(cg, a):
|
|
2579
2836
|
"""显式调用白箱能力库(AEIS 降为本地库后的唯一入口)。
|
|
2580
2837
|
|
|
@@ -2585,22 +2842,32 @@ def _whitebox_call(cg, a):
|
|
|
2585
2842
|
return whitebox.dispatch(cg, a)
|
|
2586
2843
|
|
|
2587
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。
|
|
2588
2846
|
def _stg_call(cg, a):
|
|
2589
|
-
"""语义时空图唯一入口。
|
|
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
|
+
"""
|
|
2590
2855
|
from . import stg
|
|
2591
2856
|
op = (a.get("op") or "").strip().lower()
|
|
2857
|
+
axis = a.get("time_axis") or "observed"
|
|
2592
2858
|
if op == "relation":
|
|
2593
|
-
return stg.relation(cg, a.get("a", ""), a.get("b", ""))
|
|
2859
|
+
return stg.relation(cg, a.get("a", ""), a.get("b", ""), time_axis=axis)
|
|
2594
2860
|
if op == "timeline":
|
|
2595
2861
|
return stg.timeline(cg, layer=a.get("layer"),
|
|
2596
2862
|
limit=int(a.get("limit") or 50),
|
|
2597
|
-
desc=bool(a.get("desc", True)))
|
|
2863
|
+
desc=bool(a.get("desc", True)), time_axis=axis)
|
|
2598
2864
|
if op == "anchors":
|
|
2599
2865
|
return stg.anchors(cg, time_window=a.get("time_window"), bbox=a.get("bbox"),
|
|
2600
|
-
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)
|
|
2601
2868
|
if op == "consistency":
|
|
2602
2869
|
return stg.consistency(cg, layer=a.get("layer"),
|
|
2603
|
-
limit=int(a.get("limit") or 50))
|
|
2870
|
+
limit=int(a.get("limit") or 50), time_axis=axis)
|
|
2604
2871
|
if not op:
|
|
2605
2872
|
# fail-closed 且给出可操作提示:stg 的 op 四值签名区分度低于 cg(relation 需
|
|
2606
2873
|
# a+b、timeline/anchors/consistency 皆以 layer+limit 为主),**不做签名推导**
|
|
@@ -2614,6 +2881,7 @@ def _stg_call(cg, a):
|
|
|
2614
2881
|
# 工具实现
|
|
2615
2882
|
# --------------------------------------------------------------------------
|
|
2616
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 还原。
|
|
2617
2885
|
def call_tool(cg, name, args):
|
|
2618
2886
|
"""MCP tools/call 入口:按 `as_unit` 做**请求级身份收窄**(单进程多身份)。
|
|
2619
2887
|
|
|
@@ -2646,6 +2914,7 @@ def call_tool(cg, name, args):
|
|
|
2646
2914
|
cg.principal = saved
|
|
2647
2915
|
|
|
2648
2916
|
|
|
2917
|
+
# 生效条件:name 为已注册工具名之一(cg / stg / mdcg_whitebox / mdcg_service_info / mdcg_remember 等);未识别的 name 返回含 error 的响应字典而不抛异常,进程不因此中断;
|
|
2649
2918
|
def _dispatch(cg, name, args):
|
|
2650
2919
|
a = args or {}
|
|
2651
2920
|
if name == "cg":
|
|
@@ -2732,7 +3001,8 @@ def _dispatch(cg, name, args):
|
|
|
2732
3001
|
include_recent=bool(a.get("include_recent")),
|
|
2733
3002
|
recent_limit=int(a.get("recent_limit") or 10),
|
|
2734
3003
|
query_expand=_make_query_expand(a.get("expand")),
|
|
2735
|
-
session=a.get("session")
|
|
3004
|
+
session=a.get("session"),
|
|
3005
|
+
validity=a.get("validity"))
|
|
2736
3006
|
|
|
2737
3007
|
if name == "mdcg_search":
|
|
2738
3008
|
from . import refindex
|
|
@@ -2741,7 +3011,8 @@ def _dispatch(cg, name, args):
|
|
|
2741
3011
|
roles=tuple(a["roles"]) if a.get("roles") else None,
|
|
2742
3012
|
include_work=bool(a.get("include_work")),
|
|
2743
3013
|
pools=a.get("pools"),
|
|
2744
|
-
session=a.get("session")
|
|
3014
|
+
session=a.get("session"),
|
|
3015
|
+
validity=a.get("validity"))
|
|
2745
3016
|
return {"meta": meta,
|
|
2746
3017
|
"results": [{"node": _node_view(n), "score": s, "state": q.get("state"),
|
|
2747
3018
|
"reason": q.get("reason"), **refindex.ref_fields(n)}
|
|
@@ -2869,6 +3140,7 @@ def _dispatch(cg, name, args):
|
|
|
2869
3140
|
# JSON-RPC / stdio 主循环
|
|
2870
3141
|
# --------------------------------------------------------------------------
|
|
2871
3142
|
|
|
3143
|
+
# 生效条件:error 非 None 时 msg 含 "error"=error、否则含 "result"=result,随后向 sys.stdout 写 _j(msg)+"\n" 并 flush,无返回值。
|
|
2872
3144
|
def _reply(rid, result=None, error=None):
|
|
2873
3145
|
msg = {"jsonrpc": "2.0", "id": rid}
|
|
2874
3146
|
if error is not None:
|
|
@@ -2879,6 +3151,7 @@ def _reply(rid, result=None, error=None):
|
|
|
2879
3151
|
sys.stdout.flush()
|
|
2880
3152
|
|
|
2881
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。
|
|
2882
3155
|
def _start_sustain(cg):
|
|
2883
3156
|
"""启动常驻自维持循环(MDCG_SUSTAIN=0 关闭;间隔可用环境变量调)。"""
|
|
2884
3157
|
if os.environ.get("MDCG_SUSTAIN", "1") in ("0", "false", "False"):
|
|
@@ -2911,6 +3184,7 @@ def _start_sustain(cg):
|
|
|
2911
3184
|
return lp
|
|
2912
3185
|
|
|
2913
3186
|
|
|
3187
|
+
# 生效条件:s=str(s or "").strip();不以 "session-" 开头、或去前缀按 "-" 分组后长度不等于 [8,4,4,4,12]、或某组字符不都在 "0123456789abcdef" 时返回 False,三者皆过返回 True。
|
|
2914
3188
|
def _is_dsh_session(s: str) -> bool:
|
|
2915
3189
|
"""DSH 会话 id 形态判定:session-<8>-<4>-<4>-<4>-<12>(uuid4)。"""
|
|
2916
3190
|
s = str(s or "").strip()
|
|
@@ -2922,6 +3196,7 @@ def _is_dsh_session(s: str) -> bool:
|
|
|
2922
3196
|
return all(all(c in "0123456789abcdef" for c in g) for g in groups)
|
|
2923
3197
|
|
|
2924
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"。
|
|
2925
3200
|
def _normalize_session(raw):
|
|
2926
3201
|
"""会话 id 归一 + 轻校验(只影响归因,不影响写入)。
|
|
2927
3202
|
|
|
@@ -2949,6 +3224,7 @@ def _normalize_session(raw):
|
|
|
2949
3224
|
return "anonymous"
|
|
2950
3225
|
|
|
2951
3226
|
|
|
3227
|
+
# 生效条件:环境变量 MDCG_SESSION(优先)或 DSH_SESSION_ID 去空白后非空时把 p.session 设为 _normalize_session(raw),MDCG_HARNESS 去空白后非空时把 p.harness 设为该值,MDCG_UNIT 去空白后非空时把 p.unit 设为该值,三者均为空串或未设置时 p 的对应字段保持原值;
|
|
2952
3228
|
def _apply_attribution(p):
|
|
2953
3229
|
"""归因维度注入(嵌套身份:(harness, session)),**不参与授权**。
|
|
2954
3230
|
|
|
@@ -2969,6 +3245,7 @@ def _apply_attribution(p):
|
|
|
2969
3245
|
p.unit = unit
|
|
2970
3246
|
|
|
2971
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);
|
|
2972
3249
|
def _build_principal():
|
|
2973
3250
|
"""构造 Principal(令牌优先,fail-closed)。返回 (principal, error)。
|
|
2974
3251
|
|
|
@@ -3019,6 +3296,7 @@ def _build_principal():
|
|
|
3019
3296
|
return _attach_theory(p), None
|
|
3020
3297
|
|
|
3021
3298
|
|
|
3299
|
+
# 生效条件:p 传入后调用 theory.ensure() 得到 st,把 p.theory_ok 置为 bool(st.get("theory_ok"))(缺键或假值均为 False,而非保留原值或 None),p.theory_version 置为 st.get("version")(缺键为 None),返回 p,且校验过程不抛异常;
|
|
3022
3300
|
def _attach_theory(p):
|
|
3023
3301
|
"""附加版本层状态(theory_ok / theory_version)。校验永不抛异常。
|
|
3024
3302
|
|
|
@@ -3031,6 +3309,7 @@ def _attach_theory(p):
|
|
|
3031
3309
|
return p
|
|
3032
3310
|
|
|
3033
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;
|
|
3034
3313
|
def main():
|
|
3035
3314
|
root = os.environ.get("MDCG_ROOT")
|
|
3036
3315
|
if not root:
|
|
@@ -3050,6 +3329,24 @@ def main():
|
|
|
3050
3329
|
"[mdcg-mcp] 请指向主认知图目录(如仓库内 md_cg/)。\n")
|
|
3051
3330
|
return 2
|
|
3052
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,))
|
|
3053
3350
|
principal, err = _build_principal()
|
|
3054
3351
|
if err:
|
|
3055
3352
|
sys.stderr.write(
|
|
@@ -3095,6 +3392,28 @@ def main():
|
|
|
3095
3392
|
except Exception as _exc: # 对账故障不得影响服务可用性
|
|
3096
3393
|
sys.stderr.write("[mdcg-mcp] 两段式对账失败(不阻塞启动): %r\n"
|
|
3097
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,))
|
|
3098
3417
|
_start_sustain(cg)
|
|
3099
3418
|
|
|
3100
3419
|
for line in sys.stdin:
|