@furongjun1999/dsh-memory 0.6.1 → 0.7.0

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 (48) hide show
  1. package/README.md +48 -18
  2. package/docs/README.md +1 -0
  3. 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
  4. 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
  5. 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
  6. 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
  7. 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
  8. package/docs/mdcg/README/350/257/246/347/273/206/347/211/210_v0.4.10.md +88 -0
  9. 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
  10. package/docs/mdcg//345/217/221/345/270/203/351/227/250/347/246/201/351/223/276_v0.1.md +47 -11
  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
  12. 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
  13. package/md_cg/bench_e2e_locomo_qa.py +11 -4
  14. package/md_cg/chain.py +47 -0
  15. package/md_cg/freshness.py +511 -0
  16. package/md_cg/generation.py +409 -0
  17. package/md_cg/hotcache.py +4 -1
  18. package/md_cg/mcp_server.py +128 -19
  19. package/md_cg/mdcg.py +509 -22
  20. package/md_cg/mdcos.py +203 -22
  21. package/md_cg/nodefile.py +74 -1
  22. package/md_cg/semantic/canonical.py +22 -0
  23. package/md_cg/semantic/unify.py +73 -22
  24. package/md_cg/semantic/unify_fixture.json +25 -0
  25. package/md_cg/sleep.py +1297 -0
  26. package/md_cg/sustain.py +146 -9
  27. package/md_cg/test_auto_defaults.py +424 -0
  28. package/md_cg/test_boundary_hit.py +410 -0
  29. package/md_cg/test_en_pipeline.py +22 -13
  30. package/md_cg/test_generation_guard.py +352 -0
  31. package/md_cg/test_h4_sustain_snapshot.py +14 -4
  32. package/md_cg/test_n212_n213_n224_generation_gates.py +14 -8
  33. package/md_cg/test_n230_dirty_replay.py +375 -0
  34. package/md_cg/test_p2_six_elements.py +463 -0
  35. package/md_cg/test_p3_legacy_closure.py +433 -0
  36. package/md_cg/test_p4_freshness.py +680 -0
  37. package/md_cg/test_p8_subgraph_chain.py +14 -1
  38. package/md_cg/test_rank_parity_score_mode.py +6 -0
  39. package/md_cg/test_semantic_canonical.py +5 -3
  40. package/md_cg/test_sleep.py +611 -0
  41. package/md_cg/test_sleep_p1.py +784 -0
  42. package/md_cg/test_time_core_lint.py +968 -0
  43. package/md_cg/test_unify_default_off.py +701 -0
  44. package/md_cg/test_unify_scope.py +182 -0
  45. package/md_cg/whitebox_kb/aeis_core/time_core.py +8 -0
  46. package/package.json +3 -2
  47. package/skills/plugin.json +1 -1
  48. package/utf8_boot.py +237 -0
@@ -1,27 +1,76 @@
1
1
  # 检索算法口径对照 v0.1(批次 15)
2
2
 
3
3
  > 2026-09-23 使用者口径定案:**统一翻译为中文 → 中文归一化到标准中文集(atoms 词表)→ 检索**。
4
+ > **2026-09-30 使用者裁定收窄作用域**:归一层**只对英文内容做翻译归一,中文内容原样不动**。
5
+ > **2026-09-30 使用者裁定翻缺省**:`MDCG_UNIFY_QUERY` 由「默认开」翻为「**未设即关**、
6
+ > 显式 `=1` 才开」——本层本职是让英文 query 命中中文节点,对中文检索池是纯开销
7
+ > (locomo-zh-500 实测缺省关态 lexical hit@1 96.4% / lexical+fuzzy 97.2%,
8
+ > 开态 95.8% / 96.6%);两侧三态判据同语义。
4
9
  > 本文是该口径的两侧实现对照与残留差距真源——两侧实现以本文为准,改动检索口径先改本文。
5
10
 
6
11
  ## 一、统一管线(两侧同构)
7
12
 
8
13
  ```
9
14
  query(任意语言)
10
- │ MDCG_UNIFY_QUERY=0 可整体关回退(默认开 = 口径定案转正)
15
+ │ MDCG_UNIFY_QUERY=1 可整体开(**默认关**——2026-09-30 裁定:本层只服务英文 query)
11
16
  ▼
12
- [统一归一层 unify]
13
- ├─ 纯中文 → 原样(bigrams 去空白后与原文等价,零变更纪律)
14
- ├─ 含英文 → en 形态归一(小写/停用词/时态归零)
17
+ [统一归一层 unify] —— 作用域(2026-09-30 收窄):**只译英文内容,中文原样不动**
18
+ ├─ 分段判据单点:中文 = CJK 统一表意文字基本区 U+4E00–U+9FFF
19
+ │ Python `semantic/canonical.py::is_zh_char` / Rust `text.rs::is_zh` 同判据
20
+ ├─ query 无 ASCII 字母 → 原样返回(纯中文零变更纪律,不 strip)
21
+ ├─ 中文段 → **逐字保留、绝不切分、绝不送 segment**
22
+ ├─ 含 ASCII 字母的非中文段 → en 形态归一(小写/停用词/时态归零)
15
23
  │ → en→zh 词表映射(en_zh_map.json,28478 词,CEDICT 全链派生)
16
24
  │ → 未登录词原样保留(unknown_keep = 词表边界,非错误)
17
- ├─ 中文段 → segment 贪心最长匹配(zh_keys 204 标准原子,键长降序)
25
+ │ → 映射产物经 segment 贪心最长匹配(zh_keys 204 标准原子,键长降序)
26
+ ├─ 不含 ASCII 字母的非中文段(数字/标点)→ 原样保留
27
+ ├─ 各段按原顺序单空格 join;空白(段内/段间)一律折叠为单空格
28
+ ├─ 归一产物为空(折空白后)→ **回退原入参本身(含首尾空白,不 trim)**——
29
+ │ 两侧同语义:Python `return text` / Rust `query.to_string()`(见 §六)
18
30
  ▼
19
- 标准原子序列(空格 join,如 "我 吃 牛肉 昨天")
31
+ 标准原子序列(空格 join,如 "我 吃 牛肉 昨天";
32
+ 中夹英 "领养 LGBTQ 群体" → **Python 侧**原样,旧口径会切成
33
+ "领 养 LGBTQ 群 体";Rust 侧对未登录大写词的产物是
34
+ "领养 lgbtq 群体"——**两侧既有非对称**见下「一之补」表第 ① 条)
20
35
  ▼
21
36
  检索各路(lexical / bucket / entity / graph,RRF 融合)
22
37
  —— doc 侧正文不动(真源+原始双保留纪律),只有 query 侧归一
23
38
  ```
24
39
 
40
+ **为何收窄(2026-09-30 定因,实测)**:旧口径「query 含任一 ASCII 字母即整条
41
+ 归一」会把**中夹英** query 的中文部分逐字切开(「自我接纳」→「自 我 接 纳」、
42
+ 「慈善跑」→「慈 善 跑」)。locomo-zh-500 公开题池(567 池 / 500 题,
43
+ `eval_common` jaccard + GLOBAL_CAP 解除,k=5):现状 lexical hit@1 = 94.4% /
44
+ lexical,fuzzy = 87.2%;收窄后 **95.8% / 96.6%**;归一层全关 96.4% / 97.2%。
45
+ 500 题里含 ASCII 字母的 145 条**全部**也含中文(题池无纯英文 query)。
46
+ 复现:`python -X utf8 -m md_cg.bench_locomo_zh_public`。
47
+ **2026-09-30 翻缺省后**:缺省态(= 归一层关)即取 **96.4% / 97.2%** 这一行,
48
+ 显式 `MDCG_UNIFY_QUERY=1` 才回到 95.8% / 96.6%。
49
+ (以上为本次收窄的定点实测读数,仅作口径变更的证据——仓库对外参考值/
50
+ README 数字不因本任务变动,数字回流由编排侧另行核。)
51
+
52
+ ### 一之补 · 两侧既有非对称(非本次收窄引入,2026-09-30 实测)
53
+
54
+ 下表三条是两侧实现的**既有分歧**,非 2026-09-30 收窄引入、也非本清理批次引入——
55
+ **收窄前对照实测同分歧**(收窄前 = `HEAD~1`:Python 侧按
56
+ `git show HEAD~1:md_cg/semantic/unify.py` 的整条归一路径
57
+ `" ".join(query_atoms(t))` 实跑;Rust 侧用 `git archive HEAD~1 rust` 导出到临时目录、以临时
58
+ cargo 工程(独立构建目录,不碰仓库 `rust/target/`)重建后实跑 `Atoms::unify`);该提交亦**未触碰**
59
+ `en_normalizer.py`(`git show --stat HEAD` 可见)。读数取法:Python 走
60
+ `md_cg.semantic.unify.unify_query`,Rust 走 `atoms.rs::Atoms::unify`
61
+ (两侧消费同一份 `en_zh_map.json`)。
62
+
63
+ | # | 形态 | Python 产物 | Rust 产物 | 根因(各自实现内) |
64
+ |---|---|---|---|---|
65
+ | ① | 未登录**大写**英文词 | `领养 LGBTQ 群体` → `领养 LGBTQ 群体`;`AI 记忆 系统` → `AI 记忆 系统`(保留原 case) | `领养 lgbtq 群体`;`ai 记忆 系统` | Python:未登录词 unknown_keep 原样;Rust:先经 `normalize_en`(一律 lower)再查表,未命中以 lower 形占位 |
66
+ | ② | 命中词表的**专名** | `Paris 报告` → `Paris 巴 黎 报告`(原词 + 译词**双原子**) | `巴 黎 报告`(只出译词) | Python `en_normalizer` 的 `is_proper` + 词表命中 → `proper_mapped_both` 双原子;Rust 无该分支 |
67
+ | ③ | 字母与数字**同段** | `beef 2024 报告` → `牛肉 报告`(**丢数字**) | `牛肉 2024 报告`(**保数字**) | Python `normalize_en_query` 分词类 `[A-Za-z\u4e00-\u9fff]+` 不含数字;Rust 侧 ASCII 数字词元保留、未登录则原样占位 |
68
+
69
+ **为何 fixture 避开这三类形态**:`md_cg/semantic/unify_fixture.json` 是**两侧钉同一期望值**的
70
+ 逐位对拍件(Rust 侧 `include_str!` 编译期嵌入),上表三条两侧产物不同 ⇒ 钉不出同一期望值,
71
+ 故该文件只登记「两侧同构」形态,`_caveat` 亦指向本节(正文为真源)。**是否把某一侧改成另一侧
72
+ 口径,见 §七 待裁定项——本文不自行定方向。**
73
+
25
74
  ## 二、词表真源单侧化(架构决策)
26
75
 
27
76
  | 资产 | 真源 | 产物 | Rust 消费 |
@@ -41,7 +90,9 @@ query(任意语言)
41
90
 
42
91
  | 环节 | Python | Rust | 对齐守卫 |
43
92
  |---|---|---|---|
44
- | 统一归一入口 | `semantic/unify.py::unify_query`(三处 search 入口接线) | `atoms.rs::Atoms::unify`(`engine.search` 单点接线) | rank_parity 逐位对拍 |
93
+ | 统一归一入口 | `semantic/unify.py::unify_query`(三处 search 入口接线;`unify_on()` 缺省关,显式 `"1"` 才开) | `atoms.rs::Atoms::unify`(`engine.search` 单点接线;`from_env()` 未设/`"0"`→`None`,显式 `"1"`→`Some`) | rank_parity 逐位对拍——**两个口径,读数不同**:内建合成语料 **10/10 绿**(rc=0,**门禁腿跑的就是这个口径**);`--dataset` 口径**缺省 10/10 绿**(2026-09-30 翻缺省后),**显式 `MDCG_UNIFY_QUERY=1` 时 8/10(既有差分,差在归一层)**,见 §五.2。三态一致性另由 `md_cg/test_unify_default_off.py` 钉住 |
94
+ | 中文段分段判据(单点) | `semantic/canonical.py::is_zh_char`(U+4E00–U+9FFF;边界=**长度恰为 1**,空串/多字符串一律假) | `text.rs::is_zh`(同区间;收 `char`,天然无空/多字符二态) | `semantic/unify_fixture.json` 两侧逐位对拍(19 例) |
95
+ | 归一层作用域(只译英文) | `md_cg/test_unify_scope.py` | `atoms::tests::unify_mixed_fixture_matches_python` | 同一 fixture 两侧钉同一期望值;Python 侧另有**对产物**的结构判据(第 6 节:中文段逐字保留、不得送 segment) |
45
96
  | en 形态归一 | `en_normalizer.strip_tense` | `text.rs::strip_tense_en`(golden 对齐测试) | golden_python_alignment |
46
97
  | en→zh 查表 | normalize_en_query 查链(extra→EN_ZH→CEDICT) | en2zh 查表(键=strip 后原形,lower) | 同一 en_zh_map.json |
47
98
  | segment | `zh_en_atoms.segment` | `atoms.rs::segment`(键长降序贪心) | atoms 三测 + rank_parity |
@@ -68,9 +119,25 @@ path_weights 调优消化。
68
119
  `swarm-dispatch`)时,中文 query 经 `bucket_key_readable`+`domain_similarity`
69
120
  恒 no_key_match → 不收敛。恰击中 S1b 设计目标场景(真实库 91.1% 中文节点)。
70
121
  方向:桶键双语化 / domain_similarity 中文面。
71
- 2. **对拍逐位残留**(issue #29 未清项的精确化):unify=0 基线 9/10、unify=1
72
- 8/10。差异集中于两侧 terms 展开对英文保留词的处理与 graph 路种子——两侧
73
- lexical 路细节差,归一层无关(基线态已现)。
122
+ 2. **对拍逐位残留——两个口径,读数不同(门禁绿 ≠ dataset 对拍绿)**
123
+ (issue #29 未清项的精确化;2026-09-30 实测,两侧实际口径均 jaccard):
124
+
125
+ | 口径 | 命令 | 逐位 | 集合 | top-1 | rc |
126
+ |---|---|---|---|---|---|
127
+ | **内建合成语料**(**门禁腿跑的就是这个口径**) | `python -X utf8 scripts/rank_parity.py --exe rust/target/release/mdcg-eval.exe` | **10/10** | 10/10 | 10/10 | **0(绿)** |
128
+ | `--dataset` 口径(**缺省**:归一层缺省关) | 同命令 + `--dataset scripts/retrieval_dataset.json` | **10/10** | 10/10 | 10/10 | **0(绿)**(2026-09-30 翻缺省后实测) |
129
+ | 同上 + 归一层**显式开** | 再加 `MDCG_UNIFY_QUERY=1` | **8/10** | 8/10 | 9/10 | **1(差分)** |
130
+
131
+ 两条 DIFF = `soul hub hot cache` 与 `token verification fail closed`。差分出在
132
+ **归一层**(关 unify 即 10/10),但**不是本次收窄引入**:上一批复核员把 HEAD
133
+ (=收窄产物,`git archive HEAD` 导出 + 独立 `CARGO_TARGET_DIR` 重建)同口径实跑
134
+ 同为 8/10 ⇒ **既有状态**(三项读数出自上一批复核;本批复跑的是工作树同三口径,
135
+ 读数逐位一致)。机制是两侧 terms 展开对英文保留词的处理与 graph 路种子。
136
+ **2026-09-30 缺省翻关的连带效应**:`--dataset` 口径的**缺省态**读数由 8/10 变为
137
+ **10/10 rc=0**(缺省 = 归一层关 = 原来的「全关」行);两条 DIFF 只在**显式
138
+ `MDCG_UNIFY_QUERY=1`** 时重现,逐位重现(8/10 · 8/10 · 9/10,DIFF 两条同名前缀)。
139
+ **是否把 `--dataset` 口径并入门禁腿:见 §七 待裁定项 1**——本文不自行决定
140
+ (该口径缺省已绿,但显式开归一层时恒 8/10,并入前须先裁定该差分归属)。
74
141
  3. **CEDICT 低置信错译**:dispatch→「结果」类第一义项直译(LoCoMo 报告发现 5
75
142
  同模式)。en_zh_map 保留 CEDICT 层(覆盖面)+ low_confidence 观测,错译随
76
143
  用随修进 EN_ZH 人工层。
@@ -79,7 +146,65 @@ path_weights 调优消化。
79
146
 
80
147
  ## 六、变更纪律
81
148
 
82
- - `MDCG_UNIFY_QUERY` 默认 "1"(转正);`=0` 显式关回退,两侧同一 env。
149
+ - `MDCG_UNIFY_QUERY` **默认关**(2026-09-30 使用者裁定,由「默认 "1"」翻为「未设即关」);
150
+ 两侧三态判据同语义,**唯一开态 = 显式 "1"**:
151
+ 未设 → Python `unify_on()` `False` / Rust `Atoms::from_env()` `None`;
152
+ `"0"` → 同上(关);`"1"` → `True` / `Some(Atoms)`(开)。
153
+ 两侧同一 env,判据落点:Python `md_cg/semantic/unify.py::unify_on`
154
+ `os.environ.get("MDCG_UNIFY_QUERY", "0") == "1"`;
155
+ Rust `rust/src/atoms.rs::Atoms::from_env`
156
+ `std::env::var("MDCG_UNIFY_QUERY").as_deref() != Ok("1") → None`。
157
+ 三态守卫 `md_cg/test_unify_default_off.py`(含两侧一致性与定点变异自证)。
158
+ - **归一层作用域(2026-09-30 收窄)**:只对英文内容做翻译归一,中文段逐字保留
159
+ ——中文判据单点两侧同区间(`canonical.is_zh_char` / `text.rs::is_zh`);
160
+ 逐位对拍 fixture `md_cg/semantic/unify_fixture.json`(两侧钉同一份期望值),
161
+ 改任一侧实现必先同步另一侧并跑两份守卫。
162
+ - **中文判据边界**:Python `is_zh_char` **仅长度恰为 1 的串可为真**(空串/多字符串
163
+ 一律 False);Rust `is_zh` 收 `char` 天然同语义。两侧边界约定写在各函数 docstring。
164
+ - **空产物回退**:归一产物为空时两侧**原样返回原入参(含首尾空白,不 trim)**
165
+ ——Python `unify_query` 尾行 `return text`,Rust `Atoms::unify` 的
166
+ `query.to_string()`(2026-09-30 清理批次乙1 修正:此前 Rust 误为 `query.trim()`);
167
+ fixture「空产物回退·原样返回原入参(不 trim)」例钉住。
168
+ - **两侧既有非对称三条**(§一之补)**尚未统一**——改任一条都属**改语义**,须先由
169
+ 使用者裁定方向(§七 待裁定项 2),再两侧同改 + 更新本节与 fixture。
83
170
  - 词表再生成:`python -m md_cg.semantic.export_en_zh_map` → 两侧自动同源。
84
171
  - 对拍命令:`python scripts/rank_parity.py --dataset scripts/retrieval_dataset.json --ab`
85
172
  (A/B 证据)+ 同命令去 `--ab`(逐位对拍)。
173
+
174
+ ## 七、待裁定项(2026-09-30 清理批次登记;本文不自行定方向)
175
+
176
+ ### 1. `--dataset` 对拍口径是否并入门禁腿?
177
+
178
+ 现状(§五.2 表):门禁腿跑**内建合成语料**口径(10/10 绿,rc=0);`--dataset` 口径
179
+ 在 **2026-09-30 缺省翻关后缺省态已绿(10/10 rc=0)**,只在**显式
180
+ `MDCG_UNIFY_QUERY=1`** 时回到 8/10 rc=1(既有差分,非本次收窄引入)。**本批未并入**
181
+ ——该腿对归一层开关敏感(开关一开即 8/10),并入前若不清因,等于给门禁留一条
182
+ 「看 env 的脸色」的腿,失去门禁信号价值。
183
+ 待裁定:①先清掉那两条 DIFF 再并入;②或把 `--dataset` 永久留在证据面(`--ab` 路径)
184
+ 不进门禁。**在裁定前不得并入。**
185
+
186
+ ### 2. §一之补 的三条两侧既有非对称统一到哪一侧?
187
+
188
+ **后果读数**(2026-09-30 实测):locomo-zh-500 公开题池(池 567 / 题 500,
189
+ `eval_common` jaccard + GLOBAL_CAP 解除,k=5),Python 侧用**进程内 monkeypatch**
190
+ 量(不改仓库文件;patch 包在 `en_normalizer.normalize_en_query` 外层,随后跑与
191
+ `python -X utf8 -m md_cg.bench_locomo_zh_public` 同一口径;池与结果均落临时目录):
192
+
193
+ | 态 | lexical hit@1 | lexical,fuzzy hit@1 | MRR(lexical / lex,fuzzy) |
194
+ |---|---|---|---|
195
+ | 现状(Python 保留原 case、字母数字同段丢数字) | **95.8%** | **96.6%** | 0.9755 / 0.9821 |
196
+ | 把 Python 的未登录大写词改 lower(= 向 Rust ①侧靠) | 95.8% | 96.4%(−0.2pp) | 0.9755 / 0.9811 |
197
+ | 把 Python 的字母数字同段改为保数字(= 向 Rust ③侧靠) | 96.2%(+0.4pp) | 96.6%(持平) | 0.9775 / 0.9821 |
198
+
199
+ 读数边界(如实声明,勿外推):
200
+ - 「大写 lower」patch 的判据是「term 含 ASCII 字母即 lower」⇒ 它同时覆盖第 ① 条
201
+ **与第 ② 条的原文原子大小写面**(`Paris`→`paris`),但**未动** ② 的双原子结构;
202
+ - 「保数字」patch 把数字串**追加在该段原子序列末尾**(段内原位插入会略改 bigram
203
+ 组合),属近似实现;
204
+ - **第 ② 条「专名双原子」未单独量**(需改 `is_proper` + 词表命中分支,patch 面更大)
205
+ ——缺读数即声明缺,不填猜测值。
206
+
207
+ ⇒ 结论:两条可量项都**未达「明确该改」的强度**(①向 Rust 靠在这两路不增益甚至
208
+ fuzzy −0.2pp;③向 Rust 靠 lexical +0.4pp、fuzzy 持平),且两条都动两侧共享语义面
209
+ (Rust 侧改需同步改 `normalize_en` 的 lower 语义或新增双原子分支)。**故本批只披露
210
+ 读数,统一到哪一侧由使用者裁定;裁定后两侧同改 + 更新 §一之补 / fixture / 守卫。**
@@ -22,7 +22,8 @@
22
22
  情境输入(query, context)
23
23
  ↓ S1 大域先验收敛 terms → big_domain_classify → 域集合;候选 = 该域节点 ∪ ORPHAN 兜底
24
24
  ↓ S2 条件空间前置门控 condition_space 硬槽(time_window/observation_position/存在约束)不匹配 → 不进候选
25
- ↓ S3 图扩散激活 以 (S1∩S2) 命中为种子,沿 edges 双向扩散 N 跳、按跳数衰减;不走全表
25
+ ↓ S3 图扩散激活 以 (S1∩S2) 命中为种子,沿 edges 双向扩散 N 跳、按跳数衰减;不读正文
26
+ (邻接构建为 O(N) 索引条目级——见 §3 S3 的代价口径)
26
27
  ↓ S4 层级激活优先级 anchor/self 初始激活值加成(认知优先级,不是过滤)
27
28
  ↓ S5 负记忆抑制 rejected/unresolved 命中 → 对相关正候选乘性降权(抑制信号)
28
29
  ↓ S6 一致性交叉验证 对最终 top-k 做 crosscheck(复用 md_cg/crosscheck.py)
@@ -49,7 +50,17 @@
49
50
  ### S3 图扩散激活
50
51
  - 输入:种子集合、`edges`(出边在 `fm.edges`;白箱 KB 的 `edges` 表按 source/target 双索引)
51
52
  - 输出:激活集合 + 激活值(种子 1.0,第 n 跳 × 衰减^n)
52
- - 不变量:扩散**不得引入未通过 S2 门控**的节点;边方向/关系类型权重可配
53
+ - 不变量:扩散**不得引入未通过 S2 门控**的节点;边方向/关系类型权重**部分可配**
54
+ (2026-10-01 勘误,**P3 遗留 ④ 如实降级**:实测只有「关系类型**集合**」可配
55
+ ——`MDCG_CHAIN_TYPES`(`md_cg/chain.py`,缺省 `CHAIN_TYPES_DEFAULT`);边权数值
56
+ **沿用唯一表** `EDGE_WEIGHTS`(真源唯一,不提供第二处可配口径);方向**固定为
57
+ 依赖方向(出边)**(`walk(direction="out")` 缺省)。⇒ 本不变量属**部分满足**)
58
+ - 代价口径(2026-10-01 勘误,**P3 遗留 ⑥ 如实降级**):原文「**不走全表**」与实测
59
+ 不符——`chain.adjacency`(`md_cg/chain.py:152`)遍历**全部索引节点**建出邻接,
60
+ 只是**不读正文**(`subgraph._fm` 优先走索引快照)。正确表述:**不读正文;
61
+ 邻接构建为 O(N) 索引条目级**。代价读数(`scripts/p2p4_probe.py` R7,400 条目
62
+ 确定性小库):冷建 ~0.24ms、缓存命中 ~1µs。可选硬化路径:在索引快照的**边集合**
63
+ 上增量构建邻接(本轮未做)
53
64
  - 失败模式:图稀疏(实测 142 节点 / 87 边)→ 覆盖不足,必须保留域内 LIKE 兜底
54
65
 
55
66
  ### S4 层级激活优先级
@@ -96,6 +107,25 @@ S1/S1b/S2/S4 由 `md_cg/mdcg.py::apply_retrieval_gates` **唯一实现**;三
96
107
  读入口新增或覆写时:**必须**在表中登记并给出门控状态;未登记的读入口按「缺口」处理
97
108
  (issue #25 与 C-8 是同一病灶的两次复发:新增入口时漏接共享门控)。
98
109
 
110
+ ### 4.2 读侧**语言面**分叉(2026-10-01 登记 · P3 遗留 ③)
111
+
112
+ **Python 与 Rust 两侧的缺省路集本就不同**,本表必须显式登记,**不得**被读成
113
+ 「对拍通过」:
114
+
115
+ | 侧 | 缺省路集 | 出处 |
116
+ | --- | --- | --- |
117
+ | Python | **6 路**:lexical / bucket / entity / graph / chain / temporal | `md_cg/mdcos.py::search_rrf` 的 `paths` 缺省值 |
118
+ | Rust | **4 路**:lexical / bucket / entity / graph | `rust/src/engine.rs::SearchEngine::open`(`EngineConfig.paths == None` 时的字面量) |
119
+
120
+ Rust 读侧尚未实现 `chain` / `temporal`(以及本批新增的**六要素后两行索引键**)、
121
+ 未实现 `freshness` 之外的 Python 侧多路。⇒ `scripts/rank_parity.py` 现在仍报
122
+ 10/10,**只因其语料无边、无时间参数、无六要素后两行声明**(缺省差异在这类语料上
123
+ 不产出可观测差),**不是**「两侧已对齐」的证据。
124
+
125
+ 事实钉住面:`md_cg/test_p3_legacy_closure.py`(`--mutate` 自证)逐条断言
126
+ 「Rust 缺省四路」字面量与「Python 缺省六路」并存且**不相等**——防止有人把
127
+ rank_parity 的 10/10 误读成对拍通过。
128
+
99
129
  ## 5. 验收判据(每阶段都要过)
100
130
 
101
131
  1. **等价性**:开关关 → `scripts/run_tests.py md_cg` 全绿,且返回与现状一致(快照对比);
@@ -559,6 +559,94 @@ npm install && npm run build # 构建插件本身(tsc → lib/)
559
559
 
560
560
  完整示例见 [`cordis.yml.example`](../../dsh/cordis.yml.example)。
561
561
 
562
+ ### ♻️ 升级后须重启长驻 MCP 进程(代校验 · `generation`)
563
+
564
+ > **运维前提(一句话)**:**代码换代 ⇒ 重启常驻 MCP 进程**。本条不是「可选优化」,是使用前提。
565
+
566
+ #### 根因(已定因,第 4 条条件层)
567
+
568
+ 灵枢的大脑(`md_cg`)以 **stdio 长驻进程**形态接入(`python -m md_cg.mcp_server`),而
569
+ CPython 只在模块**首次导入**时读盘:此后进程一直用内存里的模块对象。与此同时,`md_cg`
570
+ 内有**大量写在函数体内的延迟导入**(AST 实测函数内跨模块相对导入 328 处;其中相当一部分
571
+ 是**为避开循环导入**才写在函数里的)。
572
+
573
+ 两者叠加 ⇒ **升级后跨代混用**:升级**前**已载入的模块停留在旧代,升级**后**才被惰性导入
574
+ 的模块是新代,同一个进程里两代并存。实测症状(0.6.1 发版轮):
575
+
576
+ ```
577
+ cg 写入返回 ImportError: cannot import name 'mint_auto_id' from 'md_cg.mdcg'
578
+ ```
579
+
580
+ 而此刻**盘面完全正常**——新解释器导入同一模块成功、`md_cg/mdcg.py` 里就是
581
+ `def mint_auto_id(...)`。也就是说:**报错点(延迟导入被执行的那一刻)离根因(进程停在旧代)
582
+ 很远**,不重启的话重试多少次都一样。
583
+
584
+ #### 自检:对运行中的 serve 调 `cg(op=info)`
585
+
586
+ 响应里以**纯增量**方式多出五个键(既有键名/键值/嵌套结构一字未动),字段表如下
587
+ (真源=`md_cg/generation.py` 的 `generation.report()`):
588
+
589
+ | 键 | 类型 | 含义 |
590
+ |---|---|---|
591
+ | `code_generation` | string | 本进程**启动那一刻**的代码指纹前 12 位(=进程实际持有的那一代) |
592
+ | `disk_generation` | string \| null | **此刻盘面**上代码的指纹前 12 位;盘面读不到时为 `null` |
593
+ | `stale_on_disk` | bool | 两者不同 ⇒ 磁盘代码已换代(`true`) |
594
+ | `restart_required` | bool | 是否需要重启本进程(与 `stale_on_disk` 同真值) |
595
+ | `hint` | string | 中文一句话处置指引(`stale_on_disk` 为真时给出「重启常驻 MCP 进程」) |
596
+
597
+ 判读:`stale_on_disk: true` 即「**这个进程停在旧代上**,盘面已经是新代」——重启即可。
598
+
599
+ **指纹口径**(`generation.fingerprint()`):对 `md_cg/**/*.py`(跳过 `__pycache__` 与
600
+ `test_*.py`)按**排序后的(相对路径, 文件字节)**算 sha256,取十六进制串。用**内容哈希**
601
+ 而不是 `mtime`/`size`:打包 / 解压 / 校验回写造成的「无改动重写」会变 mtime 而不变内容,
602
+ 用 mtime 会**假报换代**、把使用者引向无谓的重启。开销(本机实测):指纹实际只读
603
+ **197 个非 `test_` 的 `.py`,约 10ms/次**;即使对全量 418 个 `.py` / 约 11.7 MB 做同类
604
+ 内容哈希也只需约 17ms——因此可以挂在每次 `op=info` 上。
605
+
606
+ #### 启动闸:延迟导入自检(`verify_delegations()`)
607
+
608
+ 服务**真正开始服务之前**(`md_cg/mcp_server.py::main()` 内,非模块顶层——顶层调用会与
609
+ 函数内延迟导入的避环设计冲突),对盘面上每个「函数内相对导入」逐项做「**导入目标模块 →
610
+ 取名字**」(`importlib.import_module` 对已加载模块直接返回内存实例,所以查的是**本进程实际
611
+ 持有的那个模块**)。判定三分:
612
+
613
+ | 形态 | 判定 | 处置 |
614
+ |---|---|---|
615
+ | 目标模块可导入、但**没有这个名字** | **致命** | 抛 `GenerationError`:拒绝启动(非零退出),stderr 点名**目标子模块 + 名字 + 引用处** |
616
+ | 名字是**包内子模块名**而该子模块不在盘面 | 非致命 | 记入 `unavailable`(`whitebox_kb/aeis_core` 的「身体/世界模型」面就属此类:其 docstring 明写「不带走…缺失即自动降级」) |
617
+ | **目标模块本身**不在盘面 / 导入失败 | 非致命 | 记入 `unavailable`(外部可选模块未装) |
618
+
619
+ 启动 stderr 会打一行读数:`代校验:延迟导入 N 项 / 目标模块 M 个 / 已解析 K 项 / 可选缺失 J 项 · 代 <12位>`。
620
+ 于是「半升级」(引用方已是新代、被引用模块还是旧代或缺文件)会在**启动期**就暴露,而不是等到
621
+ 某次写入才以 `ImportError` 的面目炸出来。注意这条自检**只查名字存在性**:不执行被导入者、
622
+ 不校验签名与行为,也不覆盖 `import x.y` 绝对导入与 `importlib.import_module("…")` 字符串形态。
623
+
624
+ #### 处置
625
+
626
+ **重启常驻 MCP 进程即可,记忆数据无损**:
627
+
628
+ - DSH 侧:重启 DSH(或刷新 Web UI,让插件重拉大脑子进程);
629
+ - 其它宿主(CodeBuddy / ZCode / Codex CLI / Claude Code 等):重连该 MCP server。
630
+
631
+ 盘面真源(认知图 md)一个字都没动——重启只是让进程**重新只读一代代码**。**不做热重载**:
632
+ 热重载会与函数内延迟导入的避环设计冲突,还会把已加载模块的类身份打散。
633
+
634
+ #### 守卫(改这条链路必须跑)
635
+
636
+ ```bash
637
+ python -X utf8 -m md_cg.test_generation_guard # 退出码 0 = 全绿
638
+ ```
639
+
640
+ 五项:①对当前树(逐字节临时副本)`verify_delegations()` 全绿并打印委托项数/目标模块数;
641
+ ②定点变异(临时副本里把 `mdcg.py` 的 `mint_auto_id` 定义改名)必须抛 `GenerationError`
642
+ 且消息逐字点名 `md_cg.mdcg` + `mint_auto_id`;③改一个源文件后 `is_stale()` 必须为
643
+ `True`、恢复后必须为 `False`;④AST 断言 `generation.verify_delegations(` 的调用不在
644
+ `mcp_server.py` 模块顶层;⑤`cg(op=info)` 键集对拍(五个新键齐备、既有 18 键一字未动)。
645
+ 守卫全程在 `tempfile.mkdtemp()` 临时目录内进行,不写工作区、不碰在役记忆库。
646
+
647
+ **不适用条件**:本代校验不回答「哪一代更正确」(只回答盘面与进程是否同代,跨代一律重启);
648
+ 不构成「所有延迟导入都能跑通」的完备证明;同一进程内改盘不会自动重载——这正是要重启的原因。
649
+
562
650
  ## 配置项
563
651
 
564
652
  | 字段 | 类型 | 默认值 | 说明 |
@@ -41,42 +41,42 @@ MCP stdio:md_cg/mcp_server.py
41
41
 
42
42
  | 功能 | 显式调用 | 代码位置(点击直达源码行) |
43
43
  |---|---|---|
44
- | 按需披露(投影后完整工具 / 参数文档即时取回) | `cg(op=help)` | [`help`](https://github.com/FuRongJun-1999/dsh-memory/blob/main/md_cg/mcp_server.py#L2054) → [`_help_call`](https://github.com/FuRongJun-1999/dsh-memory/blob/main/md_cg/mcp_server.py#L1972) |
45
- | 验证态 / 双时间轴 / 履历(含冷路径队列;只读) | `cg(op=status)` | [`status`](https://github.com/FuRongJun-1999/dsh-memory/blob/main/md_cg/mcp_server.py#L2060) → [`_status_call`](https://github.com/FuRongJun-1999/dsh-memory/blob/main/md_cg/mcp_server.py#L1887) |
46
- | 三元组反查(派生边任意端 / 谓词 / 时间反查;只读) | `cg(op=edges)` | [`edges`](https://github.com/FuRongJun-1999/dsh-memory/blob/main/md_cg/mcp_server.py#L2063) → [`_edges_call`](https://github.com/FuRongJun-1999/dsh-memory/blob/main/md_cg/mcp_server.py#L1943) |
47
- | 理论检索(领域理论 / 方法论文) | `cg(op=theory)` | [`theory`](https://github.com/FuRongJun-1999/dsh-memory/blob/main/md_cg/mcp_server.py#L2066) → [`theory`](../../md_cg/theory.py) |
48
- | 记忆互链(节点间链接管理) | `cg(op=link)` | [`link`](https://github.com/FuRongJun-1999/dsh-memory/blob/main/md_cg/mcp_server.py#L2083) → [`evidence`](../../md_cg/evidence.py) → [`links`](../../md_cg/links.py) → [`provenance`](../../md_cg/provenance.py) → [`security`](../../md_cg/security.py) → [`signer`](../../md_cg/signer.py) |
49
- | 服务信息 / 健康 | `cg(op=info)` | [`info`](https://github.com/FuRongJun-1999/dsh-memory/blob/main/md_cg/mcp_server.py#L2199) → [`audit`](../../md_cg/audit.py) → [`links`](../../md_cg/links.py) → [`nodefile`](../../md_cg/nodefile.py) → [`theory`](../../md_cg/theory.py) |
50
- | 路由:意图→知识+建议能力 | `cg(op=route)` | [`route`](https://github.com/FuRongJun-1999/dsh-memory/blob/main/md_cg/mcp_server.py#L2225) |
51
- | 读取(按 id / 召回 / 预算) | `cg(op=read)` | [`read`](https://github.com/FuRongJun-1999/dsh-memory/blob/main/md_cg/mcp_server.py#L2246) → [`refindex`](../../md_cg/refindex.py) |
52
- | 写入(含冲突检测 / 闸门 / 审核) | `cg(op=write)` | [`write`](https://github.com/FuRongJun-1999/dsh-memory/blob/main/md_cg/mcp_server.py#L2301) → [`writepipe`](../../md_cg/writepipe.py) |
53
- | 目标(写入 / 状态 / 清单) | `cg(op=goal)` | [`goal`](https://github.com/FuRongJun-1999/dsh-memory/blob/main/md_cg/mcp_server.py#L2309) |
54
- | 任务实体(登记 / 计划 / 状态 / 结果;done 无结果拒收) | `cg(op=task)` | [`task`](https://github.com/FuRongJun-1999/dsh-memory/blob/main/md_cg/mcp_server.py#L2328) → [`_task_call`](https://github.com/FuRongJun-1999/dsh-memory/blob/main/md_cg/mcp_server.py#L1985) |
55
- | 最近记忆(事件窗口) | `cg(op=recent)` | [`recent`](https://github.com/FuRongJun-1999/dsh-memory/blob/main/md_cg/mcp_server.py#L2331) |
56
- | 外部裁决回填(节点证据验证) | `cg(op=verify)` | [`verify`](https://github.com/FuRongJun-1999/dsh-memory/blob/main/md_cg/mcp_server.py#L2343) |
57
- | 审核队列(DEFER / 提案裁决) | `cg(op=review)` | [`review`](https://github.com/FuRongJun-1999/dsh-memory/blob/main/md_cg/mcp_server.py#L2348) |
58
- | 主动遗忘 / 恢复 | `cg(op=forget)` | [`forget`](https://github.com/FuRongJun-1999/dsh-memory/blob/main/md_cg/mcp_server.py#L2369) |
59
- | 保护(不可遗忘) | `cg(op=protect)` | [`protect`](https://github.com/FuRongJun-1999/dsh-memory/blob/main/md_cg/mcp_server.py#L2375) → [`_protect_call`](https://github.com/FuRongJun-1999/dsh-memory/blob/main/md_cg/mcp_server.py#L1194) |
60
- | 身份维度 | `cg(op=identity)` | [`identity`](https://github.com/FuRongJun-1999/dsh-memory/blob/main/md_cg/mcp_server.py#L2378) → [`_identity_call`](https://github.com/FuRongJun-1999/dsh-memory/blob/main/md_cg/mcp_server.py#L1222) |
61
- | 一致性检测 | `cg(op=consistency)` | [`consistency`](https://github.com/FuRongJun-1999/dsh-memory/blob/main/md_cg/mcp_server.py#L2381) → [`_consistency_call`](https://github.com/FuRongJun-1999/dsh-memory/blob/main/md_cg/mcp_server.py#L1273) |
62
- | 元认知(盲区聚合) | `cg(op=metacognition)` | [`metacognition`](https://github.com/FuRongJun-1999/dsh-memory/blob/main/md_cg/mcp_server.py#L2384) → [`_metacognition_call`](https://github.com/FuRongJun-1999/dsh-memory/blob/main/md_cg/mcp_server.py#L1302) |
63
- | 自我状态 | `cg(op=self_state)` | [`self_state`](https://github.com/FuRongJun-1999/dsh-memory/blob/main/md_cg/mcp_server.py#L2387) → [`_self_state_call`](https://github.com/FuRongJun-1999/dsh-memory/blob/main/md_cg/mcp_server.py#L1337) |
64
- | 演化(记忆结构演化) | `cg(op=evolution)` | [`evolution`](https://github.com/FuRongJun-1999/dsh-memory/blob/main/md_cg/mcp_server.py#L2390) → [`_evolution_call`](https://github.com/FuRongJun-1999/dsh-memory/blob/main/md_cg/mcp_server.py#L1472) |
65
- | 飞轮 / 自愈 | `cg(op=sustain)` | [`sustain`](https://github.com/FuRongJun-1999/dsh-memory/blob/main/md_cg/mcp_server.py#L2393) → [`_sustain_call`](https://github.com/FuRongJun-1999/dsh-memory/blob/main/md_cg/mcp_server.py#L1564) |
66
- | 洗脑 / 去污染 | `cg(op=scrub)` | [`scrub`](https://github.com/FuRongJun-1999/dsh-memory/blob/main/md_cg/mcp_server.py#L2396) → [`_scrub_call`](https://github.com/FuRongJun-1999/dsh-memory/blob/main/md_cg/mcp_server.py#L1673) |
67
- | 预测 / 因果门 | `cg(op=predict)` | [`predict`](https://github.com/FuRongJun-1999/dsh-memory/blob/main/md_cg/mcp_server.py#L2399) → [`_predict_call`](https://github.com/FuRongJun-1999/dsh-memory/blob/main/md_cg/mcp_server.py#L1399) |
68
- | 因果链 | `cg(op=causal)` | [`causal`](https://github.com/FuRongJun-1999/dsh-memory/blob/main/md_cg/mcp_server.py#L2402) → [`_causal_call`](https://github.com/FuRongJun-1999/dsh-memory/blob/main/md_cg/mcp_server.py#L1433) |
69
- | 白箱能力库(AEIS 能力显式调用) | `cg(op=whitebox)` | [`whitebox`](https://github.com/FuRongJun-1999/dsh-memory/blob/main/md_cg/mcp_server.py#L2405) → [`_whitebox_call`](https://github.com/FuRongJun-1999/dsh-memory/blob/main/md_cg/mcp_server.py#L3078) |
70
- | 代码索引 | `cg(op=index_code)` | [`index_code`](https://github.com/FuRongJun-1999/dsh-memory/blob/main/md_cg/mcp_server.py#L2408) → [`refindex`](../../md_cg/refindex.py) → [`security`](../../md_cg/security.py) |
71
- | 文档索引 | `cg(op=index_doc)` | [`index_doc`](https://github.com/FuRongJun-1999/dsh-memory/blob/main/md_cg/mcp_server.py#L2452) → [`refindex`](../../md_cg/refindex.py) → [`security`](../../md_cg/security.py) |
72
- | 引用 / 反向引用 | `cg(op=ref)` | [`ref`](https://github.com/FuRongJun-1999/dsh-memory/blob/main/md_cg/mcp_server.py#L2495) → [`_ref_call`](https://github.com/FuRongJun-1999/dsh-memory/blob/main/md_cg/mcp_server.py#L2978) |
73
- | 会话管理(多会话归属与过滤) | `cg(op=session)` | [`session`](https://github.com/FuRongJun-1999/dsh-memory/blob/main/md_cg/mcp_server.py#L2498) → [`_session_call`](https://github.com/FuRongJun-1999/dsh-memory/blob/main/md_cg/mcp_server.py#L2699) |
74
- | 导入落图 | `cg(op=ingest)` | [`ingest`](https://github.com/FuRongJun-1999/dsh-memory/blob/main/md_cg/mcp_server.py#L2501) → [`_ingest_call`](https://github.com/FuRongJun-1999/dsh-memory/blob/main/md_cg/mcp_server.py#L2778) |
75
- | 导出 | `cg(op=export)` | [`export`](https://github.com/FuRongJun-1999/dsh-memory/blob/main/md_cg/mcp_server.py#L2504) → [`_export_call`](https://github.com/FuRongJun-1999/dsh-memory/blob/main/md_cg/mcp_server.py#L2803) |
76
- | 维护 | `cg(op=maintain)` | [`maintain`](https://github.com/FuRongJun-1999/dsh-memory/blob/main/md_cg/mcp_server.py#L2507) → [`_maintain_call`](https://github.com/FuRongJun-1999/dsh-memory/blob/main/md_cg/mcp_server.py#L2825) |
77
- | 记忆固化 / 整理 | `cg(op=consolidate)` | [`consolidate`](https://github.com/FuRongJun-1999/dsh-memory/blob/main/md_cg/mcp_server.py#L2510) → [`_consolidate_call`](https://github.com/FuRongJun-1999/dsh-memory/blob/main/md_cg/mcp_server.py#L2903) |
78
- | 洞察 / 自主探索(信息差驱动) | `cg(op=insight)` | [`insight`](https://github.com/FuRongJun-1999/dsh-memory/blob/main/md_cg/mcp_server.py#L2513) → [`_insight_call`](https://github.com/FuRongJun-1999/dsh-memory/blob/main/md_cg/mcp_server.py#L2928) |
79
- | CCG 六要素编译(对话→候选→编外复核→落库) | `cg(op=ccg)` | [`ccg`](https://github.com/FuRongJun-1999/dsh-memory/blob/main/md_cg/mcp_server.py#L2516) → [`_ccg_call`](https://github.com/FuRongJun-1999/dsh-memory/blob/main/md_cg/mcp_server.py#L2523) |
44
+ | 按需披露(投影后完整工具 / 参数文档即时取回) | `cg(op=help)` | [`help`](https://github.com/FuRongJun-1999/dsh-memory/blob/main/md_cg/mcp_server.py#L2078) → [`_help_call`](https://github.com/FuRongJun-1999/dsh-memory/blob/main/md_cg/mcp_server.py#L1996) |
45
+ | 验证态 / 双时间轴 / 履历(含冷路径队列;只读) | `cg(op=status)` | [`status`](https://github.com/FuRongJun-1999/dsh-memory/blob/main/md_cg/mcp_server.py#L2084) → [`_status_call`](https://github.com/FuRongJun-1999/dsh-memory/blob/main/md_cg/mcp_server.py#L1911) |
46
+ | 三元组反查(派生边任意端 / 谓词 / 时间反查;只读) | `cg(op=edges)` | [`edges`](https://github.com/FuRongJun-1999/dsh-memory/blob/main/md_cg/mcp_server.py#L2087) → [`_edges_call`](https://github.com/FuRongJun-1999/dsh-memory/blob/main/md_cg/mcp_server.py#L1967) |
47
+ | 理论检索(领域理论 / 方法论文) | `cg(op=theory)` | [`theory`](https://github.com/FuRongJun-1999/dsh-memory/blob/main/md_cg/mcp_server.py#L2090) → [`theory`](../../md_cg/theory.py) |
48
+ | 记忆互链(节点间链接管理) | `cg(op=link)` | [`link`](https://github.com/FuRongJun-1999/dsh-memory/blob/main/md_cg/mcp_server.py#L2107) → [`evidence`](../../md_cg/evidence.py) → [`links`](../../md_cg/links.py) → [`provenance`](../../md_cg/provenance.py) → [`security`](../../md_cg/security.py) → [`signer`](../../md_cg/signer.py) |
49
+ | 服务信息 / 健康 | `cg(op=info)` | [`info`](https://github.com/FuRongJun-1999/dsh-memory/blob/main/md_cg/mcp_server.py#L2223) → [`audit`](../../md_cg/audit.py) → [`generation`](../../md_cg/generation.py) → [`links`](../../md_cg/links.py) → [`nodefile`](../../md_cg/nodefile.py) → [`theory`](../../md_cg/theory.py) |
50
+ | 路由:意图→知识+建议能力 | `cg(op=route)` | [`route`](https://github.com/FuRongJun-1999/dsh-memory/blob/main/md_cg/mcp_server.py#L2264) |
51
+ | 读取(按 id / 召回 / 预算) | `cg(op=read)` | [`read`](https://github.com/FuRongJun-1999/dsh-memory/blob/main/md_cg/mcp_server.py#L2285) → [`refindex`](../../md_cg/refindex.py) |
52
+ | 写入(含冲突检测 / 闸门 / 审核) | `cg(op=write)` | [`write`](https://github.com/FuRongJun-1999/dsh-memory/blob/main/md_cg/mcp_server.py#L2340) → [`writepipe`](../../md_cg/writepipe.py) |
53
+ | 目标(写入 / 状态 / 清单) | `cg(op=goal)` | [`goal`](https://github.com/FuRongJun-1999/dsh-memory/blob/main/md_cg/mcp_server.py#L2348) |
54
+ | 任务实体(登记 / 计划 / 状态 / 结果;done 无结果拒收) | `cg(op=task)` | [`task`](https://github.com/FuRongJun-1999/dsh-memory/blob/main/md_cg/mcp_server.py#L2367) → [`_task_call`](https://github.com/FuRongJun-1999/dsh-memory/blob/main/md_cg/mcp_server.py#L2009) |
55
+ | 最近记忆(事件窗口) | `cg(op=recent)` | [`recent`](https://github.com/FuRongJun-1999/dsh-memory/blob/main/md_cg/mcp_server.py#L2370) |
56
+ | 外部裁决回填(节点证据验证) | `cg(op=verify)` | [`verify`](https://github.com/FuRongJun-1999/dsh-memory/blob/main/md_cg/mcp_server.py#L2382) |
57
+ | 审核队列(DEFER / 提案裁决) | `cg(op=review)` | [`review`](https://github.com/FuRongJun-1999/dsh-memory/blob/main/md_cg/mcp_server.py#L2387) |
58
+ | 主动遗忘 / 恢复 | `cg(op=forget)` | [`forget`](https://github.com/FuRongJun-1999/dsh-memory/blob/main/md_cg/mcp_server.py#L2408) |
59
+ | 保护(不可遗忘) | `cg(op=protect)` | [`protect`](https://github.com/FuRongJun-1999/dsh-memory/blob/main/md_cg/mcp_server.py#L2414) → [`_protect_call`](https://github.com/FuRongJun-1999/dsh-memory/blob/main/md_cg/mcp_server.py#L1206) |
60
+ | 身份维度 | `cg(op=identity)` | [`identity`](https://github.com/FuRongJun-1999/dsh-memory/blob/main/md_cg/mcp_server.py#L2417) → [`_identity_call`](https://github.com/FuRongJun-1999/dsh-memory/blob/main/md_cg/mcp_server.py#L1234) |
61
+ | 一致性检测 | `cg(op=consistency)` | [`consistency`](https://github.com/FuRongJun-1999/dsh-memory/blob/main/md_cg/mcp_server.py#L2420) → [`_consistency_call`](https://github.com/FuRongJun-1999/dsh-memory/blob/main/md_cg/mcp_server.py#L1285) |
62
+ | 元认知(盲区聚合) | `cg(op=metacognition)` | [`metacognition`](https://github.com/FuRongJun-1999/dsh-memory/blob/main/md_cg/mcp_server.py#L2423) → [`_metacognition_call`](https://github.com/FuRongJun-1999/dsh-memory/blob/main/md_cg/mcp_server.py#L1314) |
63
+ | 自我状态 | `cg(op=self_state)` | [`self_state`](https://github.com/FuRongJun-1999/dsh-memory/blob/main/md_cg/mcp_server.py#L2426) → [`_self_state_call`](https://github.com/FuRongJun-1999/dsh-memory/blob/main/md_cg/mcp_server.py#L1349) |
64
+ | 演化(记忆结构演化) | `cg(op=evolution)` | [`evolution`](https://github.com/FuRongJun-1999/dsh-memory/blob/main/md_cg/mcp_server.py#L2429) → [`_evolution_call`](https://github.com/FuRongJun-1999/dsh-memory/blob/main/md_cg/mcp_server.py#L1484) |
65
+ | 飞轮 / 自愈 | `cg(op=sustain)` | [`sustain`](https://github.com/FuRongJun-1999/dsh-memory/blob/main/md_cg/mcp_server.py#L2432) → [`_sustain_call`](https://github.com/FuRongJun-1999/dsh-memory/blob/main/md_cg/mcp_server.py#L1576) |
66
+ | 洗脑 / 去污染 | `cg(op=scrub)` | [`scrub`](https://github.com/FuRongJun-1999/dsh-memory/blob/main/md_cg/mcp_server.py#L2435) → [`_scrub_call`](https://github.com/FuRongJun-1999/dsh-memory/blob/main/md_cg/mcp_server.py#L1697) |
67
+ | 预测 / 因果门 | `cg(op=predict)` | [`predict`](https://github.com/FuRongJun-1999/dsh-memory/blob/main/md_cg/mcp_server.py#L2438) → [`_predict_call`](https://github.com/FuRongJun-1999/dsh-memory/blob/main/md_cg/mcp_server.py#L1411) |
68
+ | 因果链 | `cg(op=causal)` | [`causal`](https://github.com/FuRongJun-1999/dsh-memory/blob/main/md_cg/mcp_server.py#L2441) → [`_causal_call`](https://github.com/FuRongJun-1999/dsh-memory/blob/main/md_cg/mcp_server.py#L1445) |
69
+ | 白箱能力库(AEIS 能力显式调用) | `cg(op=whitebox)` | [`whitebox`](https://github.com/FuRongJun-1999/dsh-memory/blob/main/md_cg/mcp_server.py#L2444) → [`_whitebox_call`](https://github.com/FuRongJun-1999/dsh-memory/blob/main/md_cg/mcp_server.py#L3117) |
70
+ | 代码索引 | `cg(op=index_code)` | [`index_code`](https://github.com/FuRongJun-1999/dsh-memory/blob/main/md_cg/mcp_server.py#L2447) → [`refindex`](../../md_cg/refindex.py) → [`security`](../../md_cg/security.py) |
71
+ | 文档索引 | `cg(op=index_doc)` | [`index_doc`](https://github.com/FuRongJun-1999/dsh-memory/blob/main/md_cg/mcp_server.py#L2491) → [`refindex`](../../md_cg/refindex.py) → [`security`](../../md_cg/security.py) |
72
+ | 引用 / 反向引用 | `cg(op=ref)` | [`ref`](https://github.com/FuRongJun-1999/dsh-memory/blob/main/md_cg/mcp_server.py#L2534) → [`_ref_call`](https://github.com/FuRongJun-1999/dsh-memory/blob/main/md_cg/mcp_server.py#L3017) |
73
+ | 会话管理(多会话归属与过滤) | `cg(op=session)` | [`session`](https://github.com/FuRongJun-1999/dsh-memory/blob/main/md_cg/mcp_server.py#L2537) → [`_session_call`](https://github.com/FuRongJun-1999/dsh-memory/blob/main/md_cg/mcp_server.py#L2738) |
74
+ | 导入落图 | `cg(op=ingest)` | [`ingest`](https://github.com/FuRongJun-1999/dsh-memory/blob/main/md_cg/mcp_server.py#L2540) → [`_ingest_call`](https://github.com/FuRongJun-1999/dsh-memory/blob/main/md_cg/mcp_server.py#L2817) |
75
+ | 导出 | `cg(op=export)` | [`export`](https://github.com/FuRongJun-1999/dsh-memory/blob/main/md_cg/mcp_server.py#L2543) → [`_export_call`](https://github.com/FuRongJun-1999/dsh-memory/blob/main/md_cg/mcp_server.py#L2842) |
76
+ | 维护 | `cg(op=maintain)` | [`maintain`](https://github.com/FuRongJun-1999/dsh-memory/blob/main/md_cg/mcp_server.py#L2546) → [`_maintain_call`](https://github.com/FuRongJun-1999/dsh-memory/blob/main/md_cg/mcp_server.py#L2864) |
77
+ | 记忆固化 / 整理 | `cg(op=consolidate)` | [`consolidate`](https://github.com/FuRongJun-1999/dsh-memory/blob/main/md_cg/mcp_server.py#L2549) → [`_consolidate_call`](https://github.com/FuRongJun-1999/dsh-memory/blob/main/md_cg/mcp_server.py#L2942) |
78
+ | 洞察 / 自主探索(信息差驱动) | `cg(op=insight)` | [`insight`](https://github.com/FuRongJun-1999/dsh-memory/blob/main/md_cg/mcp_server.py#L2552) → [`_insight_call`](https://github.com/FuRongJun-1999/dsh-memory/blob/main/md_cg/mcp_server.py#L2967) |
79
+ | CCG 六要素编译(对话→候选→编外复核→落库) | `cg(op=ccg)` | [`ccg`](https://github.com/FuRongJun-1999/dsh-memory/blob/main/md_cg/mcp_server.py#L2555) → [`_ccg_call`](https://github.com/FuRongJun-1999/dsh-memory/blob/main/md_cg/mcp_server.py#L2562) |
80
80
 
81
81
  <!-- FUNCMAP:END -->
82
82
 
@@ -95,10 +95,10 @@ MCP stdio:md_cg/mcp_server.py
95
95
 
96
96
  | 功能 | 显式调用 | 代码位置(点击直达源码行) |
97
97
  |---|---|---|
98
- | 两节点关系 | `stg(op=relation)` | [`relation`](https://github.com/FuRongJun-1999/dsh-memory/blob/main/md_cg/mcp_server.py#L3101) |
99
- | 时间线 | `stg(op=timeline)` | [`timeline`](https://github.com/FuRongJun-1999/dsh-memory/blob/main/md_cg/mcp_server.py#L3103) |
100
- | 锚点检索(时空窗口) | `stg(op=anchors)` | [`anchors`](https://github.com/FuRongJun-1999/dsh-memory/blob/main/md_cg/mcp_server.py#L3110) |
101
- | 时空一致性 | `stg(op=consistency)` | [`consistency`](https://github.com/FuRongJun-1999/dsh-memory/blob/main/md_cg/mcp_server.py#L3114) |
98
+ | 两节点关系 | `stg(op=relation)` | [`relation`](https://github.com/FuRongJun-1999/dsh-memory/blob/main/md_cg/mcp_server.py#L3140) |
99
+ | 时间线 | `stg(op=timeline)` | [`timeline`](https://github.com/FuRongJun-1999/dsh-memory/blob/main/md_cg/mcp_server.py#L3142) |
100
+ | 锚点检索(时空窗口) | `stg(op=anchors)` | [`anchors`](https://github.com/FuRongJun-1999/dsh-memory/blob/main/md_cg/mcp_server.py#L3149) |
101
+ | 时空一致性 | `stg(op=consistency)` | [`consistency`](https://github.com/FuRongJun-1999/dsh-memory/blob/main/md_cg/mcp_server.py#L3153) |
102
102
 
103
103
  <!-- FUNCMAP:END -->
104
104
 
@@ -8,13 +8,17 @@
8
8
  > `check_unreachable.py`(死代码扫描)与两条 **Rust 腿**(`gate_rust_crate_test.py` /
9
9
  > `gate_rust_parity.py`,批次 91 的 R-7「门禁转正」)。下表逐条与本机 `package.json`
10
10
  > 的 `scripts.gate` 实读对齐,不是复述历史文档。
11
+ >
12
+ > **2026-10-01 更新(出货面冒烟腿转正)**:门禁链再由 **8 条扩至 9 条腿**——新增
13
+ > `check_publish_smoke.py`(出货面冒烟:pack → 空沙箱真装 → 从装好的目录真启动 MCP →
14
+ > 真发 `initialize` + `tools/list`)。下表同样按 `scripts.gate` 实读对齐。
11
15
 
12
16
  ## 三层防线
13
17
 
14
18
  | 层 | 触发 | 跑什么 | 行为 |
15
19
  |---|---|---|---|
16
20
  | 本地 pre-commit | `git commit` | `python scripts/cogmap_sync.py build` | **自动重挂**行号,并把两份投影文档一并暂存 |
17
- | 发布链 | `npm publish` | `prepublishOnly`:build → test → **`npm run gate`**(八道门禁,见下) | 任一步失败即阻断发布 |
21
+ | 发布链 | `npm publish` | `prepublishOnly`:build → test → **`npm run gate`**(九道门禁,见下) | 任一步失败即阻断发布 |
18
22
  | CI | push / PR | `cogmap-check.yml`:`cogmap_sync.py check` + `link_check.py` | 远端兜底红灯 |
19
23
 
20
24
  ## 为什么本地钩子跑 build 而不是 check
@@ -37,24 +41,56 @@ git config core.hooksPath scripts/git-hooks
37
41
 
38
42
  ## 发布门禁清单(`npm run gate`)
39
43
 
40
- `prepublishOnly` 在 build + test 之后调用 `npm run gate`,八道门禁与 CI **同形但不完全同覆盖**:
44
+ `prepublishOnly` 在 build + test 之后调用 `npm run gate`,九道门禁与 CI **同形但不完全同覆盖**:
41
45
 
42
46
  | # | 命令 | 守什么 | 对应 CI |
43
47
  |---|---|---|---|
44
48
  | 1 | `python scripts/check_unreachable.py` | 控制流终止语句之后的不可达代码(拦过 s5 负记忆段与 V21-4 通道 B 两族整段静默失效) | **无**(仅本地/发布链) |
45
49
  | 2 | `python scripts/check_publish_artifact.py` | 发布件内容政策(凭据 / 私有数据 / 隐私文本 / 非追踪件) | `publish-artifact-check.yml` |
46
- | 3 | `python scripts/cogmap_sync.py check` | 认知图行号投影与真源一致 | `cogmap-check.yml` |
47
- | 4 | `python scripts/link_check.py` | 全库 md 相对链接可达 | `cogmap-check.yml` |
48
- | 5 | `python scripts/workspace_index.py --check` | 工作区索引不陈化(第 18 条) | `workspace-index-check.yml` |
49
- | 6 | `python scripts/verify_discipline.py --allow-missing` | 纪律真源 ↔ 各端产物一致 | `discipline-check.yml` |
50
- | 7 | `python scripts/gate_rust_crate_test.py` | `cargo test` @ `rust/`(Rust 侧口径漂移的回归保障) | **无**(`hive-check.yml` 只跑 `hive/Cargo.toml`,`rust/` 至今零 CI) |
51
- | 8 | `python scripts/gate_rust_parity.py` | `scripts/rank_parity.py` 逐位对拍(Python `search_rrf` vs Rust `mdcg-eval --serve`) | **无** |
52
-
53
- > **依赖提示**:第 6 道经 `render_discipline` 解析 `docs/discipline/harnesses.yaml`,需要
50
+ | 3 | `python scripts/check_publish_smoke.py` | **出货面冒烟**:真 pack → 空沙箱真装 → 从装好的目录真启动 MCP → 真发 `initialize` + `tools/list`,断言工具面 == 缺省面 `['cg','stg']` | **无**(仅本地/发布链) |
51
+ | 4 | `python scripts/cogmap_sync.py check` | 认知图行号投影与真源一致 | `cogmap-check.yml` |
52
+ | 5 | `python scripts/link_check.py` | 全库 md 相对链接可达 | `cogmap-check.yml` |
53
+ | 6 | `python scripts/workspace_index.py --check` | 工作区索引不陈化(第 18 条) | `workspace-index-check.yml` |
54
+ | 7 | `python scripts/verify_discipline.py --allow-missing` | 纪律真源 ↔ 各端产物一致 | `discipline-check.yml` |
55
+ | 8 | `python scripts/gate_rust_crate_test.py` | `cargo test` @ `rust/`(Rust 侧口径漂移的回归保障) | **无**(`hive-check.yml` 只跑 `hive/Cargo.toml`,`rust/` 至今零 CI) |
56
+ | 9 | `python scripts/gate_rust_parity.py` | `scripts/rank_parity.py` 逐位对拍(Python `search_rrf` vs Rust `mdcg-eval --serve`) | **无** |
57
+
58
+ > **第 3 道的位序不是随意的**:它紧跟第 2 道(同为「发布件面」),且**必须在第 4 道
59
+ > `cogmap_sync.py check` 之前**——前者的 `npm pack` 会触发 `prepare`(= 本仓的 `tsc` 构建,
60
+ > 会重写 `lib/`),越靠近链首越能让「包面自检」与「包已定形」两件事挨着发生;塞在链尾则
61
+ > 成了跑完一圈 Rust 之后才验包,失败反馈距离最远。位序由
62
+ > `scripts/test_publish_smoke_guard.py` 的 C2 断言钉死(挪到链尾即红)。
63
+
64
+ ### 为什么需要第 3 道(同类缺陷已漏两次)
65
+
66
+ 第 1–9 道里的**任何一道都拦不住「仓库里在、包里不在」**:第 2 道 `check_publish_artifact`
67
+ 扫的是**包内件的内容政策**(凭据 / 私有数据 / 隐私 / 非追踪)——一个必要件**整体缺席**时
68
+ 它没有任何可扫的对象,照样 VERDICT=PASS。实测两次同族事故:
69
+
70
+ - **#38**:`scripts/` 与 `hive/` 整目录未被 `files` 收录(源码树工具在包里不存在);
71
+ - **issue #48**(0.6.1):仓根 `utf8_boot.py` 未被 `files` 收录 ⇒ 装机后
72
+ `python -m md_cg.mcp_server` 在 `from utf8_boot import ensure_utf8` 处 ModuleNotFoundError,
73
+ **装机即挂**(修法= `files` 加 `utf8_boot.py`,提交 `52677077`;修完之后**仍无任何机器检查
74
+ 能拦住同类**,本道即该缺口的机器化收口)。
75
+
76
+ 第 3 道的判据面(`S0`–`S6`,名字即机器读面,详见 `scripts/check_publish_smoke.py`):S1 出货清单**点名**
77
+ 含仓根 `utf8_boot.py`(缺则打印「修法:files 加 utf8_boot.py」)、S2/S3 装好的目录里点名
78
+ `utf8_boot.py` 与 `md_cg/mcp_server.py`、S4 真握手拿到 `serverInfo`、S5 `tools` **等于**
79
+ 缺省面 `['cg','stg']`、S6 策略来源来自**包内** `data/policy.json`(只记录不判负)。
80
+ 沙箱缺省 `tempfile.mkdtemp()`(跑完清理);env `MDCG_GATE_SANDBOX_DIR` 给定时改用该目录并
81
+ **保留不删**(便于人工复核)。npm 解析复用 `check_publish_artifact.resolve_npm()` 单点
82
+ (Windows 命中 `npm.cmd`,不经 `cmd /c`);探不到 npm 即 fail-closed 退出码 1,**不静默 SKIP**。
83
+
84
+ > **诚实边界(第 3 道不覆盖什么)**:不覆盖 DSH 桥侧(`dsh/` 插件与 MCP 客户端的接线)、
85
+ > 不覆盖真实 DSH 安装路径(装的是空沙箱里的 `node_modules`)、不覆盖 peer 依赖解析
86
+ > (安装加 `--legacy-peer-deps` 跳过 peer)、不覆盖 `MDCG_MCP_SURFACE=full` 的多工具面
87
+ > (只测缺省面)、不覆盖 TypeScript 侧 `lib/` 的运行时行为。
88
+
89
+ > **依赖提示**:第 7 道经 `render_discipline` 解析 `docs/discipline/harnesses.yaml`,需要
54
90
  > **PyYAML**(CI 里显式 `python -m pip install pyyaml`)。本机缺 PyYAML 时 gate 会硬失败——
55
91
  > 那是门禁正常工作,装依赖即可,不是误报。
56
92
 
57
- > **诚实边界(勿读成「CI 全兜底」)**:第 1、7、8 道**没有对应 CI workflow**——远端不跑、
93
+ > **诚实边界(勿读成「CI 全兜底」)**:第 1、3、8、9 道**没有对应 CI workflow**——远端不跑、
58
94
  > 只有本地与 `npm publish` 会拦。Rust 侧的回归保障目前只存在于发布链这一处;
59
95
  > 若要远端兜底,须新增 workflow(`rust/**` 触发 + 装 cargo 工具链)。
60
96