@furongjun1999/dsh-memory 0.5.1 → 0.6.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.
- package/README.md +588 -552
- package/codebuddy/CODEBUDDY.md +10 -10
- package/data/policy.json +27 -0
- package/docs/discipline/harnesses.yaml +31 -0
- package/docs/discipline/templates/full.md.tmpl +1 -1
- package/docs/discipline/templates/rules.mdc.tmpl +1 -1
- package/docs/eval/DSH/346/227/245/345/277/227/347/264/242/345/274/225v2_/345/217/202/350/200/203dsh-TUI_v1.0.md +248 -0
- package/docs/eval/DSH/346/227/245/345/277/227/347/264/242/345/274/225/346/225/210/346/236/234/351/252/214/350/257/201_v1.0.md +209 -0
- package/docs/eval/DSH/347/253/257/347/274/272/351/231/267/344/270/223/351/241/271_v1.0.md +254 -0
- package/docs/eval/N225_/347/264/242/345/274/225/346/227/245/345/277/227/351/235/236/345/257/271/350/261/241/350/243/205/350/275/275/351/235/242/347/261/273/345/236/213/351/227/270_v1.0.md +418 -0
- package/docs/eval/P1b2_/350/257/273/351/235/242/344/273/243/351/231/205/344/277/256/345/244/215_v1.0.md +124 -0
- package/docs/eval/issue43_/351/273/230/350/256/244/347/255/226/347/225/245/344/270/216/351/224/256/347/261/273/345/236/213/351/227/270_v1.1.md +441 -0
- package/docs/eval/issue43_/351/273/230/350/256/244/347/255/226/347/225/245/345/212/240/350/275/275/344/270/216/345/207/255/346/215/256/346/230/216/346/226/207/351/230/237/345/210/227_v1.0.md +398 -0
- package/docs/eval//344/274/230/345/214/226/347/254/254/344/270/200/346/211/271_/346/216/245/347/272/277/344/270/216/347/255/211/344/273/267/345/217/230/346/215/242_v1.0.md +498 -0
- package/docs/eval//344/274/230/345/214/226/347/254/254/344/270/211/346/211/271_/351/227/250/347/246/201/350/275/254/346/255/243/344/270/216/350/260/203/345/272/246/346/255/242/350/241/200/344/270/216/351/227/250/346/216/247/346/224/266/345/217/243_v1.0.md +669 -0
- package/docs/eval//344/274/230/345/214/226/347/254/254/344/272/214/346/211/271_/344/276/235/350/265/226/351/200/217/344/274/240/344/270/216/345/257/271/346/213/215/345/217/243/345/276/204/344/270/216/350/264/237/347/274/223/345/255/230_v1.0.md +683 -0
- package/docs/eval//345/217/221/345/270/20306_/344/270/200/351/224/256/351/205/215/347/275/256/344/270/216DSH0172_v1.0.md +171 -0
- package/docs/eval//345/217/221/345/270/20307_/345/244/226/351/203/250/346/212/245/345/221/212/345/233/233/346/211/271/344/277/256/345/244/215/344/270/216/346/217/222/344/273/266/351/235/242/345/212/240/345/233/272_v1.0.md +205 -0
- package/docs/eval//346/200/247/350/203/275/344/270/223/351/241/271_/345/206/267/346/237/245/350/257/242/344/270/216/345/206/205/345/255/230_v1.0.md +218 -0
- package/docs/eval//346/225/205/351/232/234/346/263/250/345/205/245/345/256/236/346/265/213_v1.0.md +10 -0
- package/docs/eval//347/274/226/347/240/201/351/235/242/345/211/215/347/275/256_/345/205/245/345/217/243/350/207/252/344/277/235/350/257/201UTF8/344/270/216/346/226/207/346/234/254open/345/256/210/345/215/253_v1.0.md +646 -0
- 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_v18.md +183 -0
- 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_v19.md +207 -0
- 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_v20.md +283 -0
- 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_v21.md +224 -0
- 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_v22.md +223 -0
- 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_v23.md +293 -0
- 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_v24.md +303 -0
- 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_v25.md +230 -0
- 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 +20 -0
- package/docs/hive//350/234/202/345/267/242M6_ingest/345/256/236/346/226/275/350/256/241/345/210/222_v0.1.md +1 -1
- package/docs/mdcg/README/350/257/246/347/273/206/347/211/210_v0.4.10.md +12 -0
- package/docs/mdcg//345/212/237/350/203/275/350/260/203/347/224/250/346/230/240/345/260/204/350/241/250_v0.1.md +40 -40
- package/docs/mdcg//345/217/221/345/270/203/351/227/250/347/246/201/351/223/276_v0.1.md +21 -9
- package/docs/mdcg//347/201/265/346/236/242/350/256/260/345/277/206/345/212/250/350/257/215/345/215/217/350/256/256_v1.0-draft.md +7 -2
- package/docs/mdcg//350/256/244/347/237/245/345/233/276_/347/264/242/345/274/225/344/270/216/345/267/245/347/250/213/350/247/204/350/214/203/345/214/226_/350/256/241/345/210/222_v0.1.md +39 -3
- package/docs/plans//345/205/250/344/270/255/346/226/207/347/274/226/347/240/201/344/270/216/350/234/202/345/267/242/344/273/273/345/212/241/346/240/207/350/257/206/345/245/221/347/272/246_v2.0.md +220 -0
- package/docs/plans//347/234/237/346/272/220/347/264/242/345/274/225_/351/200/232/347/224/250/346/234/272/345/210/266_v0.3.md +227 -0
- package/docs/plans//350/234/202/345/267/242/346/250/241/345/236/213/345/257/206/351/222/245/351/205/215/347/275/256/351/235/242_v1.0.md +385 -0
- package/docs//345/267/245/344/275/234/347/272/252/345/276/213_/350/256/244/347/237/245/345/233/276/346/235/241/347/233/256_v1.1.json +460 -460
- package/dsh/cordis-patch-profile-web.example.yml +35 -0
- package/lib/bridge.js +24 -2
- package/lib/cli.d.ts +3 -0
- package/lib/cli.js +66 -0
- package/lib/hooks.d.ts +31 -2
- package/lib/hooks.js +219 -16
- package/lib/init.d.ts +88 -0
- package/lib/init.js +302 -0
- package/lib/lib/prompt_safety.d.ts +52 -1
- package/lib/lib/prompt_safety.js +76 -1
- package/md_cg/audit.py +652 -379
- package/md_cg/bench6_arms.py +1 -1
- package/md_cg/bench_p0.py +1 -1
- package/md_cg/branches.py +2 -2
- package/md_cg/ccgc.py +1071 -1006
- package/md_cg/chain.py +1 -1
- package/md_cg/consistency.py +97 -9
- package/md_cg/consolidate.py +34 -9
- package/md_cg/crypto.py +59 -26
- package/md_cg/docindex.py +16 -1
- package/md_cg/evidence.py +585 -582
- package/md_cg/evolution.py +17 -1
- package/md_cg/export.py +1 -1
- package/md_cg/forgetting.py +309 -13
- package/md_cg/fsutil.py +454 -8
- package/md_cg/identity.py +3 -3
- package/md_cg/insight.py +24 -3
- package/md_cg/linkref.py +1 -1
- package/md_cg/logref.py +327 -0
- package/md_cg/mcp_server.py +4152 -3818
- package/md_cg/mdcg.py +4208 -3462
- package/md_cg/mdcos.py +4491 -4137
- package/md_cg/mreview/pipeline.py +15 -1
- package/md_cg/nodefile.py +639 -575
- package/md_cg/protect.py +158 -11
- package/md_cg/protocol.py +41 -2
- package/md_cg/provenance.py +22 -4
- package/md_cg/reach.py +4 -4
- package/md_cg/readcache.py +76 -15
- package/md_cg/reconcile.py +1 -1
- package/md_cg/refindex.py +246 -37
- package/md_cg/refine.py +1 -1
- package/md_cg/review_cli.py +49 -4
- package/md_cg/routing.py +32 -5
- package/md_cg/run_tests.py +17 -0
- package/md_cg/scrub.py +30 -3
- package/md_cg/security.py +47 -1
- package/md_cg/self_state.py +5 -5
- package/md_cg/sources.py +23 -6
- package/md_cg/srcindex.py +352 -0
- package/md_cg/stg.py +47 -3
- package/md_cg/subgraph.py +2 -2
- package/md_cg/sustain.py +1299 -1168
- package/md_cg/tasks.py +469 -470
- package/md_cg/test_b1_auto_id_multiproc.py +277 -0
- package/md_cg/test_b1b2_write_face.py +417 -0
- package/md_cg/test_b2_sensitivity_landing.py +223 -0
- package/md_cg/test_b3_merge_keeps_content.py +576 -0
- package/md_cg/test_b4_shard_dir_selfheal.py +843 -0
- package/md_cg/test_b4_shard_dir_selfheal_guard.py +238 -0
- package/md_cg/test_c3_transient_read_negative.py +793 -0
- package/md_cg/test_c8_search_rrf_gates.py +502 -0
- package/md_cg/test_ccg_form_parity.py +188 -0
- package/md_cg/test_ccgc.py +28 -3
- package/md_cg/test_govern_directread.py +17 -4
- package/md_cg/test_h2_session_view_norm.py +233 -0
- package/md_cg/test_h4_sustain_snapshot.py +1377 -0
- package/md_cg/test_hive_ingest.py +285 -285
- package/md_cg/test_index_crossprocess_reload.py +301 -0
- package/md_cg/test_issue39_utf8_stdio.py +307 -16
- package/md_cg/test_issue43_default_policy.py +865 -0
- package/md_cg/test_legacy_p3_node_id_type.py +375 -0
- package/md_cg/test_linkref.py +10 -3
- package/md_cg/test_lock.py +2 -2
- package/md_cg/test_logref.py +1109 -0
- package/md_cg/test_m3_h9_bucket_health_protect_mark.py +301 -0
- package/md_cg/test_m3_h9_semantic_guard.py +525 -0
- package/md_cg/test_mr_m2.py +15 -3
- package/md_cg/test_n130_verify_falsified_protect.py +1 -1
- package/md_cg/test_n139_dek_provision_failclosed.py +185 -0
- package/md_cg/test_n176_link_trust.py +221 -0
- package/md_cg/test_n178_units_jobid_gate.py +212 -0
- package/md_cg/test_n184_keys_concurrent_provision.py +307 -0
- package/md_cg/test_n195_writepath_reload.py +283 -0
- package/md_cg/test_n196_stale_gate_skip.py +169 -0
- package/md_cg/test_n197_n208_write_face_gates.py +471 -0
- package/md_cg/test_n198_tokens_corrupt_failclosed.py +225 -0
- package/md_cg/test_n199_tokens_concurrent_write.py +378 -0
- package/md_cg/test_n201_proposal_visibility.py +382 -0
- package/md_cg/test_n202_session_notes_visibility.py +461 -0
- package/md_cg/test_n204_n205_n226_n227_n228_n229_exit_gates.py +542 -0
- package/md_cg/test_n206_stdio_jsonrpc_type.py +403 -0
- package/md_cg/test_n209_verify_write_face_gates.py +461 -0
- package/md_cg/test_n212_n213_n224_generation_gates.py +513 -0
- package/md_cg/test_n214_n215_n221_n222_write_face_gates.py +563 -0
- package/md_cg/test_n225_nonobject_load.py +1110 -0
- package/md_cg/test_n62_tenant_bind_failclosed.py +200 -0
- package/md_cg/test_neg_condition_hits.py +333 -0
- package/md_cg/test_neg_tail_honesty.py +663 -0
- package/md_cg/test_none_id_write_guard.py +166 -0
- package/md_cg/test_opt_batch1_md_cg.py +451 -0
- package/md_cg/test_p1.py +5 -5
- package/md_cg/test_p11_consistency.py +161 -12
- package/md_cg/test_p26_refindex.py +2 -2
- package/md_cg/test_p27_docindex.py +777 -774
- package/md_cg/test_p28_refcheck.py +740 -13
- package/md_cg/test_p29_session_ingest_export.py +2 -2
- package/md_cg/test_p2_mcp.py +12 -1
- package/md_cg/test_p30_maintain.py +33 -2
- package/md_cg/test_p31_insight.py +1 -0
- package/md_cg/test_p9c_dedup_hints.py +276 -0
- package/md_cg/test_policy_required_ccg.py +426 -0
- package/md_cg/test_protocol.py +22 -0
- package/md_cg/test_rank_parity_score_mode.py +516 -0
- package/md_cg/test_read_face_input_gates.py +363 -0
- package/md_cg/test_read_face_semantics.py +489 -0
- package/md_cg/test_recall_face_guards.py +812 -0
- package/md_cg/test_rejected_credential_forms.py +188 -0
- package/md_cg/test_rejected_redact.py +146 -0
- package/md_cg/test_retr_s1b.py +2 -2
- package/md_cg/test_retr_s5.py +20 -7
- package/md_cg/test_review_cli_attribution.py +177 -0
- package/md_cg/test_review_cli_visibility.py +235 -0
- package/md_cg/test_review_conformance.py +21 -3
- package/md_cg/test_security_audit_v21.py +2 -2
- package/md_cg/test_server_version.py +67 -0
- package/md_cg/test_srcindex.py +171 -0
- package/md_cg/test_tenant_env_override_warn.py +63 -50
- package/md_cg/test_token_lowercase_form.py +315 -0
- package/md_cg/test_v21r1_package_version.py +310 -0
- package/md_cg/test_writepipe.py +10 -4
- package/md_cg/tokens.py +225 -95
- package/md_cg/tool_face.py +4 -4
- package/md_cg/trust.py +49 -5
- package/md_cg/units.py +204 -6
- package/md_cg/weights.py +4 -4
- package/md_cg/whitebox_kb/wisdom/knowledge_points.py +1 -1
- package/md_cg/writelimit.py +42 -8
- package/md_cg/writepipe.py +651 -554
- package/package.json +8 -2
- package/skills/plugin.json +1 -1
- package/src/bridge.ts +25 -2
- package/src/cli.ts +65 -0
- package/src/hooks.ts +229 -16
- package/src/init.ts +361 -0
- package/src/lib/prompt_safety.ts +88 -1
- package/zcode/AGENTS.md +10 -10
|
@@ -0,0 +1,124 @@
|
|
|
1
|
+
# P1b-2 修复报告:读面缓存代际——常驻进程索引跨进程写入不可见(v1.0)
|
|
2
|
+
|
|
3
|
+
- **日期**:2026-09-26
|
|
4
|
+
- **缺陷编号**:P1b-2(DSH 端在役复验 dsh_restart_recheck_20260926 定性)
|
|
5
|
+
- **改动面**:`md_cg/mdcg.py`、`md_cg/mdcos.py`、`md_cg/mcp_server.py` 三改 + `md_cg/test_index_crossprocess_reload.py` 一加(git diff --stat:3 files changed, +90/-7;未 commit,由编排会话负责)
|
|
6
|
+
- **行号口径**:本报告全部 path:line 经报告会话读码逐一核对;与修复会话材料有出入的 3 处已按读码实测修正并在「三、修复」末尾的核对注记中标明。
|
|
7
|
+
|
|
8
|
+
---
|
|
9
|
+
|
|
10
|
+
## 一、缺陷与证据链(DSH 端在役复验时间戳锁死证据)
|
|
11
|
+
|
|
12
|
+
**缺陷**:MdCG 常驻进程的索引只在启动时装载一次,此后 read/get/search 全走内存态——其它进程(典型:review_cli,autoflush=1)写入对常驻进程**不可见**。
|
|
13
|
+
|
|
14
|
+
**证据链(DSH 端在役复验,探针 dsh_restart_recheck_20260926,时间戳锁死)**:
|
|
15
|
+
|
|
16
|
+
| 时刻 | 事件 |
|
|
17
|
+
|---|---|
|
|
18
|
+
| 22:13:16 | 常驻进程启动装载索引快照:14135 节点 |
|
|
19
|
+
| 22:14:37 | review_cli(autoflush=1)写入探针节点 |
|
|
20
|
+
| 22:14:43 | 磁盘 `_index.json` 已含探针(写侧落盘成功) |
|
|
21
|
+
| 同一常驻进程 | `read` 探针 → **null**(读面不可见——病灶) |
|
|
22
|
+
| 旁路新起进程 | `read` 探针 → 命中(新进程装载时读盘即得) |
|
|
23
|
+
|
|
24
|
+
**关键反差**:写侧账本是平的(盘面有、新进程能读),唯独**常驻进程**的内存态停留在启动代——这不是写入丢失,是**读面代际停滞**。
|
|
25
|
+
|
|
26
|
+
## 二、根因(启动装载一次 + 批次39 指纹仅在装载时)
|
|
27
|
+
|
|
28
|
+
1. **架构根因**:`MdCG.__init__` 仅启动时调一次 `_load_index()`(mdcg.py:939),此后 `self.index` 常驻内存,读路径(`get`/`search`/`search_rrf`/`list_goals`)不再碰盘——他进程写快照对常驻进程永不生效。
|
|
29
|
+
2. **演进根因**:批次39 为 issue #33 加的 `_index.json` 指纹校验(`fp = idx.get("_fingerprint")` 与 `_dir_fingerprint()` 比对,mdcg.py:973-974;修前行号 966-967)**也在 `_load_index` 内部**——它防的是「快照写入后盘面有增删」的陈旧快照误信,只在启动装载那一瞬间执行一次,不防「进程存活期间盘面变化」。
|
|
30
|
+
3. 二者叠加:指纹校验给了「索引新鲜」的错觉,实际保鲜窗口只有启动瞬间;DSH 复验链中 22:14:43 的盘面真相到不了 22:13:16 装载的常驻进程。
|
|
31
|
+
|
|
32
|
+
## 三、修复
|
|
33
|
+
|
|
34
|
+
**【机制】**(mdcg.py)
|
|
35
|
+
|
|
36
|
+
- **:946**(`__init__` 装载后):`self._index_sig = self._index_signature()`——记录装载时的文件签名作基线。
|
|
37
|
+
- **:992-1004** 新增 `_index_signature()`:`os.stat(index_path)` 取 `(st_mtime_ns, st_size)` 二元组(微秒级、无 open 无解析);文件不存在或 stat 抛 `OSError` 时返回 `None` 静默——签名探测绝不阻塞读。`(mtime_ns, size)` 在 NTFS 100ns / ext4 ns 粒度下足以识别「他进程写快照」;`None→非 None` 同样可判(他进程首次落快照)。
|
|
38
|
+
- **:1006-1047** 新增 `_maybe_reload_index()`:签名对比(相等含双侧 None → 返回 False 零开销);变化才调 `_load_index()` 重载(`OSError/ValueError` 静默放弃、沿用旧内存态——重载失败不阻塞读);重载后把 `self._dirty` 重放回新索引(`None`=tombstone pop,与 `_load_index` 日志重放同语义)并重算 buckets——本实例未 flush 的写入不因重载从检索面消失;顺带失效 hotcache(默认关)与 readcache(默认开)两个旧索引代派生缓存。
|
|
39
|
+
- **:1139-1141** `compact_index` 写快照后主动刷签名;**:1308-1309** `rebuild_index` 同——**自写不自载**(防止把自己的 compact/rebuild 误判为他进程写入而做无谓重载循环)。
|
|
40
|
+
- **flush 无改动**:flush 只在 `FileLock` 下向 `_index_log` 追加分片、不改 `_index.json`(mdcg.py:1145 def,:1153-1164 追加临界区),签名不变——自身写入/落账**永不**触发重载,正合适。
|
|
41
|
+
|
|
42
|
+
**【接线清单(读码定案,5 处,写路径不接)】**
|
|
43
|
+
|
|
44
|
+
| # | 位置 | 覆盖链 |
|
|
45
|
+
|---|---|---|
|
|
46
|
+
| 1 | mdcg.py:2054 `list_goals` | op=goal list/active 链(MdCGOS.list_goals 走 super 同源) |
|
|
47
|
+
| 2 | mdcg.py:2319 `get` | op=read node_id 链;MdCGSecure.get(mdcos.py:4027-4031,读隔离判定后 `super().get`)同源覆盖 |
|
|
48
|
+
| 3 | mdcg.py:2523 基类 `search` | 空查询早退后、读索引前 |
|
|
49
|
+
| 4 | mdcos.py:767 `MdCGOS.search`(:745 def) | 生产检索 + op=route 链(mcp_server.py:2117-2119 `if op == "route":` → `cg.search(...)`) |
|
|
50
|
+
| 5 | mdcos.py:1315 `MdCGOS.search_rrf` | 置于热路径 query 缓存查询(`hc = _hc.get(self)`,mdcos.py:1322)**之前**——旧索引代缓存命中会静默错答;op=read budget_tokens→recall→search_rrf 链同覆盖 |
|
|
51
|
+
|
|
52
|
+
写路径一律不接(写入面经 `_dirty`/flush 自有账本,接了反而引入自重载循环)。
|
|
53
|
+
|
|
54
|
+
**【maintain reload(显式探活面)】**
|
|
55
|
+
|
|
56
|
+
- mdcos.py:2689-2698 `MAINTAIN_ACTIONS` 登记 `"reload"`(:2690);
|
|
57
|
+
- mdcos.py:2752-2755 maintain 分派 reload 分支:`return {"ok": True, "op": "maintain", "action": "reload", "reloaded": bool(self._maybe_reload_index())}`(:2754)——签名未变时是零开销 stat + False,幂等;
|
|
58
|
+
- mdcos.py:2735 契约注释(生效条件):reload 只触发 `_maybe_reload_index`;
|
|
59
|
+
- mcp_server.py:2688-2698 `_maintain_call` 文档面:action 枚举补 reload,标注只读档(「reload 读面代际刷新 → 不额外拦截」),免 admin 天然放行。
|
|
60
|
+
|
|
61
|
+
**【红守卫】** `md_cg/test_index_crossprocess_reload.py`(新增,run_tests.py 的 `glob("md_cg/test_*.py")` 发现机制自动纳入 CI——scripts/run_tests.py:45;跳过规则 `_SKIPS` 在 :139-146,本守卫不在跳过清单)。守卫六组,全部临时库 + 哑主密钥(进程内 `os.environ['MDCG_MASTER_KEY']='ab'*32` 先行 :134,子进程同哑密钥 :95,`tempfile.mkdtemp` :138/:182/:196/:248,rmtree 清理 :291)。
|
|
62
|
+
|
|
63
|
+
**before / after**
|
|
64
|
+
|
|
65
|
+
- **修复前**:`MdCG.__init__` 仅启动调一次 `_load_index`(mdcg.py:939 旧行),此后 read/get/search 全走内存态;复验证据链(第一节)写侧落盘成功、同常驻进程 read null、旁路新进程可读。
|
|
66
|
+
- **修复后**:读路径入口每调用一次 stat(微秒级)对比签名,他进程写快照(compact/rebuild,典型在 close)即触发重载 + 日志重放,写入/删除(tombstone)对常驻进程可见;自身 flush/写入/compact/rebuild 全程零真实重载(自写不自载)。
|
|
67
|
+
- **守卫红转绿实测**:同解释器双实例(临时库+哑密钥),B 实例 add+close 落快照后——A 禁用 reload 时 read null(修前病灶形态)→ 恢复后 read/search 命中;C 实例 forget+close 后 A read 归 null(tombstone 可见);goal=list 经 list_goals 可见;maintain action=reload 幂等探活(未变 False / 他写后 True 且读面立即可见);旁路子进程 READ 1 0(修前已绿,钉住盘面账本)。
|
|
68
|
+
- **性能粗测**:接线态 vs 重载桩空转态——修复会话实测 157.4µs/读 vs 140.7µs/读(增幅 ~11.9%,即一次 stat 摊入 ~150µs 的 get;断言上界 ×3+30µs 内通过);报告会话复跑 164.0µs/读 vs 149.0µs/读(增幅 10.1%,同断言通过)。
|
|
69
|
+
|
|
70
|
+
**semantics_note(语义边界,如实)**
|
|
71
|
+
|
|
72
|
+
1. **探测面边界**:签名只盯 `_index.json`——他进程**仅追加分片日志、尚未写新快照**(存活写方未 close/rebuild)不在自动探测面内。这正合适:自身 flush 也是纯日志追加,签名不变故零自重载循环;DSH 复验链中 review_cli 退出即 close→compact 落快照,落在探测面内。此类场景可用 maintain action=reload 显式探活(显式 reload 的真重载同样走 `_load_index` 的快照+日志全量口径,日志记录仍须快照重写才并入)。
|
|
73
|
+
2. **mtime 粒度**:NTFS 100ns 粒度下同 tick 同尺寸的两次快照写入理论上可能漏检一次,下次任何签名变化自愈(启发式哨兵的诚实边界)。
|
|
74
|
+
3. **重载保留本实例未 flush 写入**:`_dirty` 重放回新索引(None=tombstone pop,与 `_load_index` 日志重放同语义)并重算 buckets——`_stage` 双写 index+_dirty 的「检索看得到未落盘写入」语义不变。
|
|
75
|
+
4. **派生缓存失效**:重载成功时顺带失效 hotcache(默认关)与 readcache(默认开)——旧索引代的 query 结果与同 path 重写的解析产物不陈旧化;重载是稀疏事件,不构成热路径开销。
|
|
76
|
+
5. **未接线的读面(读码盘点)**:op=edges(provenance.all_edges→index_edges)、protect action=check(mcp_server.py:1142-1146 直读 `cg.index`)、service_info/insight/stats(mcp_server.py:3074-3079 `len(cg.index["nodes"])`)等低频读面仍走启动快照——高频面(get/search/search_rrf/route/recall/list_goals)已全覆盖,低频面如需可后续按同款单行接入。
|
|
77
|
+
6. **stat 成本 vs 常驻不可见取舍**:无跨进程写入时每次读多一次 `os.stat`(实测 ~11-16µs 量级,占 get 的 ~11%,search 毫秒级面摊薄至 <1%),换得跨进程写入可见——读热路径无重载(重载仅在签名变化时发生,重载成本=一次 `_load_index`,与进程重启装载同量级但免去重启)。
|
|
78
|
+
|
|
79
|
+
**核对注记(报告会话读码实测 vs 修复会话材料的 3 处修正)**
|
|
80
|
+
|
|
81
|
+
| 材料 | 实测(本报告采用) |
|
|
82
|
+
|---|---|
|
|
83
|
+
| `MdCGSecure.get:4075` | **mdcos.py:4027-4031**(`MdCGSecure` 类在 mdcos.py:3655 起,不在 mdcg.py;:4075 附近实为 forget 区) |
|
|
84
|
+
| `_maintain_call` 2689-2692 | **mcp_server.py:2688-2698**(def 在 :2688,reload 只读档说明在 docstring :2689-2698) |
|
|
85
|
+
| 批次39 指纹校验 mdcg.py:966-967 | 修复插入后位移为 **mdcg.py:973-974**(报告第一节/第二节按修后行号引用,旧号在括注保留) |
|
|
86
|
+
|
|
87
|
+
## 四、验证(守卫红转绿 + 全量回归 + 门禁)
|
|
88
|
+
|
|
89
|
+
**本会话(报告员)实际复跑**(cmd:`python -X utf8`,工作目录仓库根):
|
|
90
|
+
|
|
91
|
+
| 检查 | 命令 | 结果 |
|
|
92
|
+
|---|---|---|
|
|
93
|
+
| 新守卫 | `python -X utf8 -m md_cg.test_index_crossprocess_reload` | **PASS=21 FAIL=0**(六组全绿:红转绿/旁路子进程/自身写入零重载+自写不自载/maintain reload/goal 链路/性能粗测;⑥性能 接线态 164.0µs vs 桩 149.0µs、增幅 10.1%,上界 ×3+30µs 通过) |
|
|
94
|
+
| ask 点名回归① | `python -X utf8 -m md_cg.test_readcache_prodpath` | **PASS 12 / FAIL 0** |
|
|
95
|
+
| ask 点名回归② | `python -X utf8 -m md_cg.test_index_durability` | **PASS=16 FAIL=0** |
|
|
96
|
+
| 改动面核对 | `git diff --stat` | mcp_server.py 4 行、mdcg.py 77 行、mdcos.py 16 行——合计 **3 files changed, 90 insertions(+), 7 deletions(-)**,与材料一致,未 commit |
|
|
97
|
+
|
|
98
|
+
**修复会话记录(材料转录,本会话未复跑、如实标注来源)**:
|
|
99
|
+
|
|
100
|
+
- 点名回归:`test_p2` 通过 37/失败 0。
|
|
101
|
+
- 扩面(均 0 失败):`test_p2_mcp` 64 通过、`test_readcache_default_on` PASS 10、`test_readcache_precise_inval` PASS 23、`test_i28_hotcache_prodpath` ALL OK 8 项、`test_snapshot_autoclose` PASS=10/FAIL=0、`test_review_cli_visibility` PASS=10/FAIL=0、`test_p30_maintain` 55 通过、`test_p32_backfill` 59 通过、`test_p36_kp_align` PASS=34/FAIL=0。
|
|
102
|
+
- 全量:`python -X utf8 scripts/run_tests.py md_cg --jobs 4 --timeout 600`(后台运行)→ **exit 0,"===== SUMMARY 161/161 通过,3 跳过(依赖缺失/平台不符)====="**;经 `--list` 核对发现 164 目标含 `test_index_crossprocess_reload`,跳过 3 项均为 `_SKIPS` 数据面依赖(test_p44_md_whitebox / test_md_access_parity / test_wisdom_md_store,与 scripts/run_tests.py:139-146 清单一致),与新守卫无关。
|
|
103
|
+
|
|
104
|
+
## 五、DSH 端复验指引(探针 dsh_restart_recheck_20260926)
|
|
105
|
+
|
|
106
|
+
修复部署后,探针应立即可读——**无需重启在役进程**:
|
|
107
|
+
|
|
108
|
+
1. **新起进程**:装载时经 `_load_index`(快照+日志全量口径)天然并入,探针直接可见。
|
|
109
|
+
2. **常驻旧进程**(修复前启动、仍持 22:13:16 旧内存态):二选一——
|
|
110
|
+
- 调一次 `cg(op="maintain", action="reload")`:签名对比必变(review_cli 退出即 close→compact 落了新快照)→ 真重载 → 探针立即可见,返回 `"reloaded": true`;再调一次返回 `false`(幂等探活);
|
|
111
|
+
- 或待其自然重启,重启后装载即含探针。
|
|
112
|
+
3. **注意语义边界①**:若某存活写方只追加了分片日志、尚未写新快照,maintain reload 的真重载也读不到该增量——日志记录须快照重写才并入。DSH 复验链的 review_cli 已退出(close→compact 已落快照),不受此限。
|
|
113
|
+
|
|
114
|
+
## 六、纪律合规声明
|
|
115
|
+
|
|
116
|
+
1. **实验隔离**:全部测试/守卫运行于 `tempfile.mkdtemp` 临时库 + 哑主密钥(进程内 `os.environ['MDCG_MASTER_KEY']='ab'*32` 先行,子进程 env 同哑密钥),绝不触真实 `~/.mdcg` 令牌库(守卫源码 md_cg/test_index_crossprocess_reload.py:56/:95/:134/:291 可复核)。
|
|
117
|
+
2. **在役面零接触**:DSH 在役库与探针 dsh_restart_recheck_20260926 本会话未触碰(仅读代码与跑临时库测试);在役复验按第五节指引执行。
|
|
118
|
+
3. **临时产物清理**:本会话运行守卫产生的 `p1b2_*` 临时目录已清理归零(清理前 8 个 → 清理后 0,已实测复核);`clivis_*` 8 个系批次57 遗留、非本会话产物,按材料注记未动。
|
|
119
|
+
4. **版本管理**:未 git commit(编排会话负责);工作区改动面 = 三改一加,与本报告第一节改动面记录一致。
|
|
120
|
+
5. **报告口径**:本报告不写本机绝对路径;所有 path:line 经本会话读码核对;本会话实跑的检查与修复会话材料转录的检查在第四节分列注明来源,无任何未实跑检查被报告为已通过。
|
|
121
|
+
|
|
122
|
+
---
|
|
123
|
+
|
|
124
|
+
*报告员(工程报告撰写)· 2026-09-26 · P1b-2 v1.0*
|