@furongjun1999/dsh-memory 0.7.3 → 0.7.5
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 +631 -629
- package/codebuddy/CODEBUDDY.md +5 -5
- package/docs/discipline/templates/zcode-user.md.tmpl +4 -1
- package/docs/eval//345/217/221/345/270/20312_/344/270/226/347/225/214/346/250/241/345/236/213/345/212/237/350/203/275/347/253/257_v1.0.md +108 -0
- package/docs/eval//345/217/221/345/270/20313_/344/270/212/344/270/213/346/226/207/350/207/252/347/256/241/347/220/206/346/234/272/345/210/266_v1.0.md +114 -0
- package/docs/eval//350/257/255/344/271/211/346/227/266/347/251/272/345/233/276/350/241/245/345/205/250_P1_/346/212/275/345/217/226/345/231/250v4_/344/270/211/347/216/207/350/257/273/346/225/260_v1.0.md +231 -0
- package/docs/mdcg//344/270/226/347/225/214/346/250/241/345/236/213/345/212/237/350/203/275/347/253/257_/344/275/277/347/224/250/344/270/216/350/277/220/347/273/264_v1.0.md +305 -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 +45 -43
- 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 +80 -1
- package/docs/plans//347/201/265/346/236/242/350/272/253/344/275/223/303/227/350/204/221_/344/270/226/347/225/214/346/250/241/345/236/213/345/257/271/346/216/245/350/256/276/350/256/241_v0.1.md +76 -0
- package/docs//345/267/245/344/275/234/347/272/252/345/276/213_/350/256/244/347/237/245/345/233/276/346/235/241/347/233/256_v1.1.json +461 -461
- package/docs//350/256/260/345/277/206/347/263/273/347/273/237/345/215/263/347/231/275/347/256/261/345/214/226/346/231/272/350/203/275_/346/236/266/346/236/204/345/257/271/347/205/247_v0.2.md +121 -0
- package/docs//350/256/260/345/277/206/347/263/273/347/273/237/345/215/263/347/231/275/347/256/261/345/214/226/346/231/272/350/203/275_/346/236/266/346/236/204/345/257/271/347/205/247_v0.3.md +117 -0
- package/lib/hooks.d.ts +34 -0
- package/lib/hooks.js +205 -18
- package/lib/index.js +22 -1
- package/lib/lib/mdcg_client.d.ts +37 -0
- package/lib/lib/mdcg_client.js +44 -0
- package/lib/lib/session_state.d.ts +56 -0
- package/lib/lib/session_state.js +124 -0
- package/lib/tools.js +12 -1
- package/md_cg/audit.py +7 -1
- package/md_cg/bench_governance.py +4 -1
- package/md_cg/bench_locomo_zh.py +12 -2
- package/md_cg/bench_zh_mad.py +12 -2
- package/md_cg/interop.py +25 -9
- package/md_cg/lifecycle.py +38 -0
- package/md_cg/mcp_server.py +64 -11
- package/md_cg/mdcos.py +78 -9
- package/md_cg/sleep.py +223 -103
- package/md_cg/state_slots.py +221 -0
- package/md_cg/stg.py +68 -3
- package/md_cg/sustain.py +150 -4
- package/md_cg/test_lifecycle_retire_leak.py +408 -0
- package/md_cg/test_read_face_semantics.py +6 -3
- package/md_cg/test_state_event_op.py +514 -0
- package/md_cg/test_state_slots.py +691 -0
- package/md_cg/test_sustain_bounded.py +624 -0
- package/md_cg/tokens.py +8 -1
- package/md_cg/units.py +4 -1
- package/package.json +1 -1
- package/skills/plugin.json +1 -1
- package/src/hooks.ts +217 -17
- package/src/index.ts +22 -1
- package/src/lib/mdcg_client.ts +48 -0
- package/src/lib/session_state.ts +127 -0
- package/src/tools.ts +12 -1
- package/zcode/AGENTS.md +5 -5
package/md_cg/mcp_server.py
CHANGED
|
@@ -727,12 +727,16 @@ KERNEL_TOOLS = [
|
|
|
727
727
|
"(offset/limit)、**分页前全集**聚合(aggregation=by_relation|"
|
|
728
728
|
"by_parent|by_child)、端点索引摘要(expand_nodes=true)。"
|
|
729
729
|
"时间条件缺省走**观察轴**(派生边只有写入时刻 t,无效力声明)"
|
|
730
|
-
"——与 op=read 缺省效力轴**有意不同**,由库层单点校验。"
|
|
730
|
+
"——与 op=read 缺省效力轴**有意不同**,由库层单点校验。"
|
|
731
|
+
"op=state_event:状态事件记账(追加一条五元事件"
|
|
732
|
+
"subject/slot/old/new/kind;actor 恒取令牌;"
|
|
733
|
+
"查询走 stg(op=state_chain))。",
|
|
731
734
|
"inputSchema": _s("",
|
|
732
735
|
op=_p("string", "route|read|write|verify|review|protect|identity|"
|
|
733
736
|
"consistency|metacognition|self_state|evolution|sustain|"
|
|
734
737
|
"scrub|predict|causal|"
|
|
735
|
-
"forget|goal|task|recent|info|index_code|
|
|
738
|
+
"forget|goal|task|recent|state_event|info|index_code|"
|
|
739
|
+
"index_doc|ref|whitebox|"
|
|
736
740
|
"theory|link|session|ingest|export|maintain|consolidate|"
|
|
737
741
|
"insight|ccg|status|edges|audit|help", True),
|
|
738
742
|
ccg=_p("object", "CCG 六要素编译器入参:{action, node_id, dialog, marks, "
|
|
@@ -752,6 +756,10 @@ KERNEL_TOOLS = [
|
|
|
752
756
|
"write 时作为来源证据(user=外部惊奇)"),
|
|
753
757
|
meta=_p("object", "recent op:附加元数据"),
|
|
754
758
|
window=_p("integer", "recent op:滚动窗口大小(默认 200)"),
|
|
759
|
+
slot=_p("string", "state_event:事件槽位(五元之一——哪项状态)"),
|
|
760
|
+
old=_p("string", "state_event:变更前值(撤回时留空、new 必填;"
|
|
761
|
+
"old/new 双空非法)"),
|
|
762
|
+
new=_p("string", "state_event:变更后值(撤回=留空;空值即值作废)"),
|
|
755
763
|
include_recent=_p("boolean", "read:是否附近期事件窗口(默认否)"),
|
|
756
764
|
limit=_p("integer", "goal/recent 的返回条数;read 的近期事件条数;"
|
|
757
765
|
"edges 分页条数(缺省 50、上限 500,0/负数报错不当「全部」)"),
|
|
@@ -820,7 +828,8 @@ KERNEL_TOOLS = [
|
|
|
820
828
|
"receipt(回执审计:命令与预期输出);"
|
|
821
829
|
"非法值库层报错(fail-closed)"),
|
|
822
830
|
budget_tokens=_p("integer", "read 的 token 预算"),
|
|
823
|
-
evidence=_p("string", "verify
|
|
831
|
+
evidence=_p("string", "verify 的证据;state_event:出处(五元之一,"
|
|
832
|
+
"回指原文/轮次)"),
|
|
824
833
|
verdict=_p("string", "verify 裁决:confirmed|weakened|falsified;"
|
|
825
834
|
"insight verify:verified|falsified"),
|
|
826
835
|
question=_p("string", "whitebox:ask/verify 的问题"),
|
|
@@ -913,7 +922,8 @@ KERNEL_TOOLS = [
|
|
|
913
922
|
"节点;**未生效(valid_from 未到)保留**"
|
|
914
923
|
"(两者语义相反,预约/计划类记忆生效前仍可召回)"),
|
|
915
924
|
ts=_p("number", "sustain note:事件时间戳"),
|
|
916
|
-
seq=_p("integer", "sustain note:事件序号"
|
|
925
|
+
seq=_p("integer", "sustain note:事件序号;state_event:事件序号"
|
|
926
|
+
"(五元之一——轮或序号)"),
|
|
917
927
|
task_running=_p("boolean", "sustain:任务执行中(心跳阈值放宽)"),
|
|
918
928
|
beat_interval=_p("number", "sustain start:心跳间隔秒(默认 600)"),
|
|
919
929
|
heal_interval=_p("number", "sustain start:巡检间隔秒(默认 300)"),
|
|
@@ -968,7 +978,8 @@ KERNEL_TOOLS = [
|
|
|
968
978
|
set=_p("object", "link policy:设置子系统签名策略"),
|
|
969
979
|
signers_file=_p("string", "link:签名策略文件(缺省 ~/.mdcg/_signers.json)"),
|
|
970
980
|
swarm=_p("string", "link:跨节点共享目录(缺省 ~/.mdcg/swarm)"),
|
|
971
|
-
subject=_p("string", "link evidence:按主体过滤(如 agent:node-x
|
|
981
|
+
subject=_p("string", "link evidence:按主体过滤(如 agent:node-x);"
|
|
982
|
+
"state_event:事件主体(五元之一——谁的状态)"),
|
|
972
983
|
subjects=_p("array", "link export:限定导出的主体列表"),
|
|
973
984
|
out=_p("string", "link export:证据包输出路径;export/maintain 输出路径"),
|
|
974
985
|
pack=_p("object", "link import:内联证据包(与 path 二选一)"),
|
|
@@ -1063,10 +1074,12 @@ KERNEL_TOOLS = [
|
|
|
1063
1074
|
"op=timeline:按时间排序(可用 session 切本会话/跨会话视图,"
|
|
1064
1075
|
"看「所有会话做了什么」传 session=\"*\",返回项带会话归属);"
|
|
1065
1076
|
"op=anchors:落在时间窗/空间范围的节点;"
|
|
1066
|
-
"op=consistency
|
|
1077
|
+
"op=consistency:时空字段自洽性检查;"
|
|
1078
|
+
"op=state_chain:状态槽位投影(现值/区间/变迁史;"
|
|
1079
|
+
"flag MDCG_STG_STATE 默认关)。"
|
|
1067
1080
|
"四个 op 均可用 time_axis 切换时间轴(缺省 observed)。",
|
|
1068
1081
|
"inputSchema": _s("",
|
|
1069
|
-
op=_p("string", "relation|timeline|anchors|consistency", True),
|
|
1082
|
+
op=_p("string", "relation|timeline|anchors|consistency|state_chain", True),
|
|
1070
1083
|
a=_p("string", "relation 的节点 a"), b=_p("string", "relation 的节点 b"),
|
|
1071
1084
|
time_window=_p("array", "anchors 的时间窗 [t1,t2]"),
|
|
1072
1085
|
bbox=_p("array", "anchors 的包围盒 [x1,y1,x2,y2]"),
|
|
@@ -1077,7 +1090,12 @@ KERNEL_TOOLS = [
|
|
|
1077
1090
|
"(frontmatter.session 精确相等)"),
|
|
1078
1091
|
desc=_p("boolean", "timeline 是否倒序(默认是)"),
|
|
1079
1092
|
time_axis=_p("string", "时间轴:observed(观察轴 temporal/time_window,"
|
|
1080
|
-
"缺省)| effective(效力轴 effective_from/until)")
|
|
1093
|
+
"缺省)| effective(效力轴 effective_from/until)"),
|
|
1094
|
+
subject=_p("string", "state_chain 的主体(省略=不过滤)"),
|
|
1095
|
+
slot=_p("string", "state_chain 的槽位(省略=不过滤)"),
|
|
1096
|
+
include_retired=_p("boolean", "state_chain 是否含退役槽位(默认 false;"
|
|
1097
|
+
"退役不删除,只是默认不列)"),
|
|
1098
|
+
history=_p("boolean", "state_chain 是否带变迁史(默认 true)")),
|
|
1081
1099
|
},
|
|
1082
1100
|
]
|
|
1083
1101
|
|
|
@@ -2108,7 +2126,10 @@ def _cg_dispatch(cg, a):
|
|
|
2108
2126
|
return _help_call(cg, a)
|
|
2109
2127
|
_p = getattr(cg, "principal", None)
|
|
2110
2128
|
if _p is not None and hasattr(_p, "require_op"):
|
|
2111
|
-
|
|
2129
|
+
# P3 写口(state_event)映射到既有 "write" op 词——不给令牌 face 引入新
|
|
2130
|
+
# op 词(角色白名单/派生收窄面零改动):凡 ops 白名单含 write 的角色可
|
|
2131
|
+
# 记账,guest/只读令牌照拒。其余 op 逐位不变。
|
|
2132
|
+
_p.require_op("write" if op == "state_event" else op)
|
|
2112
2133
|
|
|
2113
2134
|
if op == "status":
|
|
2114
2135
|
return _status_call(cg, a)
|
|
@@ -2428,6 +2449,26 @@ def _cg_dispatch(cg, a):
|
|
|
2428
2449
|
return {"events": cg.recent_events(limit=int(a.get("limit") or 20),
|
|
2429
2450
|
roles=a.get("roles"))}
|
|
2430
2451
|
|
|
2452
|
+
if op == "state_event":
|
|
2453
|
+
# L2 状态事件记账(P3 写口;设计稿 §2「事件是源、槽位是投影、查询走 stg」)。
|
|
2454
|
+
# actor **恒取令牌**(不接受请求参数——沿本文件既有防伪造口径:客户端
|
|
2455
|
+
# 不得改写归属);台账是直写盘面的 append-only 文件、**绕过库层节点写闸**,
|
|
2456
|
+
# 故在此显式补齐 require_write(缺了它:ops 白名单放行但 can_write=False
|
|
2457
|
+
# 的令牌也能落盘)。kind 归一:空串归 None——「未分类」是合法记账,
|
|
2458
|
+
# 而 append 对空串抛 ValueError。append 的 ValueError(缺 subject/slot、
|
|
2459
|
+
# old/new 双空、非法 kind)原样上抛(fail-closed,不吞)。
|
|
2460
|
+
from . import state_events as _se
|
|
2461
|
+
_actor = _p.actor if _p is not None else "system"
|
|
2462
|
+
if _p is not None:
|
|
2463
|
+
_p.require_write("internal")
|
|
2464
|
+
rec = _se.append(cg, a.get("subject"), a.get("slot"),
|
|
2465
|
+
old=a.get("old"), new=a.get("new"),
|
|
2466
|
+
kind=(a.get("kind") or "").strip() or None,
|
|
2467
|
+
seq=a.get("seq"),
|
|
2468
|
+
evidence=a.get("evidence") or "",
|
|
2469
|
+
actor=_actor)
|
|
2470
|
+
return {"ok": True, "event": rec}
|
|
2471
|
+
|
|
2431
2472
|
if op == "verify":
|
|
2432
2473
|
return cg.verify(a.get("node_id", ""), a.get("evidence", ""),
|
|
2433
2474
|
a.get("verdict", ""),
|
|
@@ -3212,13 +3253,25 @@ def _stg_call(cg, a):
|
|
|
3212
3253
|
if op == "consistency":
|
|
3213
3254
|
return stg.consistency(cg, layer=a.get("layer"),
|
|
3214
3255
|
limit=int(a.get("limit") or 50), time_axis=axis)
|
|
3256
|
+
if op == "state_chain":
|
|
3257
|
+
# 第 5 op:状态槽位投影(flag MDCG_STG_STATE **默认关**)。关臂由 stg 侧
|
|
3258
|
+
# 返回 disabled 返回体(**不抛**——「没开」不是错误,是与「没命中」可分辨的
|
|
3259
|
+
# 如实答复);开臂委托 md_cg/state_slots.py 现算(本层不复制投影逻辑)。
|
|
3260
|
+
# time_axis 与本 op 无关:台账事件行只有落账时间戳 t,无第二轴(不伪造)。
|
|
3261
|
+
return stg.state_chain(
|
|
3262
|
+
cg, subject=a.get("subject"), slot=a.get("slot"),
|
|
3263
|
+
include_retired=bool(a.get("include_retired", False)),
|
|
3264
|
+
history=bool(a.get("history", True)),
|
|
3265
|
+
limit=int(a.get("limit") or 50))
|
|
3215
3266
|
if not op:
|
|
3216
3267
|
# fail-closed 且给出可操作提示:stg 的 op 四值签名区分度低于 cg(relation 需
|
|
3217
3268
|
# a+b、timeline/anchors/consistency 皆以 layer+limit 为主),**不做签名推导**
|
|
3218
3269
|
# ——猜错会静默返回错误视图,比报错更贵。
|
|
3219
3270
|
raise ValueError("stg 的 op 为必填参数(缺失即报错,不静默降级);"
|
|
3220
|
-
"允许 op:relation | timeline | anchors | consistency"
|
|
3221
|
-
|
|
3271
|
+
"允许 op:relation | timeline | anchors | consistency | "
|
|
3272
|
+
"state_chain")
|
|
3273
|
+
raise ValueError(f"stg 未知 op:{op}(允许 relation | timeline | anchors | "
|
|
3274
|
+
f"consistency | state_chain)")
|
|
3222
3275
|
|
|
3223
3276
|
|
|
3224
3277
|
# --------------------------------------------------------------------------
|
package/md_cg/mdcos.py
CHANGED
|
@@ -37,7 +37,7 @@ from .mdcg import (MdCG, expand_query_terms, bigrams, normalize_en, STATE_ACCEPT
|
|
|
37
37
|
from . import (nodefile, routing, chain, subgraph, forgetting, protect,
|
|
38
38
|
identity, consistency, metacognition, crypto, sustain,
|
|
39
39
|
self_state, predict, evolution, weights, pooling,
|
|
40
|
-
writelimit, reach, trust, roleviews, autonomy_modes)
|
|
40
|
+
writelimit, reach, trust, roleviews, autonomy_modes, lifecycle)
|
|
41
41
|
from .fsutil import (FileLock, atomic_write, append_jsonl, read_jsonl,
|
|
42
42
|
read_jsonl_tail, count_jsonl, publish)
|
|
43
43
|
from .security import (Principal, TenantRegistry, AccessDenied,
|
|
@@ -425,6 +425,26 @@ def _note_visible(cg, e) -> bool:
|
|
|
425
425
|
return _security.visible_to(cg, e)
|
|
426
426
|
|
|
427
427
|
|
|
428
|
+
# 生效条件:cg 索引的 nodes 中该 nid 有条目且 lifecycle.is_archived(该条目) 为真时返回 True;条目缺失时把 None 交给 state_of ⇒ 返回 False(fail-open,与判据单点同语义)。
|
|
429
|
+
def _retired_by_id(cg, nid) -> bool:
|
|
430
|
+
"""退役判据在「**按 id 取**的节点」上的单点包装(会话续接包台账段用)。
|
|
431
|
+
|
|
432
|
+
台账两段(goals / tasks)拿到的是 `_goal_entry` / `tasks._entry` 的**对外条目**
|
|
433
|
+
(只有 id,没有索引条目本身),故此处按 id 回查索引再交判据单点
|
|
434
|
+
`lifecycle.is_archived`——判据仍只此一份,不另立第二套口径。
|
|
435
|
+
"""
|
|
436
|
+
e = ((getattr(cg, "index", None) or {}).get("nodes") or {}).get(nid)
|
|
437
|
+
return lifecycle.is_archived(e)
|
|
438
|
+
|
|
439
|
+
|
|
440
|
+
#: 会话续接包台账段(goals / tasks)的取数窗:取全量再过滤退役再截断
|
|
441
|
+
#: (`list_goals` 本就全表扫;`tasks.session_tasks` 内部本就先建全量列表再切片,
|
|
442
|
+
#: 故不增遍历成本),避免「窗口内的 archived 被剔后不足额」。
|
|
443
|
+
_LEDGER_WINDOW = 10 ** 6
|
|
444
|
+
#: 台账段每段最终回出的条数(与改动前的 limit=5 逐位一致)。
|
|
445
|
+
_PACK_ROWS = 5
|
|
446
|
+
|
|
447
|
+
|
|
428
448
|
# 生效条件:以任意 root 构造时按其拼接 audit_log/hippocampus/trash 等路径并 makedirs 创建 hippocampus 与 trash_dir(exist_ok=True),autoflush 透传父类、actor 存入 self.actor;
|
|
429
449
|
class MdCGOS(MdCG):
|
|
430
450
|
"""MdCG + 记忆 OS 七项能力。"""
|
|
@@ -747,7 +767,7 @@ class MdCGOS(MdCG):
|
|
|
747
767
|
payload_hash=_sig(content))
|
|
748
768
|
return nid
|
|
749
769
|
|
|
750
|
-
# 生效条件:在已用 root 构造的实例上遍历 index["nodes"],恒剔除 layer 为 rejected/unresolved/goals
|
|
770
|
+
# 生效条件:在已用 root 构造的实例上遍历 index["nodes"],恒剔除 layer 为 rejected/unresolved/goals 的节点,恒剔除 lifecycle.is_archived(e) 为真的节点(退役不参与默认检索;缺 lifecycle 键=active 照常,converged/demoted 仍参与),session 为真值而 e["session"] 不等于它时剔除,e["branch_id"] 不在 (None, branch) 时剔除(branch=None 时只留 branch_id 为 None 者),validity 为真值而 trust.is_expired(e) 为真时剔除(**只排已过期,not_yet 保留**),layer 为真值而 layer 不等时剔除,roles 不为 None 时仅留 role 落在 roles 内的节点;view 为真值时 role 维度裁决权移交 roleviews.matches(receipt=工作角色白名单须绕过默认剔除才可达,非法 view ValueError),view 为假值且 include_work 为假时剔除 WORK_ROLES 角色,时间算子启用时按 time_axis 轴过滤(效力轴不可判定 fail-open、观察轴不可判定 fail-closed 并入 self._time_filter_stat),其余收集进 out 返回。
|
|
751
771
|
def _candidates(self, layer=None, roles=None, include_work=False,
|
|
752
772
|
session=None, branch=None, validity=None,
|
|
753
773
|
start_time=None, end_time=None, start_operator=None,
|
|
@@ -782,6 +802,19 @@ class MdCGOS(MdCG):
|
|
|
782
802
|
if e.get("layer") in NEG_ROUTE_LAYERS:
|
|
783
803
|
continue # 负记忆走覆盖标记;目标只做定向,都不进正排
|
|
784
804
|
# (真源 mdcg.NEG_ROUTE_LAYERS,本处直接导入,不留第二份字面量)
|
|
805
|
+
if lifecycle.is_archived(e):
|
|
806
|
+
continue # lifecycle.py:42 标称兑现:archived 不参与默认检索。
|
|
807
|
+
# 本处是 **cg 检索面单点**——`MdCGSecure._candidates`
|
|
808
|
+
# 经 super() 在此之上叠加读可见性,故全部**检索类**
|
|
809
|
+
# cg 读 op(search / search_rrf / recall / route…)经此
|
|
810
|
+
# 一处。cg 的读 op 并非全走候选池:`op=session` 的续接包
|
|
811
|
+
# 自持取数面,另在 `_session_notes` / `session_recall`
|
|
812
|
+
# 接同一判据(见 lifecycle.is_archived 的消费面清单)。
|
|
813
|
+
# 判据单点在 lifecycle.is_archived(fail-open:缺键=
|
|
814
|
+
# active 照常;只剔 archived——converged/demoted 是
|
|
815
|
+
# **降权轴**,仍参与默认检索)。
|
|
816
|
+
# 直读面(cg.get / op=audit / 库层 set_state 恢复路径)**不**
|
|
817
|
+
# 经本函数:退役不删除、可显式恢复。见 lifecycle.is_archived
|
|
785
818
|
# '"*"' = 显式跨会话(读遍所有会话);缺省 None 同义(见 stg.timeline)
|
|
786
819
|
if session and session != "*" and e.get("session") != session:
|
|
787
820
|
continue
|
|
@@ -3153,11 +3186,18 @@ class MdCGOS(MdCG):
|
|
|
3153
3186
|
return {"ok": True, "id": nid, "session": session, "layer": layer,
|
|
3154
3187
|
"basis": basis, "tokens": est_tokens(content)}
|
|
3155
3188
|
|
|
3156
|
-
# 生效条件:当 session 传入且为真时仅保留 tags 含 f"session:{session}"
|
|
3189
|
+
# 生效条件:当 session 传入且为真时仅保留 tags 含 f"session:{session}" 的项;恒剔除 lifecycle.is_archived(e) 为真的条目(退役不参与默认注入,判据单点在 lifecycle.py);保留 tags 含 SESSION_TAG 或任一以 "session:" 开头的索引节点,且该索引条目经可见性单点 _readable 判为可见,_read 的 content 为 None 则跳过;按 created_at 降序后返回前 max(1, int(limit or 5)) 条,limit 为假值(含 0/None)按 5 处理;
|
|
3157
3190
|
def _session_notes(self, session=None, limit=5):
|
|
3158
3191
|
"""按时间倒序取会话要点(索引过滤 + 可见性闸 + 惰性回读摘要)。只读,不写盘。"""
|
|
3159
3192
|
out = []
|
|
3160
3193
|
for nid, e in list((self.index.get("nodes") or {}).items()):
|
|
3194
|
+
if lifecycle.is_archived(e):
|
|
3195
|
+
continue # 退役剔除(判据单点 lifecycle.is_archived,
|
|
3196
|
+
# 与 cg 检索面 `_candidates`、stg 面
|
|
3197
|
+
# `_scan_one` 同一份):会话续接包是「把节点
|
|
3198
|
+
# **内容摘要**回给调用方」的注入面,archived
|
|
3199
|
+
# 不再参与默认注入(与 §5.2 退役纪律同口径);
|
|
3200
|
+
# fail-open:缺键/非法值=active 照常。
|
|
3161
3201
|
tags = list(e.get("tags") or [])
|
|
3162
3202
|
if self.SESSION_TAG not in tags and not any(
|
|
3163
3203
|
str(t).startswith("session:") for t in tags):
|
|
@@ -3191,7 +3231,7 @@ class MdCGOS(MdCG):
|
|
|
3191
3231
|
out.sort(key=lambda n: (-n["created_at"], str(n.get("id") or "")))
|
|
3192
3232
|
return out[:max(1, int(limit or 5))]
|
|
3193
3233
|
|
|
3194
|
-
# 生效条件:limit 经 max(1,min(int(limit or 5),50))、budget_tokens 经 max(200,int(budget_tokens or 1200)) 归一后逐段取数(include_state 为真才取 self_state
|
|
3234
|
+
# 生效条件:limit 经 max(1,min(int(limit or 5),50))、budget_tokens 经 max(200,int(budget_tokens or 1200)) 归一后逐段取数(include_state 为真才取 self_state;会话要点段、未解问题段与台账两段(goals/tasks)恒剔除 lifecycle.is_archived 条目——退役不参与默认注入;台账段取全量窗过滤后再截断 `_PACK_ROWS` 条,`tasks.active_total/done_total` 取剔除后的全窗计数),每段异常只把段名追加进 degraded,再由 while 循环按预算交替裁 recent/notes 尾部、任务段最后才裁并置 tasks_truncated。
|
|
3195
3235
|
def session_recall(self, session=None, limit=5, recent_limit=10,
|
|
3196
3236
|
budget_tokens=1200, include_state=True):
|
|
3197
3237
|
"""按需恢复:一次调用返回「可续接的上下文包」(替代 hook 自动注入)。
|
|
@@ -3203,6 +3243,15 @@ class MdCGOS(MdCG):
|
|
|
3203
3243
|
任务段(2026-09-16 新增)是「忘记已实现的工程」的直接解药:新会话开机即见
|
|
3204
3244
|
「还在做的」与「刚做完的」,不必先想到去查。任务属结构层、跨会话稳定,
|
|
3205
3245
|
故**不按 session 过滤**——工程台账跟着工程走,不跟着会话走。
|
|
3246
|
+
|
|
3247
|
+
**退役口径(本包统一)**:本 op 是**注入面**(内容直接回给调用方/进上下文),
|
|
3248
|
+
故四个取数段(notes / goals / tasks[active/done 两清单]/ unresolved;合计
|
|
3249
|
+
五个清单)一律剔除
|
|
3250
|
+
`lifecycle_state=archived`(判据单点 `lifecycle.is_archived`)——「退役不参与
|
|
3251
|
+
默认注入」。`recent` 段是**事件窗口**(非节点)、`self_state` 是只读快照卡,
|
|
3252
|
+
两者不含节点条目,不涉及退役。**管理查询面不受限**:`cg(op=goal, action=list)`
|
|
3253
|
+
与 `cg(op=task, action=list)` 直读台账、archived 期间照常可达(两处不冲突:
|
|
3254
|
+
同一份台账,注入面剔除、管理面直读)。
|
|
3206
3255
|
"""
|
|
3207
3256
|
limit = max(1, min(int(limit or 5), 50))
|
|
3208
3257
|
budget = max(200, int(budget_tokens or 1200))
|
|
@@ -3218,26 +3267,41 @@ class MdCGOS(MdCG):
|
|
|
3218
3267
|
except Exception: # noqa: BLE001
|
|
3219
3268
|
pack["degraded"].append("notes")
|
|
3220
3269
|
# ② 活跃目标(检索定向的默认来源)
|
|
3270
|
+
# 退役剔除(判据单点 lifecycle.is_archived,经 `_retired_by_id` 按 id 取):
|
|
3271
|
+
# 续接包是**注入面**,archived 不参与默认注入(同 ① 与 ④)。取数窗取
|
|
3272
|
+
# **全量**(limit=None)再过滤再截断——否则窗口内的 archived 被剔后不足额,
|
|
3273
|
+
# 本该补位的在役目标补不上(`list_goals` 本就是全表扫,无额外成本)。
|
|
3274
|
+
# 管理查询面 `cg(op=goal, action=list)` **不受限**(不经本函数、直读台账)。
|
|
3221
3275
|
try:
|
|
3222
3276
|
pack["goals"] = [{"id": g["id"], "goal": g["goal"],
|
|
3223
3277
|
"priority": g["priority"]}
|
|
3224
|
-
for g in self.active_goals(limit=
|
|
3278
|
+
for g in self.active_goals(limit=None)
|
|
3279
|
+
if not _retired_by_id(self, g.get("id"))
|
|
3280
|
+
][:_PACK_ROWS]
|
|
3225
3281
|
except Exception: # noqa: BLE001
|
|
3226
3282
|
pack["degraded"].append("goals")
|
|
3227
3283
|
# ②.5 任务台账(structural 层)——见 docstring:不按 session 过滤
|
|
3284
|
+
# 退役剔除(同上,台账段是同一注入面的子段):列表剔 archived、`*_total`
|
|
3285
|
+
# 随之取**剔除后**的全窗计数(列表是它的前 `_PACK_ROWS` 条,两者同源自洽);
|
|
3286
|
+
# 管理查询面 `cg(op=task, action=list)` 仍直读台账、**不受限**。
|
|
3228
3287
|
try:
|
|
3229
3288
|
from . import tasks as _tasks
|
|
3230
|
-
ts = _tasks.session_tasks(self, active_limit=
|
|
3289
|
+
ts = _tasks.session_tasks(self, active_limit=_LEDGER_WINDOW,
|
|
3290
|
+
done_limit=_LEDGER_WINDOW)
|
|
3291
|
+
_act = [t for t in ts["active"]
|
|
3292
|
+
if not _retired_by_id(self, t.get("id"))]
|
|
3293
|
+
_done = [t for t in ts["done"]
|
|
3294
|
+
if not _retired_by_id(self, t.get("id"))]
|
|
3231
3295
|
pack["tasks"] = {
|
|
3232
3296
|
"active": [{"id": t["id"], "name": t["name"], "status": t["status"],
|
|
3233
3297
|
"plan": (t.get("plan") or "")[:300],
|
|
3234
3298
|
"updated_at": t.get("updated_at")}
|
|
3235
|
-
for t in
|
|
3299
|
+
for t in _act[:_PACK_ROWS]],
|
|
3236
3300
|
"done": [{"id": t["id"], "name": t["name"], "status": t["status"],
|
|
3237
3301
|
"result": (t.get("result") or "")[:300],
|
|
3238
3302
|
"updated_at": t.get("updated_at")}
|
|
3239
|
-
for t in
|
|
3240
|
-
"active_total":
|
|
3303
|
+
for t in _done[:_PACK_ROWS]],
|
|
3304
|
+
"active_total": len(_act), "done_total": len(_done)}
|
|
3241
3305
|
except Exception: # noqa: BLE001
|
|
3242
3306
|
pack["degraded"].append("tasks")
|
|
3243
3307
|
# ③ 近期事件(原始滚动窗口)
|
|
@@ -3253,6 +3317,11 @@ class MdCGOS(MdCG):
|
|
|
3253
3317
|
for nid, e in list((self.index.get("nodes") or {}).items()):
|
|
3254
3318
|
if e.get("layer") != "unresolved":
|
|
3255
3319
|
continue
|
|
3320
|
+
if lifecycle.is_archived(e):
|
|
3321
|
+
continue # 退役剔除(同 ① 会话要点:本条是续接包里
|
|
3322
|
+
# 「未解问题正文片段回给调用方」的第二处注入
|
|
3323
|
+
# 子面,判据仍是 lifecycle.is_archived 单点;
|
|
3324
|
+
# fail-open 同上)
|
|
3256
3325
|
# N211(2026-09-28,本族第二出口,原树内并号 N209 按 v24 裁定改判):与 ① 会话要点同根——此处也
|
|
3257
3326
|
# 是「只按 layer 过滤 → 回读正文 → 抽出 `# 问题:`」的直读出口,
|
|
3258
3327
|
# 无 _readable。实测:restricted 档未解问题的正文经 session_recall
|