@furongjun1999/dsh-memory 0.6.1 → 0.7.1
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 +49 -18
- package/docs/README.md +1 -0
- package/docs/eval/cons200_/345/206/262/347/252/201/346/243/200/346/265/213/351/200/211/351/235/242_/345/256/236/346/226/275/350/256/260/345/275/225_v1.0.md +223 -0
- package/docs/eval/cons200_/345/206/262/347/252/201/346/243/200/346/265/213/351/200/211/351/235/242_/345/256/236/346/226/275/350/256/260/345/275/225_v1.1.md +340 -0
- package/docs/eval/issue50_/345/205/203/346/225/260/346/215/256/351/200/217/344/274/240/344/270/216/345/205/234/345/272/225_/344/277/256/345/244/215/350/256/260/345/275/225_v1.0.md +437 -0
- package/docs/eval/issue50_/345/215/212/351/207/215/345/244/215/345/276/205/345/256/232/345/244/215/346/240/270_/344/277/256/345/244/215/350/256/260/345/275/225_v1.0.md +488 -0
- package/docs/eval/issue50_/345/276/205/345/256/232/345/244/215/346/240/270/345/205/245/351/230/237_/344/277/256/345/244/215/350/256/260/345/275/225_v1.0.md +428 -0
- package/docs/eval/issue50_/350/257/273/351/235/242/344/277/235/346/212/244/345/217/252/350/256/244/346/230/276/345/274/217/346/235/245/346/272/220_/344/277/256/345/244/215/350/256/260/345/275/225_v1.0.md +271 -0
- package/docs/eval/issue50_/351/207/215/350/246/201/345/272/246/345/220/214/346/272/220/344/270/216/344/277/235/346/212/244/350/257/255/344/271/211_/344/277/256/345/244/215/350/256/260/345/275/225_v1.0.md +306 -0
- package/docs/eval/issue51_/344/270/200/351/224/256/345/256/211/350/243/205/345/244/261/350/264/245_/345/275/222/345/261/236/345/210/244/345/256/232_v1.0.md +58 -0
- package/docs/eval/issue52_/346/235/241/344/273/266/345/205/210/350/241/214/344/270/216/346/210/252/346/226/255/345/217/257/350/247/202/346/265/213_/344/277/256/345/244/215/350/256/260/345/275/225_v1.0.md +360 -0
- package/docs/eval//344/270/211/346/241/243/350/207/252/346/262/273_/346/255/245/351/252/244/342/221/241/346/241/243/344/275/215/345/215/225/344/270/200/345/205/245/345/217/243_/350/220/275/347/240/201/350/256/260/345/275/225_v1.0.md +651 -0
- package/docs/eval//344/270/211/346/241/243/350/207/252/346/262/273_/346/255/245/351/252/244/342/221/242/345/217/230/346/233/264/345/215/225/344/270/216/345/233/236/346/273/232/345/216/237/350/257/255_/350/220/275/347/240/201/350/256/260/345/275/225_v1.0.md +439 -0
- package/docs/eval//344/270/211/346/241/243/350/207/252/346/262/273_/346/255/245/351/252/244/342/221/243/345/207/206/345/205/245/350/257/273/346/225/260_/350/220/275/347/240/201/350/256/260/345/275/225_v1.0.md +1337 -0
- package/docs/eval//344/270/211/346/241/243/350/207/252/346/262/273_/346/255/245/351/252/244/342/221/244/346/224/266/345/256/230/344/270/216/345/205/250/351/223/276/351/252/214/346/224/266_/350/220/275/347/240/201/350/256/260/345/275/225_v1.0.md +1817 -0
- package/docs/eval//345/207/272/350/264/247/351/235/242/345/206/222/347/203/237_/350/277/233/350/264/247/351/227/250/347/246/201_v1.0.md +460 -0
- package/docs/eval//345/217/221/345/270/20308_/350/207/252/350/277/255/344/273/243/344/270/216/347/235/241/347/234/240_/345/233/276/346/243/200/347/264/242/350/267/257/344/270/216/346/235/203/351/207/215_v1.0.md +97 -0
- package/docs/eval//345/217/221/345/270/20309_/346/243/200/347/264/242/351/235/242/344/270/211/346/211/271/346/224/266/345/217/243_v1.0.md +66 -0
- package/docs/eval//345/275/222/344/270/200/345/261/202/347/274/272/347/234/201/347/277/273/345/205/263_/344/277/256/345/244/215/350/256/260/345/275/225_v1.0.md +458 -0
- package/docs/eval//347/254/2543/345/261/202stg/347/273/223/346/236/204/347/264/242/345/274/225_/345/256/236/346/226/275/350/256/260/345/275/225_v1.0.md +250 -0
- package/docs/hive//346/243/200/347/264/242/347/256/227/346/263/225/345/217/243/345/276/204/345/257/271/347/205/247_v0.1.md +136 -11
- 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 +32 -2
- package/docs/mdcg/README/350/257/246/347/273/206/347/211/210_v0.4.10.md +88 -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 +40 -40
- package/docs/mdcg//345/217/221/345/270/203/351/227/250/347/246/201/351/223/276_v0.1.md +47 -11
- package/docs/mdcg//347/235/241/347/234/240/345/221/250/346/234/237_/350/277/220/347/273/264/345/211/215/346/217/220/344/270/216/347/273/264/346/212/244/346/214/207/345/215/227_v1.0.md +183 -0
- package/docs/plans/stg/346/235/241/344/273/266/345/214/226/344/270/216/347/273/223/346/236/204/347/264/242/345/274/225_/350/256/276/350/256/241_v0.1.md +124 -0
- package/docs/plans//347/235/241/347/234/240/344/270/216/350/207/252/350/277/255/344/273/243_/345/212/237/350/203/275/344/274/230/345/214/226/350/256/276/350/256/241_v0.4.md +547 -0
- package/docs/plans//350/256/260/345/277/206/350/207/252/345/244/204/347/220/206/344/270/211/346/241/243/350/207/252/346/262/273_/350/256/276/350/256/241_v0.2.md +207 -0
- package/md_cg/admission.py +718 -0
- package/md_cg/autonomy_modes.py +642 -0
- package/md_cg/bench_e2e_locomo_qa.py +11 -4
- package/md_cg/chain.py +47 -0
- package/md_cg/consistency.py +133 -8
- package/md_cg/forgetting.py +38 -6
- package/md_cg/freshness.py +527 -0
- package/md_cg/generation.py +409 -0
- package/md_cg/hotcache.py +4 -1
- package/md_cg/lifecycle.py +30 -2
- package/md_cg/mcp_server.py +191 -26
- package/md_cg/mdcg.py +594 -39
- package/md_cg/mdcos.py +869 -38
- package/md_cg/nodefile.py +74 -1
- package/md_cg/protect.py +79 -4
- package/md_cg/provenance.py +1 -1
- package/md_cg/review_cli.py +31 -2
- package/md_cg/rollback.py +411 -0
- package/md_cg/rollback_cli.py +104 -0
- package/md_cg/semantic/canonical.py +22 -0
- package/md_cg/semantic/unify.py +73 -22
- package/md_cg/semantic/unify_fixture.json +25 -0
- package/md_cg/sleep.py +1297 -0
- package/md_cg/stg.py +400 -50
- package/md_cg/stgidx.py +281 -0
- package/md_cg/sustain.py +146 -9
- package/md_cg/test_auto_defaults.py +424 -0
- package/md_cg/test_autonomy_admission.py +1098 -0
- package/md_cg/test_autonomy_modes.py +1972 -0
- package/md_cg/test_b1_auto_id_multiproc.py +7 -0
- package/md_cg/test_b1b2_write_face.py +7 -0
- package/md_cg/test_b3_merge_keeps_content.py +7 -0
- package/md_cg/test_boundary_hit.py +410 -0
- package/md_cg/test_cons200_scan_selection.py +791 -0
- package/md_cg/test_en_pipeline.py +22 -13
- package/md_cg/test_generation_guard.py +352 -0
- package/md_cg/test_h4_sustain_snapshot.py +14 -4
- package/md_cg/test_i50a_half_dup_defer.py +408 -0
- package/md_cg/test_i50b_defer_to_review_queue.py +545 -0
- package/md_cg/test_i50c_meta_passthrough.py +608 -0
- package/md_cg/test_i50d_importance_source.py +531 -0
- package/md_cg/test_i50e_readside_protection.py +656 -0
- package/md_cg/test_issue39_utf8_stdio.py +9 -1
- package/md_cg/test_issue52_scan_condition_first.py +677 -0
- package/md_cg/test_linkref.py +7 -0
- package/md_cg/test_mode_parity.py +1393 -0
- package/md_cg/test_mutation_rollback.py +805 -0
- package/md_cg/test_n204_n205_n226_n227_n228_n229_exit_gates.py +1 -1
- package/md_cg/test_n212_n213_n224_generation_gates.py +14 -8
- package/md_cg/test_n214_n215_n221_n222_write_face_gates.py +7 -0
- package/md_cg/test_n230_dirty_replay.py +375 -0
- package/md_cg/test_p2_mcp.py +8 -0
- package/md_cg/test_p2_six_elements.py +463 -0
- package/md_cg/test_p3_legacy_closure.py +433 -0
- package/md_cg/test_p4_freshness.py +680 -0
- package/md_cg/test_p8_subgraph_chain.py +14 -1
- package/md_cg/test_p9_forget_protect.py +7 -0
- package/md_cg/test_p9c_dedup_hints.py +7 -0
- package/md_cg/test_policy_required_ccg.py +5 -1
- package/md_cg/test_protocol.py +7 -0
- package/md_cg/test_rank_parity_score_mode.py +6 -0
- package/md_cg/test_semantic_canonical.py +5 -3
- package/md_cg/test_sleep.py +611 -0
- package/md_cg/test_sleep_p1.py +784 -0
- package/md_cg/test_stgidx_index_parity.py +1020 -0
- package/md_cg/test_time_core_lint.py +968 -0
- package/md_cg/test_unify_default_off.py +701 -0
- package/md_cg/test_unify_scope.py +182 -0
- package/md_cg/test_writelimit.py +36 -9
- package/md_cg/test_writepipe.py +5 -2
- package/md_cg/weights.py +15 -1
- package/md_cg/whitebox_kb/aeis_core/time_core.py +8 -0
- package/md_cg/writepipe.py +101 -2
- package/package.json +3 -2
- package/skills/plugin.json +1 -1
- package/utf8_boot.py +237 -0
package/md_cg/mcp_server.py
CHANGED
|
@@ -180,7 +180,9 @@ TOOLS = [
|
|
|
180
180
|
"「跳过超大、继续试更小的」在预算紧张时淘汰最有价值的详实条目。"
|
|
181
181
|
"会话开始或重要工作前调用。可选启用第 5 路模糊召回(分级隶属度)"
|
|
182
182
|
"与第 6 路条件语义路(条件结构驱动),并注入调用方 LLM 的查询"
|
|
183
|
-
"
|
|
183
|
+
"扩展词(索引侧始终白箱)。缺省另含第 7 路因果路(沿 edges 多跳)"
|
|
184
|
+
"与第 8 路时间路(时间邻近度)——按裁定「全进默认检索」缺省开,"
|
|
185
|
+
"可用 causal=false / temporal=false 单独关。",
|
|
184
186
|
"inputSchema": _s("", query=_p("string", "描述当前任务的查询", True),
|
|
185
187
|
budget_tokens=_p("integer", "token 预算(默认 1200)"),
|
|
186
188
|
max_item_tokens=_p("integer", "单条上限(默认 250);超限条目截断纳入。"
|
|
@@ -203,12 +205,22 @@ TOOLS = [
|
|
|
203
205
|
goal=_p("string", "当前目标(第 5 篇第 3 章):启用 goal 路给召回定向;"
|
|
204
206
|
"省略则自动取活跃目标"),
|
|
205
207
|
goal_path=_p("boolean", "启用目标定向路(默认否;给 goal 即自动启用)"),
|
|
208
|
+
causal=_p("boolean", "因果路(P3,设计稿 §6.2):以词法/实体命中"
|
|
209
|
+
"为种子沿 edges 多跳扩散,**缺省开**(全进默认"
|
|
210
|
+
"检索);传 false 单独关本路。无 edges 的库上"
|
|
211
|
+
"自然为空"),
|
|
212
|
+
temporal=_p("boolean", "时间路(P3,设计稿 §6.3):按时间邻近度"
|
|
213
|
+
"排序的排名项,核走 time_core.cred_factor;"
|
|
214
|
+
"**缺省开**;传 false 单独关本路。无时间算子/"
|
|
215
|
+
"区间时恒空"),
|
|
206
216
|
include_recent=_p("boolean", "是否附「近期事件」窗口(默认否)"),
|
|
207
217
|
recent_limit=_p("integer", "近期事件条数(默认 10)"),
|
|
208
218
|
fusion=_p("string", "融合模式:sum(经典 RRF,奖励多路共识)"
|
|
209
219
|
"| max(取各路最高贡献,不奖励共识)。"
|
|
210
220
|
"fuzzy=true 时缺省 max——实测 sum 会低估"
|
|
211
|
-
"「只有模糊路捞到」的目标,self@1 −10.1
|
|
221
|
+
"「只有模糊路捞到」的目标,self@1 −10.1%;"
|
|
222
|
+
"因果路(causal,缺省开)同为单路独有召回型,"
|
|
223
|
+
"故一并缺省 max")),
|
|
212
224
|
},
|
|
213
225
|
{
|
|
214
226
|
"name": "mdcg_search",
|
|
@@ -1567,6 +1579,7 @@ def _sustain_call(cg, a):
|
|
|
1567
1579
|
路线图「常驻服务:会话/心跳/自愈」。原则:诊断只读;自愈只碰派生物
|
|
1568
1580
|
(索引/临时文件/日志边界),永不删节点;缺密钥属于权限事实,只报告不修。
|
|
1569
1581
|
"""
|
|
1582
|
+
from . import sleep as _sleep
|
|
1570
1583
|
from . import sustain
|
|
1571
1584
|
act = (a.get("action") or "status").strip().lower()
|
|
1572
1585
|
name = a.get("name") or os.environ.get("MDCG_SUSTAIN_NAME") or "md_cg"
|
|
@@ -1627,16 +1640,27 @@ def _sustain_call(cg, a):
|
|
|
1627
1640
|
or sustain.DEFAULT_BEAT_INTERVAL),
|
|
1628
1641
|
heal_interval=float(a.get("heal_interval")
|
|
1629
1642
|
or sustain.DEFAULT_HEAL_INTERVAL),
|
|
1630
|
-
|
|
1643
|
+
# 四档 auto_* 一律经 sustain 的**单一真源读取器**(P0-2)——此处
|
|
1644
|
+
# 不得再写缺省字面量:op 路径原 `auto_tidy` 缺省 False 与 env 路径
|
|
1645
|
+
# 的 True 相反,同 (root,name) 走两条入口语义不一致。显式入参仍优先。
|
|
1646
|
+
auto_heal=sustain.auto_from_args("auto_heal", a),
|
|
1631
1647
|
scrub_interval=float(a.get("scrub_interval")
|
|
1632
1648
|
or sustain.DEFAULT_SCRUB_INTERVAL),
|
|
1633
|
-
auto_scrub=
|
|
1649
|
+
auto_scrub=sustain.auto_from_args("auto_scrub", a),
|
|
1634
1650
|
evolve_interval=float(a.get("evolve_interval")
|
|
1635
1651
|
or sustain.DEFAULT_EVOLVE_INTERVAL),
|
|
1636
|
-
auto_evolve=
|
|
1652
|
+
auto_evolve=sustain.auto_from_args("auto_evolve", a),
|
|
1637
1653
|
tidy_interval=float(a.get("tidy_interval")
|
|
1638
1654
|
or sustain.DEFAULT_TIDY_INTERVAL),
|
|
1639
|
-
auto_tidy=
|
|
1655
|
+
auto_tidy=sustain.auto_from_args("auto_tidy", a),
|
|
1656
|
+
# 第六档睡眠周期(§4.7):五个值一律经 `md_cg/sleep.py` 的**单一真源
|
|
1657
|
+
# 读取器**(此处不得再写缺省字面量,也不得再写 env 键名字面量——
|
|
1658
|
+
# 键名真源是 `sleep.SLEEP_ENV_KEYS`)。与 env 路径逐字同一组调用。
|
|
1659
|
+
sleep_interval=_sleep.sleep_interval(),
|
|
1660
|
+
auto_sleep=_sleep.sleep_enabled(),
|
|
1661
|
+
sleep_merge=_sleep.sleep_merge_mode(),
|
|
1662
|
+
sleep_window=_sleep.sleep_window(),
|
|
1663
|
+
sleep_scrub_apply=_sleep.sleep_scrub_apply())
|
|
1640
1664
|
return {"loop": lp.start().status()}
|
|
1641
1665
|
if act in ("stop", "down"):
|
|
1642
1666
|
lp = sustain.get_loop(cg, name)
|
|
@@ -2047,7 +2071,7 @@ def _task_call(cg, a):
|
|
|
2047
2071
|
return _t.list_tasks(cg, status=tstat or None, limit=a.get("limit"))
|
|
2048
2072
|
|
|
2049
2073
|
|
|
2050
|
-
# 生效条件: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;
|
|
2074
|
+
# 生效条件: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;fork:op=="forget" 的**删除**分支走 cg.forget_gated(三档自治批次②:档位判定在既有资格闸之后,变更确认档出变更单且不软删;restore 分支不变),op=="write" 经 writepipe 默认链(链尾 autonomy 档位闸);
|
|
2051
2075
|
def _cg_dispatch(cg, a):
|
|
2052
2076
|
"""认知图唯一入口的 op 分发主体。"""
|
|
2053
2077
|
op = (a.get("op") or "read").strip().lower()
|
|
@@ -2220,6 +2244,21 @@ def _cg_dispatch(cg, a):
|
|
|
2220
2244
|
h["write_policy"] = audit.unavailable_report(_pe)
|
|
2221
2245
|
h["theory"] = _th.check()
|
|
2222
2246
|
h["links"] = _lk.ls()
|
|
2247
|
+
# 代校验(纯增量,2026-09-30):长驻进程可被问「你现在这一代是不是盘面那一代」。
|
|
2248
|
+
# 根因(第4条取证):升级后长驻进程仍持有启动代模块,与升级后惰性导入的新代
|
|
2249
|
+
# 模块跨代混用(实测 cg 写入 ImportError: cannot import name 'mint_auto_id'
|
|
2250
|
+
# from 'md_cg.mdcg',而盘面正常)——盘面无从自证,须由进程自报。
|
|
2251
|
+
# 落点=generation.report()(单点):code_generation / disk_generation /
|
|
2252
|
+
# stale_on_disk / restart_required / hint。**纯增量**:既有键名、键值、
|
|
2253
|
+
# 嵌套结构一字不动(本行只追加五个新键,键名与既有键无冲突)。
|
|
2254
|
+
# 失败不得把 op=info 拖崩(同为诊断面契约):异常在此收口成不可用形状。
|
|
2255
|
+
from . import generation as _gen
|
|
2256
|
+
try:
|
|
2257
|
+
h.update(_gen.report())
|
|
2258
|
+
except Exception as _ge: # noqa: BLE001
|
|
2259
|
+
h.update({"code_generation": None, "disk_generation": None,
|
|
2260
|
+
"stale_on_disk": None, "restart_required": None,
|
|
2261
|
+
"hint": "代校验不可用:%s: %s" % (type(_ge).__name__, _ge)})
|
|
2223
2262
|
return h
|
|
2224
2263
|
|
|
2225
2264
|
if op == "route":
|
|
@@ -2369,8 +2408,11 @@ def _cg_dispatch(cg, a):
|
|
|
2369
2408
|
if op == "forget":
|
|
2370
2409
|
if (a.get("action") or "forget").strip().lower() == "restore":
|
|
2371
2410
|
return cg.restore(a.get("node_id", ""), force=bool(a.get("force")))
|
|
2372
|
-
|
|
2373
|
-
|
|
2411
|
+
# 三档自治批次②(设计 §三 D 删除):工具面经 forget_gated——档位判定在
|
|
2412
|
+
# 既有资格闸(not_found / protect.guard_forget)**之后**,变更确认档
|
|
2413
|
+
# 出变更单且不软删;库层 forget 语义不变(脚本通道不接,本批边界)。
|
|
2414
|
+
return cg.forget_gated(a.get("node_id", ""), a.get("reason", ""),
|
|
2415
|
+
override=bool(a.get("override")))
|
|
2374
2416
|
|
|
2375
2417
|
if op == "protect":
|
|
2376
2418
|
return _protect_call(cg, a)
|
|
@@ -3085,7 +3127,7 @@ def _whitebox_call(cg, a):
|
|
|
3085
3127
|
return whitebox.dispatch(cg, a)
|
|
3086
3128
|
|
|
3087
3129
|
|
|
3088
|
-
# 生效条件:op=(a.get("op") or "").strip().lower();op=="relation" 时返回 stg.relation(cg, a.get("a",""), a.get("b",""), time_axis=axis);op=="timeline" 时返回 stg.timeline(cg, layer=a.get("layer"), limit=int(a.get("limit") or 50), desc=bool(a.get("desc", True)), time_axis=axis, session=a.get("session"))(session 缺省不过滤读遍所有会话,"*" = 显式跨会话,其它值 = 本会话视图);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
|
|
3130
|
+
# 生效条件:op=(a.get("op") or "").strip().lower();op=="relation" 时返回 stg.relation(cg, a.get("a",""), a.get("b",""), time_axis=axis);op=="timeline" 时返回 stg.timeline(cg, layer=a.get("layer"), limit=int(a.get("limit") or 50), desc=bool(a.get("desc", True)), time_axis=axis, session=a.get("session"))(session 缺省不过滤读遍所有会话,"*" = 显式跨会话,其它值 = 本会话视图);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;返回体**原样透传**——stg 三接口的 truncated/scanned/kept/hint 读数与修正后的 count 语义(条件命中总数,issue #52)不经本层裁剪或改写,max_scan 本批不开显式入参。
|
|
3089
3131
|
def _stg_call(cg, a):
|
|
3090
3132
|
"""语义时空图唯一入口。
|
|
3091
3133
|
|
|
@@ -3094,6 +3136,13 @@ def _stg_call(cg, a):
|
|
|
3094
3136
|
的透传策略**相反**——`cg` 侧缺省由库层定(不启用的时间算子),`stg` 侧轴
|
|
3095
3137
|
决定「排序/关系依据」必须**恒有值**,故在此填默认;非法轴仍由
|
|
3096
3138
|
`trust.time_axis_of` fail-closed 抛错(本层不预先白名单,避免两套枚举)。
|
|
3139
|
+
|
|
3140
|
+
返回体**原样透传**(issue #52):timeline/anchors/consistency 新增的
|
|
3141
|
+
`truncated` / `scanned` / `kept` 读数与截断时的 `hint` 随返回值自动带出,
|
|
3142
|
+
本层不裁剪、不改写;`count` 语义已是**条件命中总数**(不再受索引切片影响,
|
|
3143
|
+
在役对照 `timeline(session=…)` 由 25 恢复为 229)。`max_scan` 本批不在
|
|
3144
|
+
MCP 面开显式入参(契约:数值不是修法——需要收窄时细化生效条件/
|
|
3145
|
+
不适用条件,或按设计稿建立条件索引)。
|
|
3097
3146
|
"""
|
|
3098
3147
|
from . import stg
|
|
3099
3148
|
op = (a.get("op") or "").strip().lower()
|
|
@@ -3229,7 +3278,26 @@ _MDCG_OP_REQUIRE = {
|
|
|
3229
3278
|
}
|
|
3230
3279
|
|
|
3231
3280
|
|
|
3232
|
-
#
|
|
3281
|
+
# 生效条件:四个布尔入参任意组合下无条件返回 "max"(当 use_fuzzy 或 use_semantic 或 use_goal 或 use_causal 任一为真)或 None(全为假);use_temporal 不参与判据;不做 IO、不看环境变量;
|
|
3282
|
+
def recall_fusion_default(use_fuzzy, use_semantic, use_goal, use_causal,
|
|
3283
|
+
use_temporal=False):
|
|
3284
|
+
"""`mdcg_recall` 的**缺省融合口径**判据(唯一单点,供守卫断言)。
|
|
3285
|
+
|
|
3286
|
+
P3-遗留 A(2026-10-01 补披露):`use_causal` **缺省 True** ⇒ 默认 recall 的
|
|
3287
|
+
融合口径由 `sum` 变成 **`max`**(影响**所有**默认召回调用,与库是否有边无关)。
|
|
3288
|
+
该口径符合设计稿 §6.2「因果路融合缺省 max」与既有先例表达式
|
|
3289
|
+
(fuzzy/semantic/goal 同款),故**保留**;本函数只把那个表达式从调用点提为
|
|
3290
|
+
**可断言的名字**——否则「缺省到底是 sum 还是 max」只能靠读表达式,
|
|
3291
|
+
静默漂移(少写一个 `or use_causal`)无守卫可抓。
|
|
3292
|
+
|
|
3293
|
+
`use_temporal` **刻意不入判据**:时间路是**排名项**(§6.3(e):与 S4 层级
|
|
3294
|
+
激活同类,不是单路独有召回型),它开着也不改变融合口径。
|
|
3295
|
+
"""
|
|
3296
|
+
return ("max" if (use_fuzzy or use_semantic or use_goal or use_causal)
|
|
3297
|
+
else None)
|
|
3298
|
+
|
|
3299
|
+
|
|
3300
|
+
# 生效条件:name 为已注册工具名之一(cg / stg / mdcg_whitebox / mdcg_service_info / mdcg_remember 等);name 属 _MDCG_OP_REQUIRE 且 cg.principal 具 require_op 属性时先 require_op(越权抛 AccessDenied),principal 为 None 或无该方法时跳过;cg 走 _cg_call、stg 走 _stg_call、whitebox 走 _whitebox_call;未识别的 name 返回含 error 的响应字典而不抛异常,进程不因此中断;mdcg_forget 走 cg.forget_gated(同 cg(op=forget) 的档位路径)、mdcg_remember 的非 gated 直写分支在同 id 覆写时先过 cg.write_qualify 再按档位判定(三档自治批次②);
|
|
3233
3301
|
def _dispatch(cg, name, args):
|
|
3234
3302
|
a = args or {}
|
|
3235
3303
|
# P1-1:mdcg_* 面的角色作用域闸(与 cg 工具的 require_op 同一语义——
|
|
@@ -3296,6 +3364,51 @@ def _dispatch(cg, name, args):
|
|
|
3296
3364
|
_prior_cov = (_forgetting.self_coverage(cg, _prior, _content)
|
|
3297
3365
|
if _prior is not None else None)
|
|
3298
3366
|
_dup = _forgetting.redundancy(cg, _content, layer=_layer, exclude=nid)
|
|
3367
|
+
# 三档自治批次②(设计 §三):本分支是**热写入路径的第二落点**(另两处 =
|
|
3368
|
+
# writepipe 链尾执行器、remember_gated)——同 id 已存在 ⇒ C 改写、
|
|
3369
|
+
# 不存在 ⇒ A 新增,判据复用 forgetting.prior_node(不另写一份存在性判据)。
|
|
3370
|
+
# 位置:既有 `if a.get("gated")` 分支之后、`cg.add` 之前(直写面没有别的
|
|
3371
|
+
# 资格闸;audit/限流属 gated 分支的链)。确认档 ⇒ 出单且不落盘。
|
|
3372
|
+
from . import autonomy_modes as _am
|
|
3373
|
+
_action = _am.C_REWRITE if _prior is not None else _am.A_ADD
|
|
3374
|
+
if _prior is not None:
|
|
3375
|
+
# 资格在先(纯加严):见 writepipe._gate_autonomy 同款注释——覆写的
|
|
3376
|
+
# 层闸/写保护闸在 cg.add 内部,档位闸不得抢在它们之前把拒绝变成入队。
|
|
3377
|
+
cg.write_qualify(nid, target_layer=_layer,
|
|
3378
|
+
override=bool(a.get("override")),
|
|
3379
|
+
actor=getattr(cg, "actor", None))
|
|
3380
|
+
_dec = _am.decide(_action)
|
|
3381
|
+
if _dec["decision"] != _am.ALLOW:
|
|
3382
|
+
_aut = {"mode": _dec["mode"], "action": _dec["action"],
|
|
3383
|
+
"action_name": _dec["action_name"],
|
|
3384
|
+
"decision": _dec["decision"]}
|
|
3385
|
+
if _dec["decision"] == _am.FORBID:
|
|
3386
|
+
return {"ok": False, "id": nid, "committed": False,
|
|
3387
|
+
"moved_to": "autonomy_forbidden",
|
|
3388
|
+
"error": "autonomy_forbid", "autonomy": _aut,
|
|
3389
|
+
"hint": _dec["hint"]}
|
|
3390
|
+
_meta = {k: a[k] for k in
|
|
3391
|
+
("tags", "condition_space", "verification_basis",
|
|
3392
|
+
"non_applicable_conditions", "derived_from", "relation",
|
|
3393
|
+
"role", "importance") if a.get(k) is not None}
|
|
3394
|
+
# 直写面的裁决参数(本分支的 add 会自己跑冲突闸):随单落进复现 meta,
|
|
3395
|
+
# 否则「确认后落盘」与「直接落盘」两条路径的判据不等价。
|
|
3396
|
+
_meta["consistency"] = bool(a.get("consistency", True))
|
|
3397
|
+
_meta["on_conflict"] = a.get("on_conflict") or "reject"
|
|
3398
|
+
_meta["override"] = bool(a.get("override"))
|
|
3399
|
+
_pay = _am.mutation_payload(
|
|
3400
|
+
_action, nid, after=_content,
|
|
3401
|
+
reason="mdcg_remember 直写(%s)" % _am.ACTION_NAMES[_action],
|
|
3402
|
+
primitive="add", meta=_meta)
|
|
3403
|
+
_pr = _am.propose_mutation(cg, _action, nid, payload=_pay,
|
|
3404
|
+
layer=_layer,
|
|
3405
|
+
sensitivity=a.get("sensitivity"),
|
|
3406
|
+
info=True)
|
|
3407
|
+
return {"ok": True, "id": nid, "committed": False,
|
|
3408
|
+
"moved_to": "review_queue", "pid": _pr["pid"],
|
|
3409
|
+
"mutation": _pay, "autonomy": _aut,
|
|
3410
|
+
"hint": "%s 本次未落盘:变更单已入审核队列(pid=%s,目标 %s)。"
|
|
3411
|
+
% (_dec["hint"], _pr["pid"], nid)}
|
|
3299
3412
|
written = cg.add(nid, _content, layer=_layer,
|
|
3300
3413
|
# B2:同上——落盘面丢字段=上游声明静默失效。
|
|
3301
3414
|
sensitivity=a.get("sensitivity"),
|
|
@@ -3332,7 +3445,16 @@ def _dispatch(cg, name, args):
|
|
|
3332
3445
|
use_fuzzy = bool(a.get("fuzzy"))
|
|
3333
3446
|
use_semantic = bool(a.get("semantic"))
|
|
3334
3447
|
use_goal = bool(a.get("goal_path") or a.get("goal"))
|
|
3335
|
-
|
|
3448
|
+
# P3(裁定 9「全进默认检索」):因果路(chain)/ 时间路(temporal)**进缺省集**,
|
|
3449
|
+
# 但**每路可单独关**——显式传 causal=false / temporal=false 即从本次调用剔除。
|
|
3450
|
+
# 未显式传(None)= 缺省进路;与既有 fuzzy/semantic/goal 的「显式启用」语义相反,
|
|
3451
|
+
# 这是刻意的非对称:这两路在无 edges / 无时间参数的库上自然为空,缺省开不产噪声。
|
|
3452
|
+
use_causal = a.get("causal")
|
|
3453
|
+
use_temporal = a.get("temporal")
|
|
3454
|
+
use_causal = True if use_causal is None else bool(use_causal)
|
|
3455
|
+
use_temporal = True if use_temporal is None else bool(use_temporal)
|
|
3456
|
+
if (use_fuzzy or use_semantic or use_goal
|
|
3457
|
+
or not use_causal or not use_temporal):
|
|
3336
3458
|
paths = ["lexical", "bucket", "entity", "graph"]
|
|
3337
3459
|
if use_fuzzy:
|
|
3338
3460
|
paths.append("fuzzy")
|
|
@@ -3340,13 +3462,22 @@ def _dispatch(cg, name, args):
|
|
|
3340
3462
|
paths.append("semantic")
|
|
3341
3463
|
if use_goal:
|
|
3342
3464
|
paths.append("goal")
|
|
3465
|
+
if use_causal:
|
|
3466
|
+
paths.append("chain")
|
|
3467
|
+
if use_temporal:
|
|
3468
|
+
paths.append("temporal")
|
|
3343
3469
|
paths = tuple(paths)
|
|
3344
3470
|
else:
|
|
3345
|
-
paths = None
|
|
3471
|
+
paths = None # 缺省六路(mdcos.search_rrf 的缺省集)
|
|
3346
3472
|
# fuzzy 路缺省用 max 融合:实测(memory-bench-1000,870 查询)sum 会把
|
|
3347
3473
|
# self@1 拉低 10.1%,因为求和奖励「多路共识」、低估「模糊路独有」的目标。
|
|
3348
3474
|
# semantic 路同理:条件结构命中常是「独有召回」,故一并缺省 max。
|
|
3349
|
-
|
|
3475
|
+
# P3:因果路按设计稿 §6.2「融合口径」同为**单路独有召回型**,照抄本条先例
|
|
3476
|
+
# 形态(同一表达式内追加条件,不另起第二套判据)。
|
|
3477
|
+
# P3-遗留 A(2026-10-01):表达式提为 `recall_fusion_default` 单点,
|
|
3478
|
+
# 使「缺省口径 = max」可被守卫直接断言(防静默漂移)。
|
|
3479
|
+
fusion = a.get("fusion") or recall_fusion_default(
|
|
3480
|
+
use_fuzzy, use_semantic, use_goal, use_causal)
|
|
3350
3481
|
# 默认单条上限从 mdcos 取(该模块只在 main() 里惰性导入,模块级没有名字,
|
|
3351
3482
|
# 直接引用 mdcos.DEFAULT_MAX_ITEM_TOKENS 会 NameError —— 故此处按需导入)。
|
|
3352
3483
|
from .mdcos import DEFAULT_MAX_ITEM_TOKENS as _DEFAULT_MAX_ITEM
|
|
@@ -3448,8 +3579,9 @@ def _dispatch(cg, name, args):
|
|
|
3448
3579
|
return {"records": cg.review_records(pid=a.get("pid"))}
|
|
3449
3580
|
|
|
3450
3581
|
if name == "mdcg_forget":
|
|
3451
|
-
|
|
3452
|
-
|
|
3582
|
+
# 三档自治批次②:与 cg(op=forget) 同一档位路径(forget_gated,见该分支注释)。
|
|
3583
|
+
return cg.forget_gated(a.get("node_id", ""), a.get("reason", ""),
|
|
3584
|
+
override=bool(a.get("override")))
|
|
3453
3585
|
|
|
3454
3586
|
if name == "mdcg_restore":
|
|
3455
3587
|
return cg.restore(a.get("node_id", ""), force=bool(a.get("force")))
|
|
@@ -3555,6 +3687,7 @@ def _start_sustain(cg):
|
|
|
3555
3687
|
"""启动常驻自维持循环(MDCG_SUSTAIN=0 关闭;间隔可用环境变量调)。"""
|
|
3556
3688
|
if os.environ.get("MDCG_SUSTAIN", "1") in ("0", "false", "False"):
|
|
3557
3689
|
return None
|
|
3690
|
+
from . import sleep as _sleep
|
|
3558
3691
|
from . import sustain
|
|
3559
3692
|
name = os.environ.get("MDCG_SUSTAIN_NAME") or "md_cg"
|
|
3560
3693
|
lp = sustain.ensure_loop(
|
|
@@ -3563,22 +3696,28 @@ def _start_sustain(cg):
|
|
|
3563
3696
|
or sustain.DEFAULT_BEAT_INTERVAL),
|
|
3564
3697
|
heal_interval=float(os.environ.get("MDCG_SUSTAIN_HEAL")
|
|
3565
3698
|
or sustain.DEFAULT_HEAL_INTERVAL),
|
|
3566
|
-
|
|
3567
|
-
|
|
3699
|
+
# 四档 auto_* 一律经 sustain 的**单一真源读取器**(P0-2):缺省值只在
|
|
3700
|
+
# `sustain.AUTO_DEFAULTS` 定义一处,此处不得再写字面量(含 env 键名——
|
|
3701
|
+
# 键名真源是 `sustain.AUTO_ENVS`)。整理巡检缺省开:确定性动作、
|
|
3702
|
+
# 永不删除节点(可逆可审计);opt-out `MDCG_AUTO_TIDY=0`。
|
|
3703
|
+
auto_heal=sustain.auto_from_env("auto_heal"),
|
|
3568
3704
|
scrub_interval=float(os.environ.get("MDCG_SCRUB_INTERVAL")
|
|
3569
3705
|
or sustain.DEFAULT_SCRUB_INTERVAL),
|
|
3570
|
-
auto_scrub=
|
|
3571
|
-
not in ("0", "false", "False"),
|
|
3706
|
+
auto_scrub=sustain.auto_from_env("auto_scrub"),
|
|
3572
3707
|
evolve_interval=float(os.environ.get("MDCG_EVOLVE_INTERVAL")
|
|
3573
3708
|
or sustain.DEFAULT_EVOLVE_INTERVAL),
|
|
3574
|
-
auto_evolve=
|
|
3575
|
-
not in ("0", "false", "False"),
|
|
3709
|
+
auto_evolve=sustain.auto_from_env("auto_evolve"),
|
|
3576
3710
|
tidy_interval=float(os.environ.get("MDCG_TIDY_INTERVAL")
|
|
3577
3711
|
or sustain.DEFAULT_TIDY_INTERVAL),
|
|
3578
|
-
|
|
3579
|
-
#
|
|
3580
|
-
|
|
3581
|
-
|
|
3712
|
+
auto_tidy=sustain.auto_from_env("auto_tidy"),
|
|
3713
|
+
# 第六档睡眠周期(§4.7):五个值一律经 `md_cg/sleep.py` 的**单一真源
|
|
3714
|
+
# 读取器**——键名真源是 `sleep.SLEEP_ENV_KEYS`、缺省真源是
|
|
3715
|
+
# `sleep.SLEEP_ENV_DEFAULTS`,本处(与 op 路径)都不得再写字面量。
|
|
3716
|
+
sleep_interval=_sleep.sleep_interval(),
|
|
3717
|
+
auto_sleep=_sleep.sleep_enabled(),
|
|
3718
|
+
sleep_merge=_sleep.sleep_merge_mode(),
|
|
3719
|
+
sleep_window=_sleep.sleep_window(),
|
|
3720
|
+
sleep_scrub_apply=_sleep.sleep_scrub_apply())
|
|
3582
3721
|
lp.start()
|
|
3583
3722
|
return lp
|
|
3584
3723
|
|
|
@@ -4109,6 +4248,32 @@ def main():
|
|
|
4109
4248
|
"该进程的代际将无法被外部机械判定)\n")
|
|
4110
4249
|
except Exception as _exc: # noqa: BLE001 —— 自报不得阻塞启动
|
|
4111
4250
|
sys.stderr.write("[mdcg-mcp] 自报异常(不阻塞启动): %r\n" % (_exc,))
|
|
4251
|
+
# 代校验(generation 单点,2026-09-30):stdio 服务**真正开始服务之前**,把盘面
|
|
4252
|
+
# 上所有「函数内延迟导入」在本进程的模块面上试解析一遍(导入目标模块 → getattr
|
|
4253
|
+
# 取名字)。根因(第4条取证):长驻进程只在模块首次导入时读盘,而 md_cg 内有
|
|
4254
|
+
# 大量写在函数里的延迟导入(AST 实测 328 处,相当一部分是为避开循环导入)——
|
|
4255
|
+
# 升级后旧代已载入模块与新代惰性模块跨代混用,实测表现为 cg 写入返回
|
|
4256
|
+
# `ImportError: cannot import name 'mint_auto_id' from 'md_cg.mdcg'` 而盘面完全
|
|
4257
|
+
# 正常(该延迟导入要到运行期才炸,且报错点离根因很远)。此处提前到启动期显式
|
|
4258
|
+
# 判一次:**名字缺失即拒绝启动**(fail-closed,消息自带「请重启常驻 MCP 进程」
|
|
4259
|
+
# 指引);外部可选模块缺失(不在盘面的可选降级面,如 whitebox_kb/aeis_core 的
|
|
4260
|
+
# 惰性身体面)非致命,但计数如实上报,不静默。
|
|
4261
|
+
# 调用点必须在**函数体内**:这些延迟导入里相当一部分是为避开循环导入才写在函数
|
|
4262
|
+
# 里的,本校验若放到模块顶层会把避环结构重新咬回来(同族守卫
|
|
4263
|
+
# md_cg/test_generation_guard.py 有 AST 断言钉死这一点)。
|
|
4264
|
+
try:
|
|
4265
|
+
from . import generation as _gen
|
|
4266
|
+
_dep = _gen.verify_delegations()
|
|
4267
|
+
except Exception as _dep_exc: # noqa: BLE001 —— 未通过即拒绝服务,不带病运行
|
|
4268
|
+
sys.stderr.write("[mdcg-mcp] 代校验未通过(拒绝启动,fail-closed):%s\n%s\n"
|
|
4269
|
+
% (type(_dep_exc).__name__, _dep_exc))
|
|
4270
|
+
return 4
|
|
4271
|
+
sys.stderr.write(
|
|
4272
|
+
"[mdcg-mcp] 代校验:延迟导入 %d 项 / 目标模块 %d 个 / 已解析 %d 项 / "
|
|
4273
|
+
"可选缺失 %d 项 · 代 %s\n"
|
|
4274
|
+
% (_dep.get("delegations"), _dep.get("target_modules"),
|
|
4275
|
+
_dep.get("resolved"), len(_dep.get("unavailable") or []),
|
|
4276
|
+
_gen.STARTUP_FINGERPRINT[:12]))
|
|
4112
4277
|
_start_sustain(cg)
|
|
4113
4278
|
|
|
4114
4279
|
for line in sys.stdin:
|