@furongjun1999/dsh-memory 0.7.2 → 0.7.4

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.
Files changed (129) hide show
  1. package/README.md +57 -47
  2. package/codebuddy/CODEBUDDY.md +6 -6
  3. package/docs/README.md +148 -144
  4. package/docs/discipline/harnesses.yaml +16 -8
  5. package/docs/discipline/templates/zcode-user.md.tmpl +49 -0
  6. package/docs/eval/AGI/344/270/203/347/273/264/350/257/204/345/210/206/346/212/245/345/221/212_/345/205/255/345/256/266/350/256/260/345/277/206/347/263/273/347/273/237/345/220/214/345/260/272/345/256/236/346/265/213_v3.1.md +340 -0
  7. package/docs/eval/N225_/347/264/242/345/274/225/346/227/245/345/277/227/351/235/236/345/257/271/350/261/241/350/243/205/350/275/275/351/235/242/347/261/273/345/236/213/351/227/270_v1.0.md +2 -2
  8. 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 +1 -1
  9. 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 +1 -1
  10. package/docs/eval/issue43_/351/273/230/350/256/244/347/255/226/347/225/245/344/270/216/351/224/256/347/261/273/345/236/213/351/227/270_v1.1.md +1 -1
  11. package/docs/eval/issue43_/351/273/230/350/256/244/347/255/226/347/225/245/345/212/240/350/275/275/344/270/216/345/207/255/346/215/256/346/230/216/346/226/207/351/230/237/345/210/227_v1.0.md +2 -2
  12. 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 +5 -5
  13. 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 +9 -9
  14. 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 +4 -4
  15. 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 +1 -1
  16. 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 +1 -1
  17. 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 +3 -3
  18. 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 +3 -3
  19. 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 +7 -7
  20. package/docs/eval//344/274/230/345/214/226/347/254/254/344/270/200/346/211/271_/346/216/245/347/272/277/344/270/216/347/255/211/344/273/267/345/217/230/346/215/242_v1.0.md +2 -2
  21. package/docs/eval//344/274/230/345/214/226/347/254/254/344/270/211/346/211/271_/351/227/250/347/246/201/350/275/254/346/255/243/344/270/216/350/260/203/345/272/246/346/255/242/350/241/200/344/270/216/351/227/250/346/216/247/346/224/266/345/217/243_v1.0.md +1 -1
  22. package/docs/eval//344/274/230/345/214/226/347/254/254/344/272/214/346/211/271_/344/276/235/350/265/226/351/200/217/344/274/240/344/270/216/345/257/271/346/213/215/345/217/243/345/276/204/344/270/216/350/264/237/347/274/223/345/255/230_v1.0.md +7 -7
  23. 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 +10 -10
  24. package/docs/eval//345/217/221/345/270/20307_/345/244/226/351/203/250/346/212/245/345/221/212/345/233/233/346/211/271/344/277/256/345/244/215/344/270/216/346/217/222/344/273/266/351/235/242/345/212/240/345/233/272_v1.0.md +4 -0
  25. 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 +1 -1
  26. package/docs/eval//345/217/221/345/270/20311_/345/244/226/346/212/245/345/205/255/350/277/236/344/277/256/344/270/216/344/270/226/347/225/214/346/250/241/345/236/213/345/272/225/345/272/247_v1.0.md +91 -0
  27. 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
  28. 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 +2 -2
  29. package/docs/eval//347/224/250/346/210/267/350/243/201/345/206/263/345/244/204/347/275/256_/347/254/254/344/270/200/346/211/271_v1.0.md +195 -0
  30. package/docs/eval//347/224/250/346/210/267/350/243/201/345/206/263/345/244/204/347/275/256_/347/254/254/344/272/214/346/211/271B6_/346/234/254/346/234/272/350/267/257/345/276/204/347/233/270/345/257/271/345/214/226_v1.0.md +78 -0
  31. package/docs/eval//347/253/257/345/210/260/347/253/257LoCoMoQA/345/220/214/345/217/243/345/276/204/345/257/271/347/205/247_v1.0.md +1 -1
  32. package/docs/eval//347/253/257/345/210/260/347/253/257/345/271/262/346/211/260/346/261/240/350/257/204/346/265/213_/347/241/256/345/256/232/346/200/247/350/243/201/345/206/263vsLLM_judge_v1.1.md +3 -3
  33. 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 +1 -1
  34. package/docs/eval//347/274/226/347/240/201/351/235/242/345/211/215/347/275/256_/345/205/245/345/217/243/350/207/252/344/277/235/350/257/201UTF8/344/270/216/346/226/207/346/234/254open/345/256/210/345/215/253_v1.0.md +1 -1
  35. package/docs/eval//347/274/272/351/231/267/346/214/226/346/216/230_/350/207/252/344/270/273/350/277/255/344/273/243_v26.md +196 -0
  36. package/docs/eval//347/274/272/351/231/267/346/214/226/346/216/230_/350/207/252/344/270/273/350/277/255/344/273/243_v27.md +259 -0
  37. package/docs/eval//347/274/272/351/231/267/346/214/226/346/216/230_/350/207/252/344/270/273/350/277/255/344/273/243_v28.md +217 -0
  38. package/docs/eval//347/274/272/351/231/267/346/214/226/346/216/230_/350/207/252/344/270/273/350/277/255/344/273/243_v29.md +270 -0
  39. package/docs/eval//347/274/272/351/231/267/346/214/226/346/216/230_/350/207/252/344/270/273/350/277/255/344/273/243_v30.md +231 -0
  40. package/docs/eval//347/274/272/351/231/267/346/214/226/346/216/230_/350/207/252/344/270/273/350/277/255/344/273/243_v31.md +281 -0
  41. 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
  42. package/docs/hive//345/256/211/345/205/250/345/256/241/350/256/241/345/256/236/351/224/232_v0.1.md +1 -1
  43. package/docs/hive//350/234/202/345/267/242M6_ingest/345/256/236/346/226/275/350/256/241/345/210/222_v0.1.md +1 -1
  44. 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 +1 -1
  45. package/docs/hive//350/234/202/345/267/242/350/256/276/350/256/241_/347/220/206/350/256/272/345/257/271/351/275/220_v0.1.md +17 -17
  46. package/docs/hive//350/234/202/345/267/242/350/277/255/344/273/243_/345/256/217/350/247/202/344/270/216/347/276/244/344/275/223/350/260/203/345/272/246_v0.1.md +1 -1
  47. package/docs/mdcg/README/350/257/246/347/273/206/347/211/210_v0.4.10.md +2 -2
  48. 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
  49. 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 -42
  50. package/docs/mdcg//345/217/221/345/270/203/351/227/250/347/246/201/351/223/276_v0.1.md +29 -8
  51. 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 +71 -1
  52. package/docs/plans//345/205/250/344/270/255/346/226/207/347/274/226/347/240/201/344/270/216/350/234/202/345/267/242/344/273/273/345/212/241/346/240/207/350/257/206/345/245/221/347/272/246_v2.0.md +1 -1
  53. package/docs/plans//345/244/232/344/270/273/344/275/223/344/270/226/347/225/214/346/250/241/345/236/213_/345/257/271/351/275/220/350/257/204/344/274/260/344/270/216/350/220/275/345/234/260/350/256/276/350/256/241_v0.1.md +141 -0
  54. 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 +2 -2
  55. package/docs/plans//350/257/255/344/271/211/346/227/266/347/251/272/345/233/276/350/241/245/345/205/250_/344/270/226/347/225/214/346/250/241/345/236/213/345/212/237/350/203/275/347/253/257_/350/256/276/350/256/241_v0.1.md +107 -0
  56. 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 +6 -5
  57. package/docs//347/247/244_/350/256/260/345/277/206/347/263/273/347/273/237/350/257/204/346/265/213/350/247/204/350/214/203_v2.1.md +225 -0
  58. package/dsh/cordis-patch-profile-web.example.yml +2 -2
  59. package/lib/bridge.js +9 -0
  60. package/lib/hooks.d.ts +8 -1
  61. package/lib/hooks.js +134 -50
  62. package/lib/lib/hook_audit.d.ts +55 -0
  63. package/lib/lib/hook_audit.js +208 -0
  64. package/lib/lib/mutual.js +5 -1
  65. package/lib/lib/roleplay_web.js +17 -2
  66. package/lib/lib/session_state.d.ts +56 -0
  67. package/lib/lib/session_state.js +124 -0
  68. package/lib/tools.js +12 -1
  69. package/md_cg/auditview.py +248 -0
  70. package/md_cg/bench_e2e_judge.py +4 -2
  71. package/md_cg/branches.py +29 -3
  72. package/md_cg/consistency.py +38 -13
  73. package/md_cg/datapath.py +38 -11
  74. package/md_cg/forgetting.py +15 -2
  75. package/md_cg/freshness.py +32 -11
  76. package/md_cg/ghostref.py +130 -0
  77. package/md_cg/judgment_manifest.py +7 -0
  78. package/md_cg/lifecycle.py +38 -0
  79. package/md_cg/mcp_server.py +122 -12
  80. package/md_cg/mdcg.py +4923 -4822
  81. package/md_cg/mdcos.py +109 -21
  82. package/md_cg/nodefile.py +77 -13
  83. package/md_cg/readcache.py +29 -4
  84. package/md_cg/selfreport.py +12 -3
  85. package/md_cg/sleep.py +129 -13
  86. package/md_cg/sources.py +1 -1
  87. package/md_cg/state_events.py +131 -0
  88. package/md_cg/state_slots.py +221 -0
  89. package/md_cg/stg.py +68 -3
  90. package/md_cg/sustain.py +1436 -1436
  91. package/md_cg/test_auditview.py +277 -0
  92. package/md_cg/test_autonomy_modes.py +2 -1
  93. package/md_cg/test_boot_openblas_guard.py +197 -0
  94. package/md_cg/test_ccg_form_parity.py +95 -4
  95. package/md_cg/test_cons200_scan_selection.py +4 -2
  96. package/md_cg/test_datapath_device_name.py +62 -3
  97. package/md_cg/test_generation_guard.py +5 -2
  98. package/md_cg/test_ghostref.py +182 -0
  99. package/md_cg/test_interop.py +1 -1
  100. package/md_cg/test_issue52_scan_condition_first.py +1 -1
  101. package/md_cg/test_lifecycle_retire_leak.py +408 -0
  102. package/md_cg/test_lock.py +16 -7
  103. package/md_cg/test_m3_h9_semantic_guard.py +1 -1
  104. package/md_cg/test_n230_dirty_replay.py +375 -375
  105. package/md_cg/test_n238_body_text_parity.py +156 -0
  106. package/md_cg/test_n276_probe_hoist.py +199 -0
  107. package/md_cg/test_p4_freshness.py +95 -1
  108. package/md_cg/test_policy_required_ccg.py +3 -1
  109. package/md_cg/test_read_face_semantics.py +6 -3
  110. package/md_cg/test_readcache_prodpath.py +66 -0
  111. package/md_cg/test_sleep.py +58 -1
  112. package/md_cg/test_sleep_p1.py +218 -2
  113. package/md_cg/test_state_event_op.py +514 -0
  114. package/md_cg/test_state_events.py +178 -0
  115. package/md_cg/test_state_slots.py +691 -0
  116. package/md_cg/test_time_core_lint.py +8 -1
  117. package/md_cg/test_writepipe.py +8 -5
  118. package/md_cg/tokens.py +18 -2
  119. package/md_cg/writepipe.py +76 -0
  120. package/package.json +2 -2
  121. package/skills/plugin.json +1 -1
  122. package/src/bridge.ts +9 -0
  123. package/src/hooks.ts +599 -517
  124. package/src/lib/hook_audit.ts +243 -0
  125. package/src/lib/mutual.ts +5 -1
  126. package/src/lib/roleplay_web.ts +17 -2
  127. package/src/lib/session_state.ts +127 -0
  128. package/src/tools.ts +12 -1
  129. package/zcode/AGENTS.md +6 -6
package/md_cg/stg.py CHANGED
@@ -12,6 +12,10 @@
12
12
  anchors(...) 落在给定时间窗 / 空间范围内的节点
13
13
  consistency() 时空字段自洽性检查
14
14
 
15
+ 第 5 op(本批):`state_chain(cg, subject, slot, …)`——L2 **状态槽位投影**
16
+ (某主体某槽位的现值/区间/变迁史;flag `MDCG_STG_STATE`,**默认关**)。语义单点
17
+ 在 `md_cg/state_slots.py`(投影不是第二真源:查询时从 append-only 台账现算)。
18
+
15
19
  **分层(issue #52 线)**:
16
20
  · 第 1/2 层(已收口):条件先于限额 + 截断可观测——`_scan` 只做「遍历 +
17
21
  layer/可见性过滤」,条件过滤与 `_cap_hits` 截断归各接口。
@@ -28,6 +32,7 @@ from __future__ import annotations
28
32
 
29
33
  import os
30
34
 
35
+ from . import lifecycle
31
36
  from . import stgidx
32
37
  from . import trust
33
38
 
@@ -130,7 +135,7 @@ def _node(cg, node_id):
130
135
  "content": n.get("content") or ""}
131
136
 
132
137
 
133
- # 生效条件:nid/e 为一条快照条目、layer 为层过滤值时——layer 为真值且 e.get("layer") != layer 即返回 None;cg 带可调用的 _readable(MdCGSecure)且判不可见即返回 None;e 含 "temporal" 或 "spatial" 键时以快照字段构造 frontmatter,否则调用 cg._read(e) 且在 fm 为 None 时返回 None;返回 {"id","frontmatter","layer","path"}。
138
+ # 生效条件:nid/e 为一条快照条目、layer 为层过滤值时——layer 为真值且 e.get("layer") != layer 即返回 None;lifecycle.is_archived(e) 为真即返回 None(退役不参与默认检索,判据单点在 lifecycle.py);cg 带可调用的 _readable(MdCGSecure)且判不可见即返回 None;e 含 "temporal" 或 "spatial" 键时以快照字段构造 frontmatter,否则调用 cg._read(e) 且在 fm 为 None 时返回 None;返回 {"id","frontmatter","layer","path"}。
134
139
  def _scan_one(cg, nid, e, layer=None):
135
140
  """单条目 → 候选条目(`_scan` 的逐条实现**单点**:全量遍历与索引子集共用)。
136
141
 
@@ -140,6 +145,16 @@ def _scan_one(cg, nid, e, layer=None):
140
145
  """
141
146
  if layer and e.get("layer") != layer:
142
147
  return None
148
+ if lifecycle.is_archived(e):
149
+ return None # lifecycle.py:42 标称兑现:archived 不参与默认检索。
150
+ # 本处是 **stg 扫描面单点**(`_scan`(:172) 的全量遍历与
151
+ # 索引子集两条分支都经本函数逐条实现)——timeline /
152
+ # anchors / consistency 三 op 的候选面同点覆盖;第 5 op
153
+ # `state_chain` 走 append-only 台账、不经节点扫描,不受影响;
154
+ # `relation` 面是显式 id 直读(`_node`→`cg.get`),也不经此。
155
+ # 判据单点在 lifecycle.is_archived(fail-open:缺键=active
156
+ # 照常;只剔 archived——converged/demoted 是降权轴仍参与)。
157
+ # 直读/审计/恢复面不经本函数:退役不删除、可显式恢复。
143
158
  _sec = getattr(cg, "_readable", None)
144
159
  if _sec is not None and not _sec(e):
145
160
  return None
@@ -164,7 +179,7 @@ def _scan_one(cg, nid, e, layer=None):
164
179
  "path": e.get("path")}
165
180
 
166
181
 
167
- # 生效条件:nodes 为 None 时**逐条**遍历 cg.index["nodes"] 全部条目(不按索引序切片、不读正文);nodes 为 (nid, entry) 对的序列时只遍历该序列(第 3 层索引子集,序由调用方保证=索引物理序);两种形态都逐条经 _scan_one(layer 过滤 + 可见性 + 条目化同一单点);返回 out 列表(全部 layer/可见性命中,**不做截断**——截断由各接口在条件过滤之后经 _cap_hits 执行,issue #52);
182
+ # 生效条件:nodes 为 None 时**逐条**遍历 cg.index["nodes"] 全部条目(不按索引序切片、不读正文);nodes 为 (nid, entry) 对的序列时只遍历该序列(第 3 层索引子集,序由调用方保证=索引物理序);两种形态都逐条经 _scan_one(layer 过滤 + 退役剔除 + 可见性 + 条目化同一单点);返回 out 列表(全部 layer/可见性命中,**不做截断**——截断由各接口在条件过滤之后经 _cap_hits 执行,issue #52);
168
183
  def _scan(cg, layer=None, nodes=None):
169
184
  """遍历节点:时空字段直接读索引快照(不读文件,O(1)/节点)。
170
185
 
@@ -174,6 +189,10 @@ def _scan(cg, layer=None, nodes=None):
174
189
  时逐条过读可见性——密级 × 会话绑定档在此与 _candidates 同口径,
175
190
  stg 各 op(timeline/relation/anchors)不得成为绕过路径。可见性判定
176
191
  **先于一切**(含截断):不可见节点既不进候选、也不占 kept 名额。
192
+ 退役单点(本轮):`lifecycle.is_archived` 为真的节点同样不进候选
193
+ (判据单点在 lifecycle.py,与 cg 读面 `MdCGOS._candidates` 共引一份),
194
+ 两个分支共用的逐条实现单点即 `_scan_one`——flag 开(索引子集)/关
195
+ (全量遍历)逐位一致,不因取数面不同而漏一次过滤。
177
196
 
178
197
  issue #52(条件先行于限额):旧实现在此处 `list(index["nodes"].items())[:max_scan]`
179
198
  ——按 id 字典序在**条件过滤之前**砍尾巴,库超 max_scan 后(a)本会话记忆等条件
@@ -269,6 +288,8 @@ def _with_scan_reads(out, *, scanned, hits, kept, truncated, max_scan,
269
288
  _INDEX_ENV = "MDCG_STG_INDEX"
270
289
  #: 条件资格首验开关(只上报不过滤)。
271
290
  _QUALIFY_ENV = "MDCG_STG_QUALIFY"
291
+ #: 状态槽位投影开关(第 5 op;与上两把同纪律:**默认关**,探针全绿后逐档开)。
292
+ _STATE_ENV = "MDCG_STG_STATE"
272
293
 
273
294
 
274
295
  # 生效条件:环境变量 name 取值属 ("1","true","True") 时返回 True,其余(含未设/其它值)返回 False——默认关的开关一律走本判据(与 MDCG_LEGACY_ENV_AUTH 同形)。
@@ -699,4 +720,48 @@ def consistency(cg, layer=None, limit=50, max_scan=5000, time_axis="observed"):
699
720
  return _with_scan_reads(
700
721
  {"issues": len(issues), "limit": limit, "items": issues[:limit]},
701
722
  scanned=scanned, hits=scanned, kept=kept, truncated=truncated,
702
- max_scan=max_scan, index_meta=imeta)
723
+ max_scan=max_scan, index_meta=imeta)
724
+
725
+
726
+ # ---------------------------------------------------------------------------
727
+ # 第 5 op:状态槽位投影(flag MDCG_STG_STATE,默认关)
728
+ # ---------------------------------------------------------------------------
729
+
730
+ # 生效条件:_flag_on(_STATE_ENV) 为假(含未设)时恒返回 {"error":"disabled","hint":…}(不抛异常、不静默降级、不触台账);为真时以 state_slots.project(cg, subject, slot, include_retired, history) 为 items 全量(查询时现算,零落盘零缓存),limit 经 int() 归一(负数归 0)后取前 limit 条,返回含 count(命中总数,截断前)/subject/slot/include_retired/limit/items/truncated(count > kept)/kept(len(items))的 dict;project 抛异常时**不吞**(原样上抛)。
731
+ def state_chain(cg, subject=None, slot=None, include_retired=False, history=True,
732
+ limit=50):
733
+ """状态槽位投影(第 5 op):某主体某槽位的**现值 / 区间 / 变迁史**。
734
+
735
+ 语义单点在 `md_cg/state_slots.py`(**投影不是第二真源**:查询时从 append-only
736
+ 台账 `<root>/_state_events.jsonl` 现算,不落盘、不缓存)——本函数只做开关与
737
+ 返回体成形,不复制任何回放逻辑(改投影只改那一处)。
738
+
739
+ 开关(`MDCG_STG_STATE`,**默认关**,与 `MDCG_STG_INDEX`/`MDCG_STG_QUALIFY`
740
+ 同纪律):关臂返回 `{"error": "disabled", "hint": …}`——**不是异常**,是「本面
741
+ 未启用」的如实答复;不静默降级成空结果(「没开」与「没命中」必须可分辨)。
742
+
743
+ 返回体沿 stg 既有口径(issue #52:截断可观测):`count` 为**条件命中总数**
744
+ (截断前,不受 limit 影响)、`items` 为前 `limit` 条、`kept` 为实际返回条数、
745
+ `truncated` 为 `count > kept`(limit=0 ⇒ items 空、truncated 随 count 真值)。
746
+
747
+ 不适用条件:`time_axis` 不适用于本 op(台账事件行只有落账时间戳 `t`,无
748
+ 双轴端点——本面**不伪造**第二轴;需要轴语义请走 timeline/relation/anchors);
749
+ `alternatives`/`blindspots` 本批恒空列表(判定口径后置,见 `state_slots` 模块头)。
750
+ """
751
+ if not _flag_on(_STATE_ENV):
752
+ return {"error": "disabled",
753
+ "hint": "本面默认关:设 MDCG_STG_STATE=1 显式启用"
754
+ "(与 MDCG_STG_INDEX/MDCG_STG_QUALIFY 同纪律)"}
755
+ from . import state_slots
756
+ units = state_slots.project(cg, subject=subject, slot=slot,
757
+ include_retired=include_retired,
758
+ history=history)
759
+ total = len(units)
760
+ cap = int(limit) if limit is not None else 0
761
+ if cap < 0:
762
+ cap = 0
763
+ items = units[:cap]
764
+ return {"count": total, "subject": subject, "slot": slot,
765
+ "include_retired": include_retired, "limit": limit,
766
+ "items": items, "truncated": total > len(items),
767
+ "kept": len(items)}