@furongjun1999/dsh-memory 0.6.1 → 0.7.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (105) hide show
  1. package/README.md +49 -18
  2. package/docs/README.md +1 -0
  3. package/docs/eval/cons200_/345/206/262/347/252/201/346/243/200/346/265/213/351/200/211/351/235/242_/345/256/236/346/226/275/350/256/260/345/275/225_v1.0.md +223 -0
  4. package/docs/eval/cons200_/345/206/262/347/252/201/346/243/200/346/265/213/351/200/211/351/235/242_/345/256/236/346/226/275/350/256/260/345/275/225_v1.1.md +340 -0
  5. package/docs/eval/issue50_/345/205/203/346/225/260/346/215/256/351/200/217/344/274/240/344/270/216/345/205/234/345/272/225_/344/277/256/345/244/215/350/256/260/345/275/225_v1.0.md +437 -0
  6. package/docs/eval/issue50_/345/215/212/351/207/215/345/244/215/345/276/205/345/256/232/345/244/215/346/240/270_/344/277/256/345/244/215/350/256/260/345/275/225_v1.0.md +488 -0
  7. package/docs/eval/issue50_/345/276/205/345/256/232/345/244/215/346/240/270/345/205/245/351/230/237_/344/277/256/345/244/215/350/256/260/345/275/225_v1.0.md +428 -0
  8. package/docs/eval/issue50_/350/257/273/351/235/242/344/277/235/346/212/244/345/217/252/350/256/244/346/230/276/345/274/217/346/235/245/346/272/220_/344/277/256/345/244/215/350/256/260/345/275/225_v1.0.md +271 -0
  9. package/docs/eval/issue50_/351/207/215/350/246/201/345/272/246/345/220/214/346/272/220/344/270/216/344/277/235/346/212/244/350/257/255/344/271/211_/344/277/256/345/244/215/350/256/260/345/275/225_v1.0.md +306 -0
  10. package/docs/eval/issue51_/344/270/200/351/224/256/345/256/211/350/243/205/345/244/261/350/264/245_/345/275/222/345/261/236/345/210/244/345/256/232_v1.0.md +58 -0
  11. package/docs/eval/issue52_/346/235/241/344/273/266/345/205/210/350/241/214/344/270/216/346/210/252/346/226/255/345/217/257/350/247/202/346/265/213_/344/277/256/345/244/215/350/256/260/345/275/225_v1.0.md +360 -0
  12. package/docs/eval//344/270/211/346/241/243/350/207/252/346/262/273_/346/255/245/351/252/244/342/221/241/346/241/243/344/275/215/345/215/225/344/270/200/345/205/245/345/217/243_/350/220/275/347/240/201/350/256/260/345/275/225_v1.0.md +651 -0
  13. package/docs/eval//344/270/211/346/241/243/350/207/252/346/262/273_/346/255/245/351/252/244/342/221/242/345/217/230/346/233/264/345/215/225/344/270/216/345/233/236/346/273/232/345/216/237/350/257/255_/350/220/275/347/240/201/350/256/260/345/275/225_v1.0.md +439 -0
  14. package/docs/eval//344/270/211/346/241/243/350/207/252/346/262/273_/346/255/245/351/252/244/342/221/243/345/207/206/345/205/245/350/257/273/346/225/260_/350/220/275/347/240/201/350/256/260/345/275/225_v1.0.md +1337 -0
  15. package/docs/eval//344/270/211/346/241/243/350/207/252/346/262/273_/346/255/245/351/252/244/342/221/244/346/224/266/345/256/230/344/270/216/345/205/250/351/223/276/351/252/214/346/224/266_/350/220/275/347/240/201/350/256/260/345/275/225_v1.0.md +1817 -0
  16. 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
  17. 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
  18. package/docs/eval//345/217/221/345/270/20309_/346/243/200/347/264/242/351/235/242/344/270/211/346/211/271/346/224/266/345/217/243_v1.0.md +66 -0
  19. 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
  20. package/docs/eval//347/254/2543/345/261/202stg/347/273/223/346/236/204/347/264/242/345/274/225_/345/256/236/346/226/275/350/256/260/345/275/225_v1.0.md +250 -0
  21. 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
  22. 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
  23. package/docs/mdcg/README/350/257/246/347/273/206/347/211/210_v0.4.10.md +88 -0
  24. 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
  25. package/docs/mdcg//345/217/221/345/270/203/351/227/250/347/246/201/351/223/276_v0.1.md +47 -11
  26. 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
  27. package/docs/plans/stg/346/235/241/344/273/266/345/214/226/344/270/216/347/273/223/346/236/204/347/264/242/345/274/225_/350/256/276/350/256/241_v0.1.md +124 -0
  28. 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
  29. package/docs/plans//350/256/260/345/277/206/350/207/252/345/244/204/347/220/206/344/270/211/346/241/243/350/207/252/346/262/273_/350/256/276/350/256/241_v0.2.md +207 -0
  30. package/md_cg/admission.py +718 -0
  31. package/md_cg/autonomy_modes.py +642 -0
  32. package/md_cg/bench_e2e_locomo_qa.py +11 -4
  33. package/md_cg/chain.py +47 -0
  34. package/md_cg/consistency.py +133 -8
  35. package/md_cg/forgetting.py +38 -6
  36. package/md_cg/freshness.py +527 -0
  37. package/md_cg/generation.py +409 -0
  38. package/md_cg/hotcache.py +4 -1
  39. package/md_cg/lifecycle.py +30 -2
  40. package/md_cg/mcp_server.py +191 -26
  41. package/md_cg/mdcg.py +594 -39
  42. package/md_cg/mdcos.py +869 -38
  43. package/md_cg/nodefile.py +74 -1
  44. package/md_cg/protect.py +79 -4
  45. package/md_cg/provenance.py +1 -1
  46. package/md_cg/review_cli.py +31 -2
  47. package/md_cg/rollback.py +411 -0
  48. package/md_cg/rollback_cli.py +104 -0
  49. package/md_cg/semantic/canonical.py +22 -0
  50. package/md_cg/semantic/unify.py +73 -22
  51. package/md_cg/semantic/unify_fixture.json +25 -0
  52. package/md_cg/sleep.py +1297 -0
  53. package/md_cg/stg.py +400 -50
  54. package/md_cg/stgidx.py +281 -0
  55. package/md_cg/sustain.py +146 -9
  56. package/md_cg/test_auto_defaults.py +424 -0
  57. package/md_cg/test_autonomy_admission.py +1098 -0
  58. package/md_cg/test_autonomy_modes.py +1972 -0
  59. package/md_cg/test_b1_auto_id_multiproc.py +7 -0
  60. package/md_cg/test_b1b2_write_face.py +7 -0
  61. package/md_cg/test_b3_merge_keeps_content.py +7 -0
  62. package/md_cg/test_boundary_hit.py +410 -0
  63. package/md_cg/test_cons200_scan_selection.py +791 -0
  64. package/md_cg/test_en_pipeline.py +22 -13
  65. package/md_cg/test_generation_guard.py +352 -0
  66. package/md_cg/test_h4_sustain_snapshot.py +14 -4
  67. package/md_cg/test_i50a_half_dup_defer.py +408 -0
  68. package/md_cg/test_i50b_defer_to_review_queue.py +545 -0
  69. package/md_cg/test_i50c_meta_passthrough.py +608 -0
  70. package/md_cg/test_i50d_importance_source.py +531 -0
  71. package/md_cg/test_i50e_readside_protection.py +656 -0
  72. package/md_cg/test_issue39_utf8_stdio.py +9 -1
  73. package/md_cg/test_issue52_scan_condition_first.py +677 -0
  74. package/md_cg/test_linkref.py +7 -0
  75. package/md_cg/test_mode_parity.py +1393 -0
  76. package/md_cg/test_mutation_rollback.py +805 -0
  77. package/md_cg/test_n204_n205_n226_n227_n228_n229_exit_gates.py +1 -1
  78. package/md_cg/test_n212_n213_n224_generation_gates.py +14 -8
  79. package/md_cg/test_n214_n215_n221_n222_write_face_gates.py +7 -0
  80. package/md_cg/test_n230_dirty_replay.py +375 -0
  81. package/md_cg/test_p2_mcp.py +8 -0
  82. package/md_cg/test_p2_six_elements.py +463 -0
  83. package/md_cg/test_p3_legacy_closure.py +433 -0
  84. package/md_cg/test_p4_freshness.py +680 -0
  85. package/md_cg/test_p8_subgraph_chain.py +14 -1
  86. package/md_cg/test_p9_forget_protect.py +7 -0
  87. package/md_cg/test_p9c_dedup_hints.py +7 -0
  88. package/md_cg/test_policy_required_ccg.py +5 -1
  89. package/md_cg/test_protocol.py +7 -0
  90. package/md_cg/test_rank_parity_score_mode.py +6 -0
  91. package/md_cg/test_semantic_canonical.py +5 -3
  92. package/md_cg/test_sleep.py +611 -0
  93. package/md_cg/test_sleep_p1.py +784 -0
  94. package/md_cg/test_stgidx_index_parity.py +1020 -0
  95. package/md_cg/test_time_core_lint.py +968 -0
  96. package/md_cg/test_unify_default_off.py +701 -0
  97. package/md_cg/test_unify_scope.py +182 -0
  98. package/md_cg/test_writelimit.py +36 -9
  99. package/md_cg/test_writepipe.py +5 -2
  100. package/md_cg/weights.py +15 -1
  101. package/md_cg/whitebox_kb/aeis_core/time_core.py +8 -0
  102. package/md_cg/writepipe.py +101 -2
  103. package/package.json +3 -2
  104. package/skills/plugin.json +1 -1
  105. package/utf8_boot.py +237 -0
@@ -0,0 +1,250 @@
1
+ # 第 3 层 stg 结构索引(装载期内存倒排+写路径增量维护 · 条件资格首验 · 回退可观测)——实施记录 v1.0
2
+
3
+ **日期**:2026-10-03 | **被测面**:`D:\program\dsh-memory-main` 工作树(未提交——3 个已跟踪文件被改+2 个新增文件;git status 实列 3 M+3 ??,第三个 ?? 为宿主目录 `.zcode/`,见文末 git 面)| **基线**:HEAD `0d3a0ab2`(`git rev-parse HEAD` 实跑核实)
4
+
5
+ **关联**:
6
+ - 设计稿 `docs/plans/stg条件化与结构索引_设计_v0.1.md`(本次随批修订,含 2026-10-03 使用者签收记录)——本批为其 **§三「第 3 层设计」** 的落地;
7
+ - 前序批 `docs/eval/issue52_条件先行与截断可观测_修复记录_v1.0.md`(第 1/2 层;其 §六留池「第 3 层结构索引与条件资格」由本批接续)。
8
+
9
+ **证据分级声明**(本报告只写有机械证据的事):
10
+
11
+ | 标记 | 含义 |
12
+ |---|---|
13
+ | 〔本报告实跑〕 | 本报告撰写员在本次 ask 内亲手执行并计数(守卫两模式 / python 全量 / `git grep` 零实现面 / 行号读码核实 / git 面) |
14
+ | 〔工作流采集·修复段〕 | 修复工作流采集材料(7 条修前复现腿 / 实施 changes / targetedSuite),本报告**转录**,不代跑不代补 |
15
+ | 〔工作流采集·复核段〕 | 修复工作流的独立复核段采集材料(ACCEPT 判定 / 三臂 battery / fuzz / 退化与注入探针),本报告转录 |
16
+ | 〔编排侧〕 | 随任务材料传入的编排侧输出(容器两栈),本报告转录、未复跑 |
17
+
18
+ 行号口径:改后行号=读工作树核实〔本报告实跑〕;改前行号=`git show HEAD:<path>` 核实〔本报告实跑〕。
19
+
20
+ **术语速览**(出处随条标注:标 `stgidx.py` 的条目出自**本批新增文件**;标 `stg.py`/`mdcg.py` 的含本批新增落点;行号=现树读码;本批之前不存在的概念会注明):
21
+
22
+ | 术语 | 释义 |
23
+ |---|---|
24
+ | **第 1/2/3 层** | 设计稿 §二/§三的分层:**第 1 层**=全量快照遍历+条件过滤(**正确性基线路径**——索引路径必须与它逐位一致);**第 2 层**=截断可观测(`truncated`+hint+近期优先兜底)——两者由前序批(issue52)落地;**第 3 层**=结构索引(条件维倒排直取)+条件资格首验,即**本批**(设计稿 §3.1) |
25
+ | **三表 / 三张表** | 结构索引 `StgIndex` 的三张倒排(`md_cg/stgidx.py:148`):`by_session`(`None`=无会话归属桶)/ `by_layer` / `by_time`(升序 `(t, id)`)+ `pos`(物理位序)+ `cls`(每节点分类记录)。**不变量**:恒为快照 keys 的划分,自检单点 `stgidx.verify`(`:85`) |
26
+ | **物理序(pos)** | 快照 `index["nodes"]` 的 dict 插入序=基线 `_scan` 的候选序;索引子集取数后须按 `pos` 回排以复现它(`stgidx.py:19-20` 注释) |
27
+ | **unassigned 桶** | 无会话归属节点(`session` 为 `None`)的兜底桶;具体会话视图**不得**混入它(设计稿 §六-4;守卫 G3) |
28
+ | **nonfinite** | 时间戳为 NaN/±inf 的节点单列:NaN 在基线上**会**命中时间窗(保守超集,逐条精确判定仍在 `_scan` 侧)、±inf 永不命中(`stgidx.py:22-26` 注释) |
29
+ | **观察轴 / 效力轴(time_axis)** | stg 的时间轴开关:`observed`(缺省)=观察轴,读 `temporal`(回退 `condition_space.time_window`);`effective`=效力轴,读 `effective_from` / `effective_until`。单点 `stg._interval`(`stg.py:44`,委托 `trust.time_window_of` :393 与 `trust.time_axis_of` :378);非法轴抛 ValueError。`by_time` 表按观察轴建,故非观察轴查询不索引时间维(§六-5) |
30
+ | **代际(generation)** | 表绑定的快照身份:`StgIndex.index_obj is cg.index` 判据(`md_cg/stg.py:287`);整体换过快照=代际不符 ⇒ 丢陈旧表并回退上报 |
31
+ | **回退 reason / fallback** | 索引不可服务时 `meta` 里的非空原因串(9 个字面量全清单见 §3.3);`path=full` 表示本查询实走第 1 层全量 |
32
+ | **flag** | `MDCG_STG_INDEX`(结构索引)/ `MDCG_STG_QUALIFY`(条件资格首验);取值 `"1"/"true"/"True"` 为开,缺省关(`md_cg/stg.py:275` `_flag_on`) |
33
+ | **只上报不过滤** | 资格首验的契约红线:`qualification` 只挂到返回条目上,不动成员/次序/截断面(`md_cg/stg.py:441`;硬过滤另立裁定) |
34
+ | **签收点 1–5** | 设计稿 §六「待签收点」(逐条裁决请求)与 §八「签收记录」(2026-10-03 使用者逐条签收:1 索引形态主案「同意」/ 2 路径等价为唯一准入「同意」/ 3 资格首验只上报不过滤(硬过滤另立裁定)「同意」/ 4 unassigned 语义保持现状「确认」/ 5 `consistency.check` `MAX_SCAN=200` 选面「纳入本线第二实现批」) |
35
+
36
+ ---
37
+
38
+ ## 一、缺陷定义与真实站点
39
+
40
+ ### 1.1 缺陷定义
41
+
42
+ **一句话**:设计稿 §三定义的**第 3 层缺位**——三接口(timeline / anchors / consistency)的候选面恒为**全量快照遍历**(O(N),改前树 `md_cg/stg.py:141` 逐条全库),session / layer / time_window 条件只能在遍历**之后**过滤;同时条件资格(`judge_qualification`)未进 stg 读面,索引化所需的回退/可观测面(reason / meta)在改前树**无实现点**。
43
+
44
+ - 前序批(issue52)已把「条件先行+截断可观测」收口,但候选面仍是全量——设计稿 §3.1 目标形态=「触碰节点数从 N(全库) 降到 域内 ∩ 条件匹配 ∩ 邻域」;本批实测收敛读数见 §4。
45
+ - **本批改动为「新能力实施」,不是崩溃修复**:修前 7 条复现腿中 **6 条可运行腿的 observed 全部为「无异常」读数、第 7 条无可断言对象**(`reproduced=false`;§二逐条列),其语义是**基线取证**——为「flag 开/关逐位等价」这一唯一准入判据(设计稿 §四-1、§六-2)建立逐位靶子,并取证 flag 缺席面(改前树两 flag 零实现,见 §1.2 机械甄别)。
46
+ - 一处**行为差异的风险面**已预判并被守卫/复核覆盖:索引物理序(快照插入序)与时间序、id 字典序互相错位(修前腿 1/4 的取证形态),取数面若不回排 `pos` 即无法复现基线候选序(变异④、守卫 G1)。
47
+
48
+ ### 1.2 真实站点(行号为本报告读码所见)
49
+
50
+ **改前树**(`git show HEAD:md_cg/stg.py` / `md_cg/mdcg.py`,本报告实跑核实):
51
+
52
+ | 站点 | 内容 |
53
+ |---|---|
54
+ | `md_cg/stg.py:119` | `def _scan(cg, layer=None):`——遍历单点定义(逐条过滤/条目化内联其中,无 `nodes` 参数) |
55
+ | **`md_cg/stg.py:141`** | **全量遍历主站点**:`for nid, e in list(cg.index["nodes"].items()):`——三接口候选面恒为全量(AST 判据 `scan_ast_slices=[]`、`scan_src_line=141`〔工作流采集·修复段〕) |
56
+ | `md_cg/stg.py:347 / 392 / 433` | timeline / anchors / consistency 三接口共性调用点 `for n in _scan(cg, layer=layer):`(本报告实跑核对 HEAD 版全部 `_scan(` 调用点,三处全中) |
57
+ | `md_cg/stg.py:160` | 旧快照回退分支 `fm, _content = cg._read(e)`(既有兼容路径,本批不动) |
58
+ | `md_cg/stg.py:280 / 343 / 350 / 359` | `_view_session` 定义 / timeline 会话归一 / 会话过滤 / `items.sort(key=(start,end,id))`——第 3 层必须逐位保住这些语义 |
59
+ | `md_cg/mdcg.py:1454` | 装载完成点 `self.index = self._load_index()`——其后**无**索引三表构建(现树该行 1460) |
60
+ | `md_cg/mdcg.py:2996 / 3006` | `_stage` / `_unstage` 写路径——**无**结构索引同钩(现树 3017 / 3062) |
61
+ | `md_cg/mdcg.py:1740 / 1794 / 1977` | `compact_index` / `flush` / `rebuild_index`——整体换快照路径**无**索引失效点 |
62
+ | flag 面(本报告实跑) | `git grep -E "MDCG_STG_(INDEX|QUALIFY)" HEAD -- md_cg src dsh test scripts` → **rc=1 零命中**(本报告实跑的五个代码路径面内;设计稿等 `docs/` 面不在该条 grep 路径内) |
63
+ | 索引/回退面(本报告实跑) | `git grep -E "by_session\|fallback_reason\|index_hit\|index_miss" HEAD -- …` → **rc=1 零命中**;`by_time` 8 处全为 `trust.filter_by_time` 族(mdcg.py:3566、mdcos.py:820/1283/5146、provenance.py:528、test_retr_s8_time.py:151/153、trust.py:556 定义);`by_layer` 在改前为**统计用途**(export.py 导出统计等),无倒排取数实现 |
64
+ | `md_cg/mcp_server.py:1044 / 3153` | stg 工具面 `layer` 声明为 string(`:1044`);`_stg_call` 三分支**原样透传**(`:3153` timeline 分支)——不校验,见 §5.2 分叉 |
65
+
66
+ **改后树**:落点表见 §3.2。
67
+
68
+ ---
69
+
70
+ ## 二、修前现场(本工作流采集的 7 条复现腿)
71
+
72
+ **共同事实**:6 条可运行腿**无异常抛出、无崩溃**(observed 列即逐条读数;本批语义=基线取证);第 7 条(表缺失回退面)在改前树**无可断言对象**——属第 3 层新增面,如实记 `reproduced=false`。逐条如下〔工作流采集·修复段〕。表内读数记号(`hash_biz`/`hash_full`、`*_ids`/`*_eq_*` 等)均为采集脚本自产(脚本未随材料提供);读者点名的两处记号已就地注明(腿 1 摘要记号、腿 2 布尔读数)。
73
+
74
+ | # | 腿 | payload | observed(异常/崩溃点) | 站点 | reproduced |
75
+ |---|---|---|---|---|---|
76
+ | 1 | 构造期装载(flag 关 · >5000 节点合成库 · 三接口逐位快照) | lib_big 合成库 5203 节点:4900 填充(sess_o1/sess_o2 交错,temporal=2e6+i)+200 目标节点(session=target-sess,temporal=1e6+i,id=zz_target_\* 字典序落索引尾部)+100 无会话(m_unassigned_\*)+3 倒置(z_bad_\*);close 落快照后重开装载;flag 未设 | 无异常。装载走快照路径:nodes=5203 / `_index.json` 在 / fingerprint_match=true / load 0.03s;索引尾 3=zz_target_0197..0199、zz_target_0000 位置 5003。`timeline(session=target-sess)`:count=200 scanned=5203 kept=200 truncated=false——索引第 5003 位的目标会话节点被条件先行全覆盖(第 1/2 层已收口,此为**等价性基线锚点**)。20 条查询(Q1-Q20)返回体逐位留档:run1/out/default.json(Q1 hash_biz=9f196e20…、Q3 hash_full=22027553…、Q15 hash_biz=f231733a…)。串行计时(全量遍历 5203,5 次中位):T1 timeline(target) 3.8ms / T2 timeline(\*) 无截断 6.2ms / T3 anchors(时间窗) 8.3ms / T4 consistency 全量 9.5ms(记号口径:`hash_biz`/`hash_full`=采集脚本对返回体的两种摘要(业务字段 / 含读数全量),其精确定义与复算脚本**未随材料提供**;`run1/out/default.json`=材料中的留档相对路径,根目录**未随材料提供**;「索引尾 3」=快照物理序最后 3 项、「位置 5003」=0-based 下标——其前恰有 4900+100+3=5003 个节点(nid 字典序:`m_unassigned_*`/`z_bad_*` 均小于 `zz_target_*`;本报告读码+算术核实) | `md_cg/mdcg.py:1454`(装载完成点);`md_cg/stg.py:141`(全量遍历) | true |
77
+ | 2 | 重放面(写钩 `_stage`/`_unstage` · rebuild/compact/重开装载后逐位一致) | lib_write 63 节点库(50 填充+10 目标+3 无会话);操作序列:add b_new_0001 → rebuild_index → _unstage(zt_00)+删文件 → flush+compact_index → 重开装载;flag 未设(「删文件」=删除 zt_00 节点对应文件,执行者/脚本未随材料提供) | 无异常。count 10→11(新节点时间最新居首位);rebuild 后物理序由追加序变 sorted(b_new_0001 位置 63→50,append_is_sorted=false / rebuild_is_sorted=true;两枚布尔读数为采集脚本产出,其脚本与判据未随材料提供),而查询返回体与 rebuild 前逐位相同(hash_full/hash_biz 均相等)——结果与索引物理序无耦合;`_unstage`+删文件后 count=10 且 zt_00 不在;compact 后重开装载 hash 与删除后逐位相同 | `md_cg/mdcg.py:2996`(_stage)、`:3006`(_unstage)、`:1977`(rebuild)、`:1740`(compact)、`:1794`(flush)(改前树行号,本报告已对 HEAD 核实) | true |
78
+ | 3 | 多会话交错+无会话节点(unassigned 语义现状) | 同一 5203 库;3 个具体会话(sess_o1/sess_o2/target-sess)交错+100 条无 session 节点+sess_bad;查询 timeline 各会话视图/跨会话/anchors;含空白会话值归一探测 | 无异常。`timeline(session=target-sess)` items 的 session 值集合={target-sess}、无 unassigned id 混入(target_view_unassigned_ids=[]);`session="*"` 与缺省均 count=5203(含无会话节点,cross_eq_default=true);anchors(时间窗,无会话维度)返回全部 100 条 m_unassigned_\*;会话值归一(`" target-sess "`→strip)count=200 | `md_cg/stg.py:343-350`(timeline 会话过滤与 cross 判据)、`:280`(_view_session 定义) | true |
79
+ | 4 | 时间序与 id 字典序错位(目标会话节点落索引尾部) | 目标节点 temporal 最旧(1e6+i)而 id=zz_target_\* 字典序最大;填充 temporal=2e6+i;无会话节点 temporal=3e6+i;查询 desc/asc/max_scan=10 | 无异常。timeline desc 头部=zz_target_0199..、尾部=zz_target_0150(按时间倒序而非 id 序);desc=False 升序;max_scan=10 时保留 zz_target_0199..0190(近期优先保留最新而非 id 尾部);count 恒=条件命中总数;索引物理序(rebuild 后 sorted 写盘)与查询输出无耦合 | `md_cg/stg.py:359`(items.sort 键);`md_cg/mdcg.py:1969-1974`(_scan_nodes 按 nid 排序写盘=索引物理序) | true |
80
+ | 5 | 截断语义继承(truncated/scanned/kept/近期优先/hint) | 5203 条跨会话命中(默认 max_scan=5000);consistency 在 5203 候选上三档(默认/100/None);anchors 全命中 bbox | 无异常。`timeline(session="*")`:count=5203 kept=5000 truncated=true,hint 在场且含「细化生效条件」「条件索引」字样;anchors(bbox 全覆盖)同型读数;consistency 默认 scanned=5203 kept=5000 truncated=true(3 条倒置因时间不可判定先被截→issues=0)、max_scan=100→kept=100、max_scan=None→kept=5203 truncated=false 且 issues=3(z_bad_0..2) | `md_cg/stg.py:169`(_cap_hits)、`:215`(_with_scan_reads)、`:208`(_CAP_HINT 文案)(第 1/2 层落点) | true |
81
+ | 6 | flag 缺席面(`MDCG_STG_INDEX=1` / `MDCG_STG_QUALIFY=1` 行为零变化) | 同库同 20 条查询,子进程 env 置两 flag=1 重跑(default 臂自动 spawn flags 臂,同脚本同载荷) | 无异常。两臂 58 个 hash 键(全量+业务字段)逐位一致 equal=true;两臂返回体 leak 检查全 false(无 qualification / index_hit / index_miss / fallback / index_tables 键);`git grep -E "MDCG_STG_(INDEX\|QUALIFY)" -- md_cg src dsh test scripts` → rc=1 零命中(五个代码路径面内;该命令的路径面不含 `docs/`,设计稿在 `docs/plans/` 下的命中与否不由该命令判定) | 改动前树无实现点(`stg.py`/`mdcg.py` 无 flag 读取;`mcp_server.py:3131` `_stg_call` 原样透传);设计稿 §3.5 预定落点 | true |
82
+ | 7 | 回退路径(表缺失时) | 不适用——改动前树无索引三表,无表可缺,无法注入 | **未复现**(无可断言对象;此非实验失败,系该面属第 3 层新增):「表缺失/代际不符 ⇒ 回退第 1 层+meta reason」在改动前树不存在。机械甄别:`by_session` 在 md_cg rc=1 零命中;`by_time` 8 处全部为 `trust.filter_by_time`(检索时间算子,trust.py:556);`by_layer` 为统计用途;`fallback_reason`/`index_hit`/`index_miss` 零命中。既有最近似回退=旧快照缺 temporal/spatial 键时 `_scan` 回退 `cg._read` 读文件(实测 lib_snap 库 timeline(session=target) count=2 命中)——该面仍成立但语义不同。基线对应物=腿 1 的 flag 关全量遍历路径(已取证) | `md_cg/stg.py:160`(既有回退分支);三表构建点在改前树不存在 | false |
83
+
84
+ ---
85
+
86
+ ## 三、修法契约与落点
87
+
88
+ ### 3.1 契约(设计稿 §3.2/§3.4/§3.5/§四/§五/§六+守卫钉住的红线)
89
+
90
+ | # | 契约 | 机械钉法 |
91
+ |---|---|---|
92
+ | C1 | **flag 默认关**:`MDCG_STG_INDEX` / `MDCG_STG_QUALIFY` 未设=第 1 层路径;关臂返回体与第 1/2 层**逐位一致**(不落 `index` 键) | `stg.py:269/271/275/328`;守卫 G1b、G5j;变异⑫(红 3) |
93
+ | C2 | **只改取数面、不改语义面**:逐条构造与过滤(layer/可见性/条目化)单点 `_scan_one`,全量遍历与索引子集共用;第 1/2 层条件先行与无切片红线一字未动 | `stg.py:134/168`;守卫 G7b(AST 判据:`_scan` 内无切片子表达式);变异③(红 1) |
94
+ | C3 | **逐位等价为唯一准入**:flag 开/关业务字段逐位一致(`meta` 计数除外);开臂候选面必须**真收窄**(子集≥全量时走 full 并报 `no_convergence`) | 守卫 G1(A01–A21)、G1c;变异⑧(红 14) |
95
+ | C4 | **回退即回报(禁止静默)**:表缺失/构建失败/代际不符/表-快照残余不一致/迭代期旧快照条目/无条件维/未收窄 → 回退全量并带**非空 reason** | `_index_pairs` 全路径(`stg.py:321-362`);守卫 G5a–G5i(G5a=表规模读数==快照实况;G5b–G5i=回退面);变异⑨(红 14) |
96
+ | C5 | **资格只上报不过滤**:复用 read 面唯一单点 `MdCG.judge_qualification`,不动成员/次序/截断面;密文不可解 ⇒ 不附(不伪造状态) | `stg.py:405/441`;守卫 G6a–G6e;变异⑩(红 4)、⑪(红 3) |
97
+ | C6 | **写路径同钩增量维护**:写/删只经 `_set_index_entry` / `_remove_index_entry` 单点(桶计数与结构索引同钩);整体换快照三路(重载/compact/rebuild)显式失效、下次访问惰性重建;flush 不失效 | `mdcg.py:3024/3041/3057` 与失效点 `:1683/1801/2006`、`flush:1808`;守卫 G2a–G2i;变异①(红 3)②(红 2)⑬(红 2)⑭(红 1) |
98
+ | C7 | **不引入第二套解析**:时间走 `trust.time_window_of`(与 `_interval` 同源)、会话走 `_view_session`、资格走 `judge_qualification`;索引划分不变量自检单点 `stgidx.verify` | `stgidx.py:56/85`;守卫 G7a(stg 侧 `judge_qualification` 恰一处调用,不另写第二套资格判据) |
99
+
100
+ ### 3.2 落点表(改后行号=本报告读码核实)
101
+
102
+ | 文件 | 行(现树) | 内容 |
103
+ |---|---|---|
104
+ | `md_cg/stgidx.py`(新增 281 行) | `:56` `time_of`(观察轴起点,复用 `trust.time_window_of`)/ `:73` `build`(O(N) 惰性构建)/ `:85` `verify`(划分不变量自检)/ `:148` `StgIndex` / `:169` `add` / `:182` `remove` / `:192` `_classify` / `:209` `_unclassify` / `:232` `range_ids`(二分区间,含同刻并列尾巴)/ `:244` `subset`(多维修交集,time 维先回排 pos)/ `:277` `size` | 第 3 层结构索引**单点**:三表+pos+cls;`nonfinite` 单列;`broken` 标记(增量期异常 ⇒ 读侧整表回退重建) |
105
+ | `md_cg/stg.py`(702 行) | `:134` `_scan_one`(逐条单点)/ `:168` `_scan(cg, layer, nodes=)`(候选面可换)/ `:253` `_with_scan_reads(index_meta)`(关臂不落 index 键)/ `:269` `_INDEX_ENV`、`:271` `_QUALIFY_ENV`、`:275` `_flag_on`、`:280` `_index_bundle`、`:307` `_index_meta_hit`、`:314` `_index_meta_full`、`:321` `_index_pairs` / `:405` `_qual_node_dict`、`:441` `_attach_qualification` / `:527` timeline(by_session,接线 `:552/:557`)、`:584` anchors(by_time 区间+blocked,接线 `:621/:627`)、`:657` consistency(by_layer,接线 `:675/:676`) | 读侧编排:直取、回退、可观测、资格只上报 |
106
+ | `md_cg/mdcg.py`(4764 行) | `:1459` `self._stg_index=None`(惰性槽,装载完成后首次 stg 需要时构建)/ `:3017` `_stage`、`:3062` `_unstage`(委托)/ `:3024` `_set_index_entry`、`:3041` `_remove_index_entry`(桶计数+结构索引同钩单点)/ `:3057` `_invalidate_stg_index` 及三处失效点 `:1683`(`_maybe_reload_index`)、`:1801`(`compact_index`)、`:2006`(`rebuild_index`)/ `:1808` `flush`(**不**失效,注释 `:1809-1811` 声明) | 写侧同钩+失效编排 |
107
+ | `md_cg/test_stgidx_index_parity.py`(新增 1020 行) | `_SRC_MUTATIONS` `:691-798`(17 处定点变异表)/ `_MUTATION_IDS` `:802` / `_table_gaps` `:822` / `_table_integrity_check` `:862` / `_selfcheck_judge` `:877` / `_anchor_check` `:941` / `_branch_baseline` `:958` / `main` `:1007` | 守卫:G1–G7 共 **51** 条断言+17 处定点变异+防误删自检+ANCHOR-MISS fail-closed(退出码 2) |
108
+
109
+ ### 3.3 回退 reason 全清单(读码核实)
110
+
111
+ `_index_bundle`(`:280`):`tables_missing`、`build_failed`(`:299`)、`generation_mismatch`(`:291`)、`table_snapshot_mismatch`(`:294`,键数型);`_index_pairs`(`:321`):`table_snapshot_mismatch`(`:354`,残余型)、`entry_file_read`(`:360`)、`no_condition_dimension`(`:340`)、`no_convergence`(`:346`);anchors 侧 `blocked`:`time_axis_not_indexed`(`:616`)、`inverted_query_window`(`:620`)。
112
+
113
+ (「材料口径八类」的来源=工作流采集·修复段的实施说明原文:`_index_pairs:321(八类回退 reason:tables_missing/generation_mismatch/table_snapshot_mismatch/entry_file_read/time_axis_not_indexed/inverted_query_window/no_condition_dimension/no_convergence)`——即上列**除 `build_failed` 外**的 8 个;本报告读码在 `_index_bundle`(`stg.py:299`)另见 `build_failed`,故合计 **9 个字面量**。每条回退路径都同时落 `path=full`+`index_miss`+非空 `fallback`。)
114
+
115
+ ---
116
+
117
+ ## 四、验证数字
118
+
119
+ ### 4.1 本报告实跑
120
+
121
+ | 项 | 命令(本报告原样) | 结果 |
122
+ |---|---|---|
123
+ | 守卫默认模式 | `python -X utf8 -m md_cg.test_stgidx_index_parity` | 退出码 **0**;**51 通过 / 0 失败**(逐条计数:G1 23=A01–A21 两臂等价 21 条+G1b/G1c 形态钉住 2 条、G2 9、G3 1、G4 1、G5 10、G6 5、G7 2) |
124
+ | 守卫变异自证 | `python -X utf8 -m md_cg.test_stgidx_index_parity --branch-baseline` | 退出码 **0**;未变异基线 51 全绿;17 处变异**各自恰好命中**:①3 ②2 ③1 ④3 ⑤9 ⑥1 ⑦8 ⑧14 ⑨14 ⑩4 ⑪3 ⑫3 ⑬2 ⑭1 ⑮1 ⑯5 ⑰12;空转断言 0;判别力自证 PASS |
125
+ | python 全量 | `python -X utf8 scripts/run_tests.py` | 退出码 **0**;`===== SUMMARY 310/310 通过,5 跳过(依赖缺失/平台不符) =====`;清单内含 `PASS md_cg.test_stgidx_index_parity` |
126
+ | 改前树零实现面 | `git grep -E "MDCG_STG_(INDEX\|QUALIFY)" HEAD -- md_cg src dsh test scripts` 等 | rc=1 零命中(flag 面、by_session/fallback_reason/index_hit/index_miss 面);`by_time` 8 处全为 `trust.filter_by_time` 族 |
127
+ | git 面 | `git status --porcelain` / `git rev-parse HEAD` | 3 M+3 ??(含宿主 `.zcode/`);HEAD=`0d3a0ab2d35d3100e3a5b31737fc722c3ec81bf7`;全量测试跑后状态不变 |
128
+
129
+ **守卫读数定义**(读码核实,适用于下表与全文):
130
+ - **「红 N」**=该处定点变异打红的断言条数;
131
+ - **预期值**=守卫源码变异表 `_SRC_MUTATIONS`(`test_stgidx_index_parity.py:691-798`)每条的**第 6 个元素**;`--branch-baseline` 逐处替换源码后跑全部断言组,判据=「打红集合大小 == 预期」(比较逻辑 `:983-995`);
132
+ - **「恰好命中」**=不多红、不少红(上判据全过);
133
+ - **「空转断言 0」**=没有任何一处变异能打红的断言数为 0(`never = 全部断言标签 − 各变异红项并集`,`:998-1001`)——即每条断言都至少被一处变异打红(有判别力)。
134
+
135
+ ### 4.2 工作流采集(转录)
136
+
137
+ **修复段**:
138
+ - targeted:`python -X utf8 scripts/run_tests.py md_cg` → **233/233 通过、3 跳过、退出码 0**(较改前 232 恰增新守卫 1 件;含 `md_cg.test_issue52_scan_condition_first` 36/36 保绿);
139
+ - 改前树基线对拍(`git archive HEAD` 到系统临时目录、33 用例):关臂逐位 **0/33 不一致**、开臂业务字段 **0/33 不一致**;
140
+ - 收敛读数(5320 节点合成库、串行 9 次中位):`timeline(session=sess_target)` 3.749→0.174ms(scanned 5320→120)、`anchors` 时间窗 6.883→0.077ms(5320→51)、`timeline(session=s1)` 4.366→1.447ms(5320→1265)、冷态含 O(N) 构建 8.3ms。(「→」两端:左=第 1 层**全量臂**、右=第 3 层**索引臂**——按同一读数内 scanned 全量→子集的口径标注;材料原文未逐字标明两端旗标/树。本读数与 §二腿 1 的 T1=3.8ms **不是同一读数**:腿 1 是 5203 库上的纯全量基线锚点,本项是 5320 库上的两臂对照。)
141
+
142
+ **复核段**(§五 详列):三臂 battery(A=HEAD·flag 关 vs B=现行·flag 关 vs C=现行·flag 开):A/B 严格逐位仅 3 处原始差异(1 处复核自加的存在性探针 `meta.index_attr_present`+2 处运行期环境量 `_fingerprint`),**剔除后 0**;B/C 业务字段 0 差异;66 点 0 异常。(66 操作点口径=4 合成库 ×(timeline/anchors/consistency 读面+add/覆写迁移/删除/flush/rebuild/compact 写面+全量状态摘要);C 臂 index 读数(`analyze.py`):命中面真收敛——tl_target scanned=120/full=5325、an_win=51、an_tie=2(同刻并列窗)、tl_nosuch=0;回退面 reason 全覆盖且 `path=full`。)随机对拍 200 轮 0 异常 0 差异;退化输入 34 点(不可哈希 session/layer 值、±inf/NaN 时间、字符串窗口、None token、falsy 层/会话、非 dict 条目;off/on 两遍×两树)非法输入异常类型+消息逐字一致;注入探针 12/12(`fallback_probe.py`;`tables_missing`/`build_failed`/`generation_mismatch`/`table_snapshot_mismatch` 两型;每条=reason 在场+path=full+scanned==全量节点数+结果==关臂);空池 4 点(em.\*)良构;legacy 旧快照(装载后条目缺 temporal/spatial 键=8,两臂同);NaN 保守超集(材料原文:「窗 [inf,inf]:取 3 候选、逐条复核后 2 命中==关臂」;机制读码:时间窗索引取数恒并入 nonfinite 桶(`stgidx.py:256-257`),窗 [inf,inf] 时区间取数为空、候选=nonfinite 全部(3 条)——「逐条复核」=候选仍逐条经语义面精确判定(`time_relation`),2 条命中与关臂相等:**超集只多取候选、不放大结果**);删断言探针(摘 g2→RC 1 且 ①/②/⑭ 红 0≠3/2/1、⑤8≠9、⑦5≠8、⑧13≠14、⑯3≠5、⑰4≠12;摘 g4→RC 1 且 ⑮ 红 0≠1)、fail-closed 三注入→RC 2、真锚点漂移→RC 2+ANCHOR-MISS 点名 `MdCG._set_index_entry`、删表条目→`_table_gaps` 报缺号(两个形态)。
143
+
144
+ **编排侧**:
145
+ - **容器栈一:退出码 1**(读数两段并列:`结果: 22 pass / 0 fail`;`[PASS] smoke_test (linux)`;`=== 汇总: 39 pass / 2 fail ===`——两段的包含关系未随材料提供,本报告如实并列、不合并);
146
+ - **容器栈二:退出码 0**(读数:`# cancelled 0 | # skipped 3 | # todo 0 | # duration_ms 12100.223292`)。
147
+
148
+ ### 4.3 数字口径说明
149
+
150
+ - 三处库规模 **5203 / 5320 / 5325** 分属三个不同夹具实例(修前腿 / 守卫-实施夹具 / 复核夹具),数字按来源分开、不合并;5325 的挂靠读数=复核段 C 臂 `full=5325`(§4.2)。
151
+ - **容器栈一退出码 1(39 pass / 2 fail)**:2 fail 的条目清单与归因**未随材料提供**,本报告如实转写、不代跑、不作红绿归因猜测(§六列未覆盖)。同一栈内 `结果: 22 pass / 0 fail` 与 `=== 汇总: 39 pass / 2 fail ===` 两段的**包含关系**(孰为子集/总账)同样未随材料提供——不合并、不判定。
152
+
153
+ ---
154
+
155
+ ## 五、独立复核判定与未覆盖
156
+
157
+ ### 5.1 判定与依据
158
+
159
+ **判定:ACCEPT**〔工作流采集·复核段〕。依据(复核自述):
160
+ - 只读执行,**未编辑工作区任何文件**(复核自述:复核前后 `git status` 一致——3 处 M+2 处 ??;本报告实跑当刻为 3 M+3 ??,差 1 项=宿主目录 `.zcode/`(非本批交付面)——M 数(3)与交付面 ?? 数(`stgidx.py`、`test_stgidx_index_parity.py`)两口径一致);
161
+ - 全部实验根在系统临时目录(`stgidx_review_rc1`,含守卫夹具残留共 33 个目录已清理);
162
+ - 未 `git add` / `commit` / `push`。
163
+
164
+ **oracle**=改动前实现=仓 HEAD `0d3a0ab2` 整树(`git archive HEAD` 提取到系统临时目录:2158 文件,实证无 `md_cg/stgidx.py`、`stg.py` 无 index 面、`mdcg.py` 无 `_stg_index`)。
165
+
166
+ 复核覆盖面(自述要点):三臂 battery 与改前逐位一致(见 §4.2);随机对拍 200 轮;退化输入 34 点;跨实例(他进程写→重载)路径;注入探针 12/12;空池;legacy 旧快照;守卫两模式独立跑(退出码 0;红项数与声明一致);删断言探针;fail-closed 三注入;可观测面(flag 关不落 `index` 键;开臂回退恒带非空 reason+`path=full`+`index_miss`,命中带 `path=index`/`size`/`full_nodes`;表规模读数独立重算一致;截断面 `truncated/kept/hint` 两臂一致)。
167
+
168
+ ### 5.2 复核列出的未阻断分叉(唯一一条)
169
+
170
+ **不可哈希 `layer`(list/dict)在 flag 开时抛 `TypeError: unhashable type: 'list'`**(已独立复现):
171
+ - 复现:`timeline(cg, layer=['knowledge'], limit=5)`;
172
+ - 出处:`stgidx.subset` 的 `self.by_layer.get(layer, [])`(本报告读码核实=`md_cg/stgidx.py:252`;同形路径 `by_session.get(session)` 在 `:249`);
173
+ - 对照:HEAD 与关臂对同输入返回**空视图**(count=0 / scanned=0);
174
+ - 可达面:`mcp_server.py:1044` 声明 `layer` 为 string,但 `_stg_call`(`:3153`)直通不校验,故 MCP 面可被畸形参数触达;
175
+ - 定性(复核自述):**默认关不受影响**;方向为 **fail-closed(非静默错值)**;属 **schema 外输入**;
176
+ - 处置:本轮**不修**,留池(§六-4)。
177
+
178
+ ### 5.3 复核未覆盖(材料可见范围内)
179
+
180
+ - 容器两栈读数:复核段材料未见引用(容器读数由编排侧另行采集,见 §4.2);
181
+ - 在役库(AEIS 数据面)实测读数:设计稿 §八签收附加要求「实施后须实测——在役库上的路径等价读数与遍历面收敛读数」;本报告材料范围内给出的收敛读数为**合成库(5320 节点)**读数,在役库读数**未随材料提供、本报告未跑**(§六列未覆盖)。
182
+
183
+ ---
184
+
185
+ ## 六、边界与未覆盖(含本轮明确不修而留池的面)
186
+
187
+ **本轮明确不修而留池**(设计稿 §五/§六与复核结论):
188
+
189
+ 1. **默认开关**:不改默认启用(先 flag、逐项验证、再讨论默认开启)——`MDCG_STG_INDEX` / `MDCG_STG_QUALIFY` 默认关,关臂=第 1 层路径(守卫 G1b/G5j 钉住)。
190
+ 2. **资格硬过滤**:首验只**上报**不过滤;硬过滤(与 read 面同权)另立裁定(设计稿 §六-3;§八签收记录:该项「同意」——签收原话与五条明细见设计稿 §八)。
191
+ 3. **`consistency.check` 的 `MAX_SCAN=200` 选面**(字典序前 200 → 应改相关性/条件预筛):签收记录明确「纳入本线**第二实现批**」(批间独立复核)。
192
+ 4. **schema 外输入**(不可哈希 layer/session):复核已列唯一分叉(§5.2),fail-closed、默认关不受影响;本轮不收紧工具面校验,留池。
193
+ 5. **非观察轴不索引**:`anchors` 在 `time_axis != "observed"` 时时间维不索引(回退带 `time_axis_not_indexed`)——表按观察轴建,换轴不预筛,语义由基线同点(`_interval`)保证(`stg.py:609-620`)。
194
+ 6. **跨进程共享**:索引是**进程内**派生结构,各进程自建(`stgidx` 模块 docstring 的「不适用条件」);无共享过期面,亦无跨进程一致性承诺。**部署假设未随材料给出**:构建是**惰性**的(装载后首次 stg 访问才建、写路径零成本——`stg.py:279`/`mdcg.py:3023`),长驻进程内重复查询可摊薄 O(N) 构建(5320 库冷态 8.3ms);若部署为「每查询起新进程」,每次首查须付构建成本——该形态的成本收益对照**未做**(材料无读数,本报告不代算,列入下方待对账)。
195
+ 7. 其它设计稿 §五已声明边界:不改 `max_scan` 数值与第 1/2 层语义;不做 FTS(full-text search,全文检索)替代;不动写入侧磁盘格式(索引为内存派生+同钩维护)。
196
+
197
+ **本报告未能覆盖/核实的**:
198
+
199
+ - **容器栈一退出码 1 的 2 fail 条目与归因**:材料只给汇总读数(39 pass / 2 fail),未给失败条目清单;本报告未复跑(容器不在本报告可及范围),**不作归因猜测**。附注:复核 ACCEPT 的覆盖面与容器读数是**两条独立采集线**(复核段材料未引用容器读数)——本报告不主张「该红栈不影响结论」,只如实登记红栈与其未归因状态;
200
+ - **在役库(AEIS 数据面)实测读数**(§5.3):设计稿 §八签收附加要求「实施后须实测——在役库上的路径等价读数与遍历面收敛读数」的补跑时点与责任人**未随材料提供**,本报告不代答、不代排期;
201
+ - 改前树基线对拍(33 用例)、三臂 battery、fuzz 200 轮、退化 34 点、注入探针等复核实验:本报告**转录**材料读数,未复跑(本报告实跑项=守卫两模式、python 全量、`git grep` 零实现面、行号读码核实、git 面)。
202
+
203
+ **待对账(读者问询项,材料未提供、本报告不代答)**:
204
+
205
+ - **flag 何时开**:「逐项验证」的判据=设计稿 §四 五条验收判据(等价性 / 收敛性 / 不劣化 / 可观测 / 守卫与定点变异);默认开启的判据与时点未随材料提供。§5.2 分叉的 `_stg_call` 校验收紧与 flag 默认开启的先后关系亦未裁定——本轮仅记「不收紧」(§六-4)。
206
+ - **提交与排期**:本批改动何时提交、设计稿的「随批修订+2026-10-03 签收记录」是否随批提交、留池项(资格硬过滤、`consistency` `MAX_SCAN=200` 选面)的排期——均未随材料提供(本报告不含提交动作与排期决定)。
207
+ - **材料取阅位置**:本报告证据源(工作流采集·修复段/复核段、编排侧输出、腿 1 的 `run1/out` 留档)的独立留档位置**未随材料提供**——本报告无法给出取阅路径。
208
+ - **进程生命周期假设**(见 §六-6):长驻 vs 每查询新进程两形态下构建成本的摊销对照未做。
209
+
210
+ ---
211
+
212
+ ## 附:git 面〔本报告实跑〕
213
+
214
+ 工作树(`git status --porcelain`,本次核实;全量测试跑后不变):
215
+
216
+ ```
217
+ M docs/plans/stg条件化与结构索引_设计_v0.1.md
218
+ M md_cg/mdcg.py
219
+ M md_cg/stg.py
220
+ ?? .zcode/
221
+ ?? md_cg/stgidx.py
222
+ ?? md_cg/test_stgidx_index_parity.py
223
+ ```
224
+
225
+ `git diff --stat`:3 files changed, 359 insertions(+), 52 deletions(-)(设计稿 +12 / mdcg.py 77 处变化 / stg.py 322 处变化);新增未追踪 `md_cg/stgidx.py` **281 行**、`md_cg/test_stgidx_index_parity.py` **1020 行**(读码计数)。
226
+
227
+ 未 `git add` / 未 `commit` / 未 `push`(复核段自述一致;提交时点与排期见 §六「待对账」)。本文档落盘后,工作树在这之上仅多 1 个未追踪文件:`docs/eval/第3层stg结构索引_实施记录_v1.0.md`。本报告未改源码、未改上述任何既有文件。
228
+
229
+
230
+ ---
231
+
232
+ ## 附:编排侧收口注记(v1.1,2026-10-03)
233
+
234
+ 1. **容器栈一 2 fail 定因与处置**(本报告 §五 列示的未归因项):两腿=
235
+ `md_cg.test_issue52_scan_condition_first --branch-baseline / --legacy-baseline`——
236
+ **不是代码回归**,是该守卫的 fail-closed 行为**按设计工作**:它检测到 `_scan` 结构被本批
237
+ 改造(实现改了却没同步 `_MUTATIONS`)→ 报 `ANCHOR-MISS` + 退出码 2。
238
+ 处置=按新结构同步五组锚(①三接口候选行 ②读数上报段 ⑥`_sec` 判定 ⑦旧快照回退 ⑧layer 过滤),
239
+ 并在 `_MUTATIONS` 头部加维护记录。同步后逐项复验(编排侧亲跑):
240
+ - 主模式 36/36;`--branch-baseline` 八处变异红项数与预期**逐项一致**(24/15/3/4/4/3/1/2);
241
+ `--legacy-baseline` 修前形态打红 28 条(含 A1/A3 核心)→ 三模式全绿;
242
+ - python 全量 **310/310**;容器栈一 **41 pass / 0 fail**;栈二 **96 / 0 / 3**。
243
+ 2. **在役库实测(设计稿 §八 签收附加要求 · 只读)**:
244
+ - **等价**:flag 关/开两臂,timeline / anchors / consistency 业务字段**逐位一致**;
245
+ - **收敛**:timeline 全量遍历(关) **44.84 ms** → 索引取数(开) **0.86 ms**(**52.07×**,在役 17882 节点);
246
+ - 索引 meta:`path=index / index_hit=1 / fallback=null / size={nodes:17882, sessions:204, layers:8, timed:17882, untimed:0}`。
247
+ 3. **留池登记(非本批引入,会话归属面)**:收口核查中确认——常驻 MCP 重启后进程随机
248
+ session 水印更替(`security.py` 既有随机回退的既有行为),跨重启写入落于不同水印;
249
+ 与「会话归因通道未接通」同族,留池待裁,不在本批范围。
250
+ 4. **裁决**:工作流独立复核的 ACCEPT 维持;容器红栈按上述处置转绿,**未改动任何业务代码**。
@@ -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` 全绿,且返回与现状一致(快照对比);