@furongjun1999/dsh-memory 0.5.0 → 0.5.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.
Files changed (138) hide show
  1. package/README.md +552 -465
  2. package/docs/README.md +1 -0
  3. package/docs/eval/bench_lingshu_self/bench_self.py +140 -0
  4. package/docs/eval/bench_lingshu_self/self_bench_result.json +404 -0
  5. package/docs/eval/bench_lingshu_self//347/201/265/346/236/242/350/207/252/345/272/223/347/253/257/345/210/260/347/253/257/346/243/200/347/264/242/345/256/236/346/265/213_v1.0.md +38 -0
  6. package/docs/eval//344/270/215/345/217/257/351/235/240/346/200/247/350/220/275/345/234/260_P0_v1.0.md +185 -0
  7. package/docs/eval//346/225/205/351/232/234/346/263/250/345/205/245/345/256/236/346/265/213_v1.0.md +422 -0
  8. 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 +100 -0
  9. 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 +197 -0
  10. 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_v1.md +156 -0
  11. 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_v10.md +210 -0
  12. 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_v11.md +227 -0
  13. 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_v12.md +203 -0
  14. 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_v13.md +233 -0
  15. 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_v14.md +191 -0
  16. 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_v15.md +213 -0
  17. 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_v16.md +214 -0
  18. 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_v17.md +199 -0
  19. 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_v2.md +156 -0
  20. 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_v3.md +152 -0
  21. 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_v4.md +128 -0
  22. 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_v5.md +114 -0
  23. 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_v6.md +192 -0
  24. 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_v7.md +187 -0
  25. 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_v8.md +207 -0
  26. 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_v9.md +203 -0
  27. package/docs/hive//345/256/211/345/205/250/345/256/241/350/256/241/345/256/236/351/224/232_v0.1.md +202 -0
  28. 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 +19 -3
  29. package/docs/images/lingshu-moonlight-covenant-poster-preview.jpg +0 -0
  30. package/docs/images/lingshu-moonlight-covenant-poster.png +0 -0
  31. 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
  32. package/docs/theory//344/270/215/345/217/257/351/235/240/345/256/232/347/220/206/344/270/216/345/244/261/346/225/210/344/274/230/345/205/210/346/241/206/346/236/266_v0.3.md +365 -0
  33. package/docs//344/270/215/345/217/257/351/235/240/346/200/247/347/220/206/350/256/272_v0.1.md +343 -0
  34. package/lib/bridge.d.ts +9 -0
  35. package/lib/bridge.js +35 -0
  36. package/lib/index.js +7 -1
  37. package/lib/lib/roleplay_web.js +530 -443
  38. package/lib/lib/token_store.d.ts +7 -1
  39. package/lib/lib/token_store.js +12 -3
  40. package/md_cg/audit.py +12 -1
  41. package/md_cg/backfill.py +16 -15
  42. package/md_cg/backfill_bucket_zh.py +35 -0
  43. package/md_cg/bench_e2e_judge.py +532 -0
  44. package/md_cg/bench_e2e_locomo_qa.py +368 -0
  45. package/md_cg/bench_e2e_qa.py +256 -0
  46. package/md_cg/branches.py +18 -2
  47. package/md_cg/ccgc.py +3 -2
  48. package/md_cg/chain.py +19 -4
  49. package/md_cg/consolidate.py +7 -6
  50. package/md_cg/crosscheck.py +4 -3
  51. package/md_cg/crypto.py +439 -437
  52. package/md_cg/datapath.py +395 -335
  53. package/md_cg/evidence.py +582 -580
  54. package/md_cg/export.py +3 -1
  55. package/md_cg/forgetting.py +2 -2
  56. package/md_cg/fsutil.py +48 -0
  57. package/md_cg/hotcache.py +255 -238
  58. package/md_cg/interop.py +161 -22
  59. package/md_cg/judgment_manifest.py +177 -0
  60. package/md_cg/links.py +655 -622
  61. package/md_cg/mcp_server.py +280 -29
  62. package/md_cg/mdcg.py +616 -125
  63. package/md_cg/mdcos.py +430 -66
  64. package/md_cg/mreview/govern.py +5 -4
  65. package/md_cg/postings.py +4 -2
  66. package/md_cg/readcache.py +76 -18
  67. package/md_cg/reconcile.py +228 -0
  68. package/md_cg/review_cli.py +170 -0
  69. package/md_cg/routing.py +28 -0
  70. package/md_cg/run_tests.py +211 -0
  71. package/md_cg/scrub.py +862 -852
  72. package/md_cg/security.py +385 -275
  73. package/md_cg/selfreport.py +3 -2
  74. package/md_cg/signer.py +565 -562
  75. package/md_cg/sources.py +3 -2
  76. package/md_cg/stg.py +6 -0
  77. package/md_cg/sustain.py +1168 -1138
  78. package/md_cg/test_access_hints.py +147 -0
  79. package/md_cg/test_branch_discard_tombstone.py +136 -0
  80. package/md_cg/test_branches.py +259 -249
  81. package/md_cg/test_chain_read_isolate.py +168 -0
  82. package/md_cg/test_datapath_device_name.py +203 -0
  83. package/md_cg/test_emit_negtail_cache.py +156 -0
  84. package/md_cg/test_en_pipeline.py +186 -166
  85. package/md_cg/test_govern_directread.py +421 -0
  86. package/md_cg/test_i32_hotcache_env_key.py +218 -0
  87. package/md_cg/test_identity_attribution.py +228 -147
  88. package/md_cg/test_index_durability.py +238 -224
  89. package/md_cg/test_interop.py +4 -2
  90. package/md_cg/test_interop_judgment.py +228 -0
  91. package/md_cg/test_issue39_utf8_stdio.py +273 -0
  92. package/md_cg/test_links_concurrent_write.py +188 -0
  93. package/md_cg/test_merge_upsert.py +168 -0
  94. package/md_cg/test_n123_derive_expiry_chain.py +205 -0
  95. package/md_cg/test_n130_verify_falsified_protect.py +185 -0
  96. package/md_cg/test_n131_merge_gate.py +205 -0
  97. package/md_cg/test_p1x_ref_root.py +160 -0
  98. package/md_cg/test_p27_docindex.py +774 -765
  99. package/md_cg/test_p2_mcp.py +3 -0
  100. package/md_cg/test_p32_backfill.py +304 -298
  101. package/md_cg/test_p39_verify_flow.py +90 -50
  102. package/md_cg/test_p47_session_view.py +60 -25
  103. package/md_cg/test_propose_tail_index.py +157 -0
  104. package/md_cg/test_read_scope_b27.py +277 -0
  105. package/md_cg/test_readcache_default_on.py +168 -0
  106. package/md_cg/test_readcache_precise_inval.py +270 -0
  107. package/md_cg/test_readcache_prodpath.py +55 -7
  108. package/md_cg/test_reconcile_v0.py +294 -0
  109. package/md_cg/test_retr_s1.py +6 -2
  110. package/md_cg/test_retr_s1b.py +67 -0
  111. package/md_cg/test_retr_s7.py +8 -0
  112. package/md_cg/test_retr_s9_entity_ctx.py +181 -175
  113. package/md_cg/test_retr_score_once.py +208 -0
  114. package/md_cg/test_review_onepass.py +170 -0
  115. package/md_cg/test_rrf_graph_seed_cache.py +154 -0
  116. package/md_cg/test_security_audit.py +155 -0
  117. package/md_cg/test_security_audit_b26.py +161 -0
  118. package/md_cg/test_security_audit_v21.py +250 -0
  119. package/md_cg/test_semantic_canonical.py +255 -241
  120. package/md_cg/test_session_isolation.py +168 -0
  121. package/md_cg/test_snapshot_autoclose.py +187 -0
  122. package/md_cg/test_tail_watermark_race.py +208 -0
  123. package/md_cg/test_tenant_env_override_warn.py +139 -0
  124. package/md_cg/test_tenant_registry_corrupt_warn.py +151 -0
  125. package/md_cg/test_v14_fixes.py +415 -397
  126. package/md_cg/test_verify_dirty_reconcile.py +157 -0
  127. package/md_cg/theory.py +276 -273
  128. package/md_cg/tokens.py +734 -677
  129. package/md_cg/units.py +3 -2
  130. package/md_cg/vision_evidence.py +4 -3
  131. package/md_cg/whitebox_kb/wisdom/code_solidified.json +6195 -6195
  132. package/md_cg/whitebox_kb/wisdom/multilang_ir.py +128 -124
  133. package/md_cg/writepipe.py +554 -550
  134. package/package.json +6 -2
  135. package/src/bridge.ts +434 -401
  136. package/src/index.ts +526 -518
  137. package/src/lib/roleplay_web.ts +1019 -932
  138. package/src/lib/token_store.ts +202 -192
package/md_cg/ccgc.py CHANGED
@@ -38,6 +38,7 @@ from dataclasses import asdict, dataclass, field
38
38
  from typing import Any, Dict, List, Optional
39
39
 
40
40
  from . import nodefile
41
+ from .readcache import direct_read
41
42
 
42
43
  # ---- 四态:复用 audit / judge_qualification 的裁决语汇(不新造状态机) ----
43
44
  ACCEPT, REJECT, DEFER, BLINDSPOT = "ACCEPT", "REJECT", "DEFER", "BLINDSPOT"
@@ -754,7 +755,7 @@ def link(compiled: CompileResult, attestation: Optional[AttestResult], *,
754
755
  return out
755
756
 
756
757
  from . import crypto
757
- fm, content = _cg._read(entry)
758
+ fm, content = direct_read(_cg, entry) # 写前重查走盘上真值(读缓存口径)
758
759
  if fm is None or crypto.is_encrypted(content):
759
760
  out.errors.append("E004 " + E_CODES["E004"])
760
761
  return out
@@ -838,7 +839,7 @@ def recalibrate(node_id: str, corrections: Dict[str, Any], verifier: str,
838
839
  return out
839
840
 
840
841
  from . import crypto
841
- fm, content = _cg._read(entry)
842
+ fm, content = direct_read(_cg, entry) # 写前重查走盘上真值(读缓存口径)
842
843
  if fm is None or crypto.is_encrypted(content):
843
844
  out.errors.append("E004 " + E_CODES["E004"])
844
845
  return out
package/md_cg/chain.py CHANGED
@@ -123,7 +123,7 @@ def node_conditions(cg, nid):
123
123
  return pos
124
124
 
125
125
 
126
- # 生效条件:cg 已有 _chain_adj 且其 [0] 等于 bool(include_hierarchy) 时直接返回缓存的 [1];否则以 cg.index["nodes"](无 index 或无该键时视为无节点)逐节点收集 frontmatter.edges 中 edge_target 非空的出边,include_hierarchy 为真时再为 subgraph.nodes 各合成一条 relation_type="part_of"、confidence=1.0 的层级边,仅对有出边的 nid 建表,写回 cg._chain_adj=(bool(include_hierarchy), adj) 后返回 adj;
126
+ # 生效条件:cg 已有 _chain_adj 且其 [0] 等于 bool(include_hierarchy)、[1] 等于可见性闸存在位时直接返回缓存的 [2];否则以 cg.index["nodes"](无 index 或无该键时视为无节点)逐节点收集 frontmatter.edges 中 edge_target 非空的出边,include_hierarchy 为真时再为 subgraph.nodes 各合成一条 relation_type="part_of"、confidence=1.0 的层级边,仅对有出边的 nid 建表,写回 cg._chain_adj=(bool(include_hierarchy), 闸存在位, adj) 后返回 adj;cg 提供 _chain_visible(nid) 谓词(读隔离,MdCGSecure 注入)时不可见 nid 的出边整体不入表、指向不可见目标的边(含层级合成边)截断——不可见节点 id、其边条件与下游拓扑对调用方不存在(walk/explain/causal_path/expand_from_seeds 全部消费者同闸);
127
127
  def adjacency(cg, include_hierarchy=True):
128
128
  """出邻接表:nid → [(target_id, edge_dict)]。
129
129
 
@@ -131,28 +131,43 @@ def adjacency(cg, include_hierarchy=True):
131
131
  1. 节点 frontmatter.edges(关系边,含 relation_type)
132
132
  2. 节点 frontmatter.subgraph.nodes(层级边,合成 part_of)
133
133
  只读索引快照,不读文件正文;结果缓存在 `cg._chain_adj`。
134
+
135
+ 读隔离(2026-09-25):cg._chain_visible(nid) 谓词在位(MdCGSecure 注入,
136
+ = 索引有条目 ∧ _readable)时按其过滤——不可见节点不入表、指向不可见
137
+ 目标的边截断;谓词缺席(基类)行为零变化。缓存键含闸存在位;闸语义
138
+ 实例内稳定(_readable 绑定档判定恒用 principal.session,见 mdcos
139
+ _readable),同一实例不会跨身份串台。
134
140
  """
135
141
  cached = getattr(cg, "_chain_adj", None)
136
- if cached is not None and cached[0] == bool(include_hierarchy):
137
- return cached[1]
142
+ vis = getattr(cg, "_chain_visible", None)
143
+ vis_on = vis is not None
144
+ if (cached is not None and cached[0] == bool(include_hierarchy)
145
+ and cached[1] == vis_on):
146
+ return cached[2]
138
147
  from . import subgraph as _sg
139
148
  nodes = ((getattr(cg, "index", None) or {}).get("nodes") or {})
140
149
  adj = {}
141
150
  for nid in nodes:
151
+ if vis is not None and not vis(nid):
152
+ continue # 不可见节点:其出边与条件整体不可见(不解析 fm)
142
153
  fm = _sg._fm(cg, nid)
143
154
  out = []
144
155
  for e in (fm.get("edges") or []):
145
156
  tgt = edge_target(e)
146
157
  if tgt:
158
+ if vis is not None and not vis(tgt):
159
+ continue # 拓扑边界:指向不可见目标的边对调用方不存在
147
160
  out.append((tgt, e if isinstance(e, dict) else {"target": tgt}))
148
161
  if include_hierarchy:
149
162
  for ch in _sg.declared(fm)["nodes"]:
163
+ if vis is not None and not vis(ch):
164
+ continue
150
165
  out.append((ch, {"target": ch, "relation_type": "part_of",
151
166
  "confidence": 1.0, "verified": 0}))
152
167
  if out:
153
168
  adj[nid] = out
154
169
  try:
155
- cg._chain_adj = (bool(include_hierarchy), adj)
170
+ cg._chain_adj = (bool(include_hierarchy), vis_on, adj)
156
171
  except Exception:
157
172
  pass
158
173
  return adj
@@ -85,6 +85,7 @@ import urllib.request
85
85
  from . import crypto, evolution, nodefile, routing
86
86
  from .fsutil import append_jsonl
87
87
  from .mdcg import BUCKETED_LAYERS, bigrams, expand_query_terms_weighted
88
+ from .readcache import direct_read
88
89
  from .mdcos import (MdCGOS, _ccg_field, _declared_conditions, _neg_hit, _sig,
89
90
  _weighted_coverage)
90
91
 
@@ -675,7 +676,7 @@ def consolidate(root: str, layer: str = None, limit: int = None, apply: bool = F
675
676
  if limit is not None and rep["targeted"] >= limit:
676
677
  break
677
678
  nid = os.path.basename(e["path"])[:-3]
678
- fm, content = cg._read(e)
679
+ fm, content = direct_read(cg, e) # 写前重查走盘上真值(读缓存口径,见 readcache.direct_read)
679
680
  if fm is None:
680
681
  _bump("read_failed")
681
682
  continue
@@ -811,7 +812,7 @@ def fill_verification_basis(root: str, basis: str, layer: str = None,
811
812
  for e in entries:
812
813
  if limit is not None and rep["written"] >= limit:
813
814
  break
814
- fm, content = cg._read(e)
815
+ fm, content = direct_read(cg, e) # 写前重查走盘上真值(读缓存口径)
815
816
  if fm is None:
816
817
  continue
817
818
  if crypto.is_encrypted(content):
@@ -891,7 +892,7 @@ def promote_memories(root, source_layer="contextual", target_layer="knowledge",
891
892
  for e in entries:
892
893
  if limit is not None and rep["written"] >= int(limit):
893
894
  break
894
- fm, content = cg._read(e)
895
+ fm, content = direct_read(cg, e) # 写前重查走盘上真值(读缓存口径)
895
896
  if fm is None:
896
897
  continue
897
898
  if crypto.is_encrypted(content):
@@ -962,7 +963,7 @@ def rollback_promotion(root, node_ids=None, batch=None, actor="maintain") -> dic
962
963
  e = (cg.index.get("nodes") or {}).get(nid)
963
964
  if not e:
964
965
  continue
965
- fm, content = cg._read(e)
966
+ fm, content = direct_read(cg, e) # 回滚比对走盘上真值(读缓存口径)
966
967
  if fm is None or crypto.is_encrypted(content):
967
968
  continue
968
969
  back = rec.get("from") or "contextual"
@@ -1064,7 +1065,7 @@ def contextualize_prefixes(root, prefixes=None, node_ids=None,
1064
1065
  nid = _entry_id(e)
1065
1066
  if not _hit(e):
1066
1067
  continue
1067
- fm, content = cg._read(e)
1068
+ fm, content = direct_read(cg, e) # 写前重查走盘上真值(读缓存口径)
1068
1069
  if fm is None:
1069
1070
  continue
1070
1071
  if crypto.is_encrypted(content):
@@ -1122,7 +1123,7 @@ def rollback_contextualize(root, node_ids=None, batch=None, actor="maintain") ->
1122
1123
  e = (cg.index.get("nodes") or {}).get(nid)
1123
1124
  if not e:
1124
1125
  continue
1125
- fm, content = cg._read(e)
1126
+ fm, content = direct_read(cg, e) # 回滚比对走盘上真值(读缓存口径)
1126
1127
  if fm is None or crypto.is_encrypted(content):
1127
1128
  continue
1128
1129
  back = rec.get("from") or "knowledge"
@@ -36,6 +36,7 @@ from .backfill import (BASIS_ENUM_DEFAULT, BASIS_TEXT, INTERNAL_LAYERS,
36
36
  from .consolidate import _has_ccg_line, _upsert_ccg_line
37
37
  from .fsutil import append_jsonl, read_jsonl
38
38
  from .mdcos import _ccg_field
39
+ from .readcache import direct_read
39
40
 
40
41
  # ---- 常量 ----------------------------------------------------------------
41
42
 
@@ -341,7 +342,7 @@ def _scan(cg, layer=None, ids=None, prefix=None):
341
342
  if not _readable_guard(cg, e):
342
343
  yield {"status": "skip", "reason": "denied", "id": nid}
343
344
  continue
344
- fm, content = cg._read(e)
345
+ fm, content = direct_read(cg, e) # 扫描读喂写面:走盘上真值(读缓存口径)
345
346
  if fm is None:
346
347
  yield {"status": "skip", "reason": "unreadable", "id": nid}
347
348
  continue
@@ -783,7 +784,7 @@ def crosscheck(x, layer=None, limit=None, ids=None, reflect_fn=None,
783
784
  rep["targeted"] += 1
784
785
  nid = row["id"]
785
786
  e = cg.index["nodes"].get(nid)
786
- fm, content = cg._read(e) if e else (None, None)
787
+ fm, content = direct_read(cg, e) if e else (None, None) # 写前重查走盘上真值
787
788
  if fm is None or crypto.is_encrypted(content):
788
789
  rep["skipped_locked"] += 1
789
790
  continue
@@ -938,7 +939,7 @@ def rollback(x, batch=None, entry_ids=None, actor=None) -> dict:
938
939
  if not e:
939
940
  rep["skipped_drift"] += 1
940
941
  continue
941
- fm, content = cg._read(e)
942
+ fm, content = direct_read(cg, e) # 回滚比对走盘上真值(write_id 防护所验 fm 同源)
942
943
  if fm is None or crypto.is_encrypted(content):
943
944
  rep["skipped_drift"] += 1
944
945
  continue