@furongjun1999/dsh-memory 0.5.0 → 0.6.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.
- package/README.md +572 -465
- package/docs/README.md +1 -0
- 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/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/bench_lingshu_self/bench_self.py +140 -0
- package/docs/eval/bench_lingshu_self/self_bench_result.json +404 -0
- package/docs/eval/bench_lingshu_self//347/201/265/346/236/242/350/207/252/345/272/223/347/253/257/345/210/260/347/253/257/346/243/200/347/264/242/345/256/236/346/265/213_v1.0.md +38 -0
- package/docs/eval//344/270/215/345/217/257/351/235/240/346/200/247/350/220/275/345/234/260_P0_v1.0.md +185 -0
- 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//346/225/205/351/232/234/346/263/250/345/205/245/345/256/236/346/265/213_v1.0.md +422 -0
- package/docs/eval//347/253/257/345/210/260/347/253/257LoCoMoQA/345/220/214/345/217/243/345/276/204/345/257/271/347/205/247_v1.0.md +100 -0
- package/docs/eval//347/253/257/345/210/260/347/253/257/345/271/262/346/211/260/346/261/240/350/257/204/346/265/213_/347/241/256/345/256/232/346/200/247/350/243/201/345/206/263vsLLM_judge_v1.1.md +197 -0
- package/docs/eval//347/274/272/351/231/267/346/214/226/346/216/230_/350/207/252/344/270/273/350/277/255/344/273/243_v1.md +156 -0
- package/docs/eval//347/274/272/351/231/267/346/214/226/346/216/230_/350/207/252/344/270/273/350/277/255/344/273/243_v10.md +210 -0
- package/docs/eval//347/274/272/351/231/267/346/214/226/346/216/230_/350/207/252/344/270/273/350/277/255/344/273/243_v11.md +227 -0
- package/docs/eval//347/274/272/351/231/267/346/214/226/346/216/230_/350/207/252/344/270/273/350/277/255/344/273/243_v12.md +203 -0
- package/docs/eval//347/274/272/351/231/267/346/214/226/346/216/230_/350/207/252/344/270/273/350/277/255/344/273/243_v13.md +233 -0
- package/docs/eval//347/274/272/351/231/267/346/214/226/346/216/230_/350/207/252/344/270/273/350/277/255/344/273/243_v14.md +191 -0
- package/docs/eval//347/274/272/351/231/267/346/214/226/346/216/230_/350/207/252/344/270/273/350/277/255/344/273/243_v15.md +213 -0
- package/docs/eval//347/274/272/351/231/267/346/214/226/346/216/230_/350/207/252/344/270/273/350/277/255/344/273/243_v16.md +214 -0
- package/docs/eval//347/274/272/351/231/267/346/214/226/346/216/230_/350/207/252/344/270/273/350/277/255/344/273/243_v17.md +199 -0
- 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_v2.md +156 -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_v3.md +152 -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_v4.md +128 -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_v5.md +114 -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_v6.md +192 -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_v7.md +187 -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_v8.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_v9.md +203 -0
- package/docs/hive//345/256/211/345/205/250/345/256/241/350/256/241/345/256/236/351/224/232_v0.1.md +202 -0
- package/docs/hive//350/234/202/345/267/242/345/217/214/345/256/236/344/276/213/344/272/222/351/252/214_/350/256/276/350/256/241/345/256/232/347/250/277.md +19 -3
- package/docs/images/lingshu-moonlight-covenant-poster-preview.jpg +0 -0
- package/docs/images/lingshu-moonlight-covenant-poster.png +0 -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/theory//344/270/215/345/217/257/351/235/240/345/256/232/347/220/206/344/270/216/345/244/261/346/225/210/344/274/230/345/205/210/346/241/206/346/236/266_v0.3.md +365 -0
- package/docs//344/270/215/345/217/257/351/235/240/346/200/247/347/220/206/350/256/272_v0.1.md +343 -0
- package/dsh/cordis-patch-profile-web.example.yml +35 -0
- package/lib/bridge.d.ts +9 -0
- package/lib/bridge.js +35 -0
- package/lib/cli.d.ts +3 -0
- package/lib/cli.js +66 -0
- package/lib/index.js +7 -1
- package/lib/init.d.ts +88 -0
- package/lib/init.js +287 -0
- package/lib/lib/roleplay_web.js +530 -443
- package/lib/lib/token_store.d.ts +7 -1
- package/lib/lib/token_store.js +12 -3
- package/md_cg/audit.py +12 -1
- package/md_cg/backfill.py +16 -15
- package/md_cg/backfill_bucket_zh.py +35 -0
- package/md_cg/bench_e2e_judge.py +532 -0
- package/md_cg/bench_e2e_locomo_qa.py +368 -0
- package/md_cg/bench_e2e_qa.py +256 -0
- package/md_cg/branches.py +18 -2
- package/md_cg/ccgc.py +3 -2
- package/md_cg/chain.py +19 -4
- package/md_cg/consolidate.py +7 -6
- package/md_cg/crosscheck.py +4 -3
- package/md_cg/crypto.py +439 -437
- package/md_cg/datapath.py +395 -335
- package/md_cg/evidence.py +8 -3
- package/md_cg/export.py +3 -1
- package/md_cg/forgetting.py +2 -2
- package/md_cg/fsutil.py +48 -0
- package/md_cg/hotcache.py +255 -238
- package/md_cg/interop.py +161 -22
- package/md_cg/judgment_manifest.py +177 -0
- package/md_cg/links.py +655 -622
- package/md_cg/mcp_server.py +282 -31
- package/md_cg/mdcg.py +702 -126
- package/md_cg/mdcos.py +454 -68
- package/md_cg/mreview/govern.py +5 -4
- package/md_cg/postings.py +4 -2
- package/md_cg/readcache.py +76 -18
- package/md_cg/reconcile.py +228 -0
- package/md_cg/review_cli.py +215 -0
- package/md_cg/routing.py +28 -0
- package/md_cg/run_tests.py +211 -0
- package/md_cg/scrub.py +862 -852
- package/md_cg/security.py +385 -275
- package/md_cg/selfreport.py +3 -2
- package/md_cg/signer.py +565 -562
- package/md_cg/sources.py +3 -2
- package/md_cg/stg.py +6 -0
- package/md_cg/sustain.py +1168 -1138
- package/md_cg/test_access_hints.py +147 -0
- package/md_cg/test_branch_discard_tombstone.py +136 -0
- package/md_cg/test_branches.py +259 -249
- package/md_cg/test_chain_read_isolate.py +168 -0
- package/md_cg/test_datapath_device_name.py +203 -0
- package/md_cg/test_emit_negtail_cache.py +156 -0
- package/md_cg/test_en_pipeline.py +186 -166
- package/md_cg/test_govern_directread.py +421 -0
- package/md_cg/test_i32_hotcache_env_key.py +218 -0
- package/md_cg/test_identity_attribution.py +228 -147
- package/md_cg/test_index_crossprocess_reload.py +301 -0
- package/md_cg/test_index_durability.py +238 -224
- package/md_cg/test_interop.py +4 -2
- package/md_cg/test_interop_judgment.py +228 -0
- package/md_cg/test_issue39_utf8_stdio.py +273 -0
- package/md_cg/test_links_concurrent_write.py +188 -0
- package/md_cg/test_merge_upsert.py +168 -0
- package/md_cg/test_n123_derive_expiry_chain.py +205 -0
- package/md_cg/test_n130_verify_falsified_protect.py +185 -0
- package/md_cg/test_n131_merge_gate.py +205 -0
- package/md_cg/test_none_id_write_guard.py +165 -0
- package/md_cg/test_p1x_ref_root.py +160 -0
- package/md_cg/test_p27_docindex.py +774 -765
- package/md_cg/test_p2_mcp.py +3 -0
- package/md_cg/test_p32_backfill.py +304 -298
- package/md_cg/test_p39_verify_flow.py +90 -50
- package/md_cg/test_p47_session_view.py +60 -25
- package/md_cg/test_propose_tail_index.py +157 -0
- package/md_cg/test_read_scope_b27.py +277 -0
- package/md_cg/test_readcache_default_on.py +168 -0
- package/md_cg/test_readcache_precise_inval.py +270 -0
- package/md_cg/test_readcache_prodpath.py +55 -7
- package/md_cg/test_reconcile_v0.py +294 -0
- package/md_cg/test_retr_s1.py +6 -2
- package/md_cg/test_retr_s1b.py +67 -0
- package/md_cg/test_retr_s7.py +8 -0
- package/md_cg/test_retr_s9_entity_ctx.py +181 -175
- package/md_cg/test_retr_score_once.py +208 -0
- 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_onepass.py +170 -0
- package/md_cg/test_rrf_graph_seed_cache.py +154 -0
- package/md_cg/test_security_audit.py +155 -0
- package/md_cg/test_security_audit_b26.py +161 -0
- package/md_cg/test_security_audit_v21.py +250 -0
- package/md_cg/test_semantic_canonical.py +255 -241
- package/md_cg/test_session_isolation.py +168 -0
- package/md_cg/test_snapshot_autoclose.py +187 -0
- package/md_cg/test_tail_watermark_race.py +208 -0
- package/md_cg/test_tenant_env_override_warn.py +139 -0
- package/md_cg/test_tenant_registry_corrupt_warn.py +151 -0
- package/md_cg/test_v14_fixes.py +415 -397
- package/md_cg/test_verify_dirty_reconcile.py +157 -0
- package/md_cg/theory.py +276 -273
- package/md_cg/tokens.py +734 -677
- package/md_cg/units.py +3 -2
- package/md_cg/vision_evidence.py +4 -3
- package/md_cg/whitebox_kb/wisdom/code_solidified.json +6195 -6195
- package/md_cg/whitebox_kb/wisdom/multilang_ir.py +128 -124
- package/md_cg/writepipe.py +554 -550
- package/package.json +11 -2
- package/src/bridge.ts +434 -401
- package/src/cli.ts +65 -0
- package/src/index.ts +526 -518
- package/src/init.ts +347 -0
- package/src/lib/roleplay_web.ts +1019 -932
- package/src/lib/token_store.ts +202 -192
|
@@ -0,0 +1,207 @@
|
|
|
1
|
+
# 缺陷挖掘报告 · 自主迭代 v8(安全专项)
|
|
2
|
+
|
|
3
|
+
- **日期**:2026-09-25
|
|
4
|
+
- **范围**(生效条件):第 8 轮 = 安全专项,四区复核(legacy / auth / inject / fs)确认 **22 条目**(四区 rejected 数组均为空,整项证伪 0;另 2 处证据形态修正见第三节末)→ 去重后独立缺陷 **20**(exec.py:103 与 op=ref 各有两区双报)→ 本轮修复 **5 个补丁覆盖 6 个独立缺陷**(high 4 / medium 2,其中 ref 缺陷两区分别评级 medium/high,取高者处置)→ 遗留 **14**(medium 10 / low 4)
|
|
5
|
+
- **legacy 重开依据**(重要):本轮 8 项 legacy 均非重复报——其中 **v2 N5/N11(verify_runner iter_id 穿越)与 v2 N10(快照 HEAD 残留)经 git 取证证实批次 37 提交(03ae053)信息声称已修但未落盘**(`git show 03ae053 -- hive/verify_runner.py` 无任何 diff;`-- hive/wm.py` 全部改动仅 +4 行 job_id 校验),现行代码确无对应防御,属「声称已修未落盘」的重开,非对已落盘项的重复报告
|
|
6
|
+
- **回归**:`python scripts/run_tests.py --jobs 4` 全量 **174/174 通过、5 跳过(依赖缺失/平台不符)**(材料口径退出码 0;**本报告会话独立实跑同命令,SUMMARY 行与材料逐字一致**;174 = v7 基线 172 + 本轮两个新守卫套件);`cargo test` **未运行**(Rust 面零改动);`npm test` **未运行**(TS 面零改动);`npm run gate` **FAIL——R4 非追踪件面命中新守卫文件 `md_cg/test_p1x_ref_root.py`(非追踪=25、允许=24)**,本报告会话以第 2 环 `check_publish_artifact.py` 单独复现同因同置(R1/R2/R3 全 PASS)——时序性失败(新守卫尚未 `git add` 登记),处置归编排会话提交前裁决,同 v7 先例
|
|
7
|
+
- **行号口径**:缺陷行号为缺陷时点快照行号;本轮修复叠加致三文件行号漂移,涉及处本会话另注现行行号(hive/wm.py:236 → 现行 :253;hive/exec.py:1517 → 现行 :1541;compiler/lexer.py:393 → 现行 :393-394 不变、新增段 :396-410);未修项所在文件本轮零改动或已逐一读核现行行号(见第五节)
|
|
8
|
+
- **编号口径**:legacy 项沿用原轮次号(v2 N5/N11、v2 N6、v2 N7、v2 N10、v2 N16、v3 N6、v5 N24、v6 N38);本轮新发现 12 项独立缺陷沿历轮 N 口径续编 **N60-N71**(v7 用至 N59)
|
|
9
|
+
- **结构口径**(CCG 六要素):功能名(标题)/ 生效条件(范围与口径行)/ 子功能(第二~五节)/ 执行与验证方式(第四节:实跑命令与结果)/ 不适用条件(第七节:跳过与未运行项)
|
|
10
|
+
|
|
11
|
+
---
|
|
12
|
+
|
|
13
|
+
## 一、执行摘要
|
|
14
|
+
|
|
15
|
+
本轮为安全专项:四区复核 22 条候选全部确认、0 项整项证伪(2 处证据形态修正单独列于第三节末,不动摇结论)。修复 5 个补丁(覆盖 6 个独立缺陷)、留档 14 项。三个主题:
|
|
16
|
+
|
|
17
|
+
1. **「声称已修未落盘」的 git 取证重开(legacy 区,3 修)**:v2 N5/N11(verify_runner iter_id 穿越,越界读 frozen.json + 仓库外 makedirs 写 verdict.json)与 v2 N10(快照失败 HEAD 残留 task 分支 → 旧产物绕三级闸进 main)在批次 37 提交信息中声称已修但 `git show` 证无 diff——本轮**实际落盘**(F3/F4)。同区 v3 N6(无空格「条件空间为伴侣」绕过情感权重上限)为第 3 轮遗留,本轮修复(F1)。
|
|
18
|
+
2. **P1-4 根白名单契约在读回面失效(auth+inject 双区独立命中,1 补丁修 2 缺陷)**:ingest/export/link/mdcg_ingest 四入口的 `check_path_root` fail-closed 闸在位,而 **op=ref(自报 root / inline ref / 绝对 path / `..` 上跳三形态全文回读白名单外文件)与 index_code/index_doc(白名单外目录直接进图、docstring/前置注释/md 摘要落 internal 密级节点对 guest 持久可读)三入口零校验**——auth 区(F1/F2,medium)与 inject 区(越权任意读原语,high)两份独立报告同一根因,修复时合并为一个补丁三处挂闸(F2,N60+N61)。
|
|
19
|
+
3. **诚实失败链断裂(legacy+fs 双报,1 修)**:v2 N6(exec.py write_result 裸 `open("w")` 非原子——强杀/崩溃留半截文件且先毁旧完整结果,成功任务被读者判 error 假失败)在 legacy 区与 fs 区三度命中、姊妹执行器 exec_cmd.py 的 tmp+fsync+os.replace 模板在位,本轮照抄补齐并加 Windows 读者面适配(F5)。
|
|
20
|
+
|
|
21
|
+
**对输入口径的核验**:输入称「确认 22 条目 → 修复 5 补丁 6 缺陷 → 留档 14」。本会话以 `git status`/`git diff --stat` + 逐处读核核对:改动面恰为——compiler/lexer.py +15、md_cg/mcp_server.py +20、hive/verify_runner.py +21/-3、hive/wm.py +37/-10、hive/exec.py +28/-2(五个修复补丁)+ 守卫四处(md_cg/test_p1x_ref_root.py +27 新增、md_cg/test_p39_verify_flow.py +27、hive/test_wm_progress.py +23、hive/test_exec_tools.py +47、compiler/tests/test_lexer_v3n6.py 新增)+ cogmap 锚点同步两文件(README.md、docs/mdcg/功能调用映射表_v0.1.md)+ scripts/verify_linux.sh 注册新守卫(40→41 套)——与五项修复一一对应;20 − 6 = 14 留档,无多无少。工作区另有 README.md / docs/mdcg 功能调用映射表 / code_solidified.json 的先前会话改动(cogmap build 只做标记段内替换、段外保留),未与本轮修复混淆。
|
|
22
|
+
|
|
23
|
+
---
|
|
24
|
+
|
|
25
|
+
## 二、修复清单(5 项,逐项 where / 攻击面 / 修复 / 攻击前后对比 / 守卫)
|
|
26
|
+
|
|
27
|
+
### F1(v3 N6,high)lexer 定向断开:「条件空间为X」无空格写法解锁名实校验
|
|
28
|
+
|
|
29
|
+
- **where**:缺陷时点 `compiler/lexer.py:393-394`(CJK 收集分支断开前瞻集合仅「大于/等于/小于/于」,:390-392 注释明示「为」不在集合)+ `compiler/name_checker.py:836`(`_check_condition_space_switch` 要求 condition.type==COMPARISON 且 left=='条件空间' 才设 current_condition_space,:812-819 情感权重上限检查依赖该状态);修复落点 `compiler/lexer.py:396-410`(新增定向断开,本会话读核 :396-410 注释与断开逻辑在位、:393-394 既有集合不变)
|
|
30
|
+
- **攻击面**:任何协议源码作者——无空格写法使「条件空间为伴侣」整段吞作单 IDENTIFIER,parser 不生成 COMPARISON,条件空间切换检测永不触发,「伴侣」空间情感权重上限 0.15 对无空格源码整体失效(超限值通过编译进入条件空间)。批次 37 F1 只修了「于」断开(数值操作数分离),「为」漏在集合外。
|
|
31
|
+
- **修复**(最小 +15 行单处):_segment 的 CJK 连续段收集中,在既有断开集合之后追加**定向断开**——仅当 `text[i-4:i]=="条件空间"` 且当前位置是「为」/「不为」起点时 break。断点落在关键字(WEI/BUWEI,均在 SORTED_KW/KEYWORD_MAP)起点,主循环最长匹配随后正常发出 WEI/BUWEI,使无空格与带空格写法产生相同 token 流 → parser 生成 COMPARISON → name_checker 按既有逻辑设置条件空间 → 0.15 上限对无空格源码生效。**未把「为」全局加入断开集合**(避免切碎「作为/成为/行为/认为/人为/信任为基」等合法名词),name_checker 侧零改动。
|
|
32
|
+
- **攻击前后对比**(临时守卫实跑,`python -X utf8` 调 compiler api):修复前『若条件空间为伴侣,则止情感权重于0.9。』→ `success=True`、errors=[]、warnings=[],token 流为单 `IDENTIFIER("条件空间为伴侣")`;修复后 → `success=False`、errors=['L1:C17 在「伴侣」条件空间中情感权重不可超过 0.15,当前值: 0.9'],token 流 → ID(条件空间)+WEI(为)+ID(伴侣);『不为』无空格形态同拒(L1:C18);合法值 0.15 无空格版不误报;「作为/成为/行为/认为/人为/信任为基」仍为单 IDENTIFIER、「无为」仍为单 WUWEI(断开不外溢)。
|
|
33
|
+
- **守卫**:临时攻击复现守卫(系统临时区,14 项,跑完已删):修复前 6 项红(无空格 errors 非空/点名 0.15/不为形态/token 流三查),基线 6 项绿;修复后 14/14。**永久守卫 `compiler/tests/test_lexer_v3n6.py`**(15 项:攻击拒绝/不为形态/前缀名词无分叉/带空格不回归/合法值不误伤/token 流形态/误伤面钉死)——**本报告会话实跑:15/15 通过**。
|
|
34
|
+
- **范围注(如实)**:「我的条件空间为伴侣」等前缀名词形态无空格/带空格行为一致(均不切换条件空间)——name_checker 只认精确名「条件空间」为既有语义,非本缺陷回归面,按最小改动不扩大。
|
|
35
|
+
|
|
36
|
+
### F2(N60 medium/high 双评级 + N61 medium)op=ref / index_code / index_doc 三入口挂根白名单
|
|
37
|
+
|
|
38
|
+
- **where**:缺陷时点 `md_cg/mcp_server.py:2887`(_ref_call 直接调 `refindex.read_ref`,ref dict 与 root 参数透传)→ 实际读文件 `md_cg/refindex.py:439-466`(probe_ref `os.path.join(root,path)` 后 open 全文回读;绝对 path 时 join 丢弃 base、`..` 上跳同漏)+ `md_cg/mcp_server.py:2275`(index_code `root=a.get("path")`)+ `:2307`(index_doc 同型);修复落点现行 `md_cg/mcp_server.py:2902-2906`(ref read/get 分支)、`:2280`(index_code)、`:2316`(index_doc)——三处挂闸本会话逐一读核在位(含 :2896 「两份独立报告合并」注释),refindex.py 零改动
|
|
39
|
+
- **攻击面**:auth 区口径——持 designer 令牌的 MCP 进程被提示注入(与 P1-4 自身威胁模型同款)或同机多会话宿主,`cg(op=ref, ref={path,root})` 全文读出白名单外哑样例凭据文件;record 令牌与 guest 身份均被 require_op 拒(本轮实测),边界为 designer 面。inject 区口径——任何含 ref 的 op 令牌(designer `ops_allow=["*"]`;签发者可经 `issue --ops-allow` 授自定义只读面):三形态(自报 root / ref.path 绝对路径 / `..` 上跳)全文回读,对照组证明 op 闸本身工作、缺口在 ref 按只读面归类且路径零校验;index_code/index_doc 把白名单外目录(含哑样例密钥文件的 vault)直接进图,泄漏通道实测为**模块 docstring、函数/类前置注释、md 章节摘要首段**三条(普通 `#` 注释实测不进图,见第三节修正),进图节点 sensitivity=internal,无令牌 guest 经 op=read 召回命中泄漏串。
|
|
40
|
+
- **修复**(最小 +20 行单文件三处挂闸,复用既有 `security.check_path_root` 的 P1-4 fail-closed 语义):① _ref_call read/get 分支按**最终将打开的完整路径**挂闸——`check_path_root(os.path.join(a.get("root") or ref.get("root") or "", ref.get("path") or ""), "MDCG_INGEST_ROOT", "ref")`,自报 root、inline ref 自带 root/path、node 登记 ref 三来源统一 realpath 落根判定(绝对 path 丢弃 join base 与 `..` 上跳在 realpath 归一后自然被拒);② index_code 分支对模型可控的显式 `a.get("path")` 挂闸(未传回落服务器侧 cg.root 不校验,与 ingest 先例同语义);③ index_doc 同②。**env 未设置 = 放开(部署开关,默认行为不变);设置了 = 越界抛 PermissionError**,经 stdio 层 tools/call 既有异常处置(mcp_server.py:3690-3699)转 isError 响应。附带:cogmap 锚点同步(`scripts/cogmap_sync.py build` 重写 README COGMAP 段 + 功能调用映射表 3 段——插入代码致行号漂移,build 只做标记段内替换,段外用户文案改动保留);新守卫注册进 `scripts/verify_linux.sh`(本会话读核 diff:清单 40→41 套)。
|
|
41
|
+
- **攻击前后对比**(临时哑数据 + MDCG_INGEST_ROOT 设白名单):修复前——①自报 root 指白名单外 victim → `ok=True` 哑样例密钥全文漏出;②ref.path 绝对路径 → `ok=True` 全文漏出;③`..` 上跳 → `ok=True` 漏出;④index_code path=白名单外 → `ok=True` 越界索引;⑤index_doc 同。修复后——五形态全部 `PermissionError`(「ref/index_code/index_doc 路径超出 MDCG_INGEST_ROOT 白名单,拒绝访问」),哑样例不再出现在任何返回;白名单内 index_code+node 回读 `ok=True`(indexed=2)、白名单内 inline ref 回读 `ok=True` 不误伤;env 未设时 ref 保持既有放开语义;ingest 先例闸与 guest require_op 均不回归。
|
|
42
|
+
- **守卫**:临时攻击复现守卫(系统临时区,10 项,跑完已删):修复前 5 项红(三形态+两索引越界全放行),基线 5 项绿;修复后 10/10。**永久守卫 `md_cg/test_p1x_ref_root.py`**(10 项:①a-c 三形态拒 / ②a-b 索引越界拒 / ③a-b 白名单内不误伤 / ④a ingest 先例不回归 / ④b env 未设行为不变 / ④c guest op 闸)——**本报告会话实跑:10/10 通过**;`git stash` 仅回退 mcp_server.py 对照,旧代码下该守卫 5/10(五项攻击全红)——红守卫确定性达成。
|
|
43
|
+
- **范围声明(如实)**:本轮只覆盖 _ref_call 的 read/get 分支与 index_code/index_doc 显式 path;ref action=check/prune 巡检分支读图内登记 ref(非 inline 模型可控)未挂闸,未在本任务扩大。
|
|
44
|
+
|
|
45
|
+
### F3(v2 N5/N11,high)verify_runner iter_id 白名单:CLI 直跑穿越读写
|
|
46
|
+
|
|
47
|
+
- **where**:缺陷时点 `hive/verify_runner.py:90`(`iter_id = argv[1]` 完全未校验)、`:103`(frozen_fp 裸拼——越界读)、`:161-162`(out_fp 裸拼 + os.makedirs——越界写);修复落点 `hive/verify_runner.py:97-105`(本会话读核 :102-106 白名单与 rc=2 分支在位、:80-93 docstring 生效条件同步)
|
|
48
|
+
- **攻击面**:verifier 实例(半信任对等体)CLI 直跑 verify_runner.py——argv[1] 传 `..\` 穿越形态、自设 HIVE_ROLE=verifier 即过角色守卫(守卫只查环境变量值);姊妹入口 write_verdict_to_repo(md_cg/interop.py:316 `re.fullmatch(r"[A-Za-z0-9_.-]{1,80}")`)有白名单而本入口没有,防御不一致。**git 取证**:`git log -- hive/verify_runner.py` 最后改动 d2dc6bd;`git show 03ae053 -- hive/verify_runner.py` 无任何 diff——批次 37 提交信息声称已修「verify_runner iter_id 穿越」但未落盘。
|
|
49
|
+
- **修复**:main() 取 argv[1] 后、任何路径拼接之前新增同模板白名单 `re.fullmatch(r"[A-Za-z0-9_.-]{1,80}", iter_id)`,不过即打印 `{"ok":false,"error":"iter_id 非法(入库路径组成部分)…"}` 诚实留痕并 rc=2 退出(**不触盘、不读 frozen、不 makedirs**,fail-closed 于路径拼接之前)。
|
|
50
|
+
- **攻击前后对比**(同盘仓库外临时目录,测毕清理):修复前——iter_id=穿越形态 + HIVE_ROLE=verifier + `--smoke` → rc=0,stdout path 字段指向仓库外 verdict.json,盘面确认仓库外 frozen.json 被读入(越界读实锤)、verdict.json 被写入(越界写实锤);修复后——同一形态复跑 → rc=2、输出含「iter_id 非法」、仓库外无任何文件创建(盘面零触达)。
|
|
51
|
+
- **守卫**:`md_cg/test_p39_verify_flow.py` 新增确定性红守卫 **2e**(穿越形态 + verifier 身份 → 断言 rc=2、输出含「iter_id 非法」、仓库外目标路径 os.path.exists 为 False 即不触盘)与 **2f**(绝对路径注入形态同断言),本会话读核 :110-121 在位;原有守卫(2d 角色守卫 rc=3、3c 姊妹入口注入拒绝)语义不受影响——**本报告会话实跑整套:11 passed, 0 failed**。
|
|
52
|
+
|
|
53
|
+
### F4(v2 N10,high)wm 快照提交链 try/finally:失败不再残留 HEAD 于 task 分支
|
|
54
|
+
|
|
55
|
+
- **where**:缺陷时点 `hive/wm.py:166-173`(checkout -B → add → commit → rev-parse → checkout main 之间无 try/finally,任一步 _git_ok 抛 WmError 即把 HEAD 永久留在 task/<job_id>);修复落点 `hive/wm.py:167-192`(本会话读核 :174-181 try 四步 + :182-190 finally 无条件 checkout main 在位,:167-172 生效条件注释同步)
|
|
56
|
+
- **攻击面**:result.json 自报 job_id 的产物数据不可信 + 快照重试/重复执行确定性触发——典型:重复快照已合并任务 → commit「nothing to commit」退出码 1 → WmError 后 HEAD 残留 task 分支 → 三级闸 merge 被卡死(「merge 须在 main 上执行」)或更糟:后续新任务分支以残留分支为祖先,合并新任务把旧任务产物静默带进 main,绕过旧任务自己的三级闸合并审查。**git 取证**:`git show 03ae053 -- hive/wm.py` 全部改动为 +4 行 job_id 路径段校验——「快照 HEAD 残留」声称修复未落盘。
|
|
57
|
+
- **修复**:提交链四步包入 try,新增 **finally 无条件 checkout main**;还原失败不吞——try 内有正传播异常时抛消息合并(`from` 原异常)的 WmError、无则直接抛,均含「HEAD 可能残留于 <branch>」提示(留痕)。诚实失败语义不变:nothing-to-commit 仍如实抛 WmError。
|
|
58
|
+
- **攻击前后对比**(系统临时区临时 wm 仓;修复前对照经 `git show HEAD:hive/wm.py` 提取临时副本加载,不动工作区,测毕清理):修复前——snap1 ok → merge ok → snap2 同 job 重复快照抛 WmError → 终态 HEAD=task/<job> ≠ main(残留实锤)→ cmd_merge 被残留卡死 → snap3 新任务成功且以残留分支为祖先(旧产物绕闸进 main 路径成立);修复后——snap2 仍如实抛同一 WmError 但 HEAD=main(不残留)、cmd_merge ok=True(三级闸不再卡死)、snap3 正常且新任务分支从 main 主线创建(含已合并提交)。
|
|
59
|
+
- **守卫**:`hive/test_wm_progress.py` 新增 **[G] 段**五项(本会话读核 :249-269 在位)——G1 重复快照如实抛 WmError;G2 失败后 HEAD==main(红守卫判定点);G3 失败后三级闸不被卡死;G4 失败后新任务快照正常;G5 新任务分支从 main 主线创建——**本报告会话实跑整套:PASS=49 FAIL=0**(原 44 项无回归)。
|
|
60
|
+
|
|
61
|
+
### F5(v2 N6,medium)exec write_result 原子写:强杀/崩溃不再留半截 result.json
|
|
62
|
+
|
|
63
|
+
- **where**:缺陷时点 `hive/exec.py:103-105`(`with open(...,"w"): json.dump` 裸写,全文件 grep tempfile/fsync/os.replace 零命中);修复落点 `hive/exec.py:102-131`(本会话读核 :116-129 tmp+fsync+replace 与 WinError 5 重试环在位、:102 生效条件注释同步);exec.py 内六处调用(:1447-1560 缺陷时点口径)+ `hive/orch.py:570/588` 复用同一函数,一处修多处受益
|
|
64
|
+
- **攻击面**:rust serve 超时/kill 强杀(`hive/src/scheduler.rs:430-441` kill_requested 与 timeout 两分支均 kill_tree 强杀 worker)落在写入窗口内 → 半截文件且**先毁旧完整结果**(重投第二次执行同路径);读者面——`wm.py` _read_json 不捕获解析异常且 main 只捕获 WmError → 半截 result.json 使 wm snapshot 裸 traceback 崩溃;rust 轮询、hive_mcp._result_view、orch._card 同样暴露(成功任务被读成 error 假失败)。姊妹执行器 `exec_cmd.py:39-48` `_write_result` 已用 tmp+flush+fsync+os.replace 且注释明示原子语义——两套口径。
|
|
65
|
+
- **修复**:照抄姊妹模板 + Windows 适配——修复过程实撞发现:纯 os.replace 在 Windows Python 读者(open 无 FILE_SHARE_DELETE)高频打开下抛 PermissionError WinError 5(exec_cmd 无此问题因其读者是 rust),故 replace 撞瞬态句柄时 10ms×递增重试至多 50 次(约 12.5s),耗尽才抛(此时旧完整结果仍在位,fail-safe)。
|
|
66
|
+
- **攻击前后对比**(系统临时区,测毕清理):①并发撕裂压测(1 写者 3MB×30 + 4 并发读者高频 json.load)——修复前 torn=125 + empty=7176(半截解码失败 + 旧结果被截断成空文件的窗口),对照组 exec_cmd 同场景 0 撕裂;修复后 **torn=0 empty=0**,线程形态最严苛压测(2 读者线程 + 1MB×20)33551 次读零异常;②强杀截断旧结果(确定性)——先落完整旧结果 → 写 100MB 中途 terminate 模拟 kill_tree → 修复前 result.json=0 字节、旧完整结果被毁;修复后旧结果完整存活、无 tmp 残留;③读者面崩溃链(半截 result.json → wm snapshot 裸 Traceback)的**源头已断**——wm 对「手工半截文件」的裸 Traceback 属读者面既有行为,不在本修复 where 范围,如实说明未改(见遗留建议)。
|
|
67
|
+
- **守卫**:`hive/test_exec_tools.py` 新增 **[K] 段**(本会话读核 :655-692 在位)——K1 result.json 写后完整可解析且无 .tmp 残留;K2 双读者线程高频读 + 主线程 1MB×20 连写压测 → torn==0 且 empty==0(旧码此压测必现撕裂,线程形态实测灵敏度为 torn=22+empty=11)——**本报告会话实跑整套:87 通过 / 0 失败**(原 85 项无回归)。
|
|
68
|
+
|
|
69
|
+
---
|
|
70
|
+
|
|
71
|
+
## 三、发现明细(四区确认 22 条目 / 整项证伪 0 / 证据形态修正 2 处)
|
|
72
|
+
|
|
73
|
+
四区复核 rejected 数组均为空——**零整项证伪**,如实记录。以下每项「证据」为上游复核会话的读码+实跑(材料原文,攻击复现均在系统临时区/哑令牌/哑数据、测毕清理,环境细节按仓库口径转录);标注★者本报告会话另做了现行代码读核。
|
|
74
|
+
|
|
75
|
+
### legacy 区(8 条目,4 项已修、4 项留档)
|
|
76
|
+
|
|
77
|
+
| # | where(缺陷时点) | 严重度 | 问题摘要 | 证据要点 | 状态 |
|
|
78
|
+
|---|------|--------|----------|----------|------|
|
|
79
|
+
| v2 N5/N11★ | hive/verify_runner.py:90 | high | iter_id 取自 argv[1] 完全未校验即裸拼读/写路径:`..\` 穿越可从仓库外读 frozen.json、仓库外 makedirs+写 verdict.json;姊妹入口有白名单本入口没有 | 本轮实跑复现(同盘临时目录测毕清理):iter_id=穿越形态 + HIVE_ROLE=verifier + --smoke → rc=0、stdout path 字段=仓库外 verdict.json、盘面确认越界写+越界读;git 取证 03ae053 声称已修无 diff | **已修**(F3) |
|
|
80
|
+
| v3 N6★ | compiler/lexer.py:393 + name_checker.py:836 | high | 「伴侣」条件空间情感权重上限 0.15 对无空格中文写法完全失效:『若条件空间为伴侣,则止情感权重于0.9。』编译成功零错误零警告 | 本轮实跑:无空格版 success=True/errors=[]/warnings=[];带空格版 success=False 点名 0.15 上限——守卫在位但只对分词形态生效;断开集合仅四词、_check_condition_space_switch 恒不触发 | **已修**(F1) |
|
|
81
|
+
| v2 N10★ | hive/wm.py:166 | high | cmd_snapshot 无 try/finally 还原 HEAD:checkout -B 后任一 git 步骤失败即把 HEAD 永久留在 task/<job_id>(典型:重复快照 nothing to commit)→ 三级闸卡死或残留分支为祖先致旧产物绕闸进 main | 本轮实跑复现(临时 wm 仓测毕清理):snap2 抛 WmError 后终态 HEAD=task 分支≠main、merge 被卡死、snap3 新任务以残留分支为基;git 取证 03ae053 只落了 +4 行 job_id 校验、「HEAD 残留」未落盘 | **已修**(F4) |
|
|
82
|
+
| v2 N6★ | hive/exec.py:103 | medium | write_result 直接 open("w") 覆盖写 result.json 非原子:并发读者(rust poll/status、wm 快照拷贝)可读到截断 JSON 被判 error 终态;exec_cmd.py:39-48 同契约已原子写,exec.py 漏修 | 本轮实跑(4 秒并发对撞):424 次坏读(JSONDecodeError 截断形态样例);全文件 grep tempfile/fsync/os.replace 零命中 | **已修**(F5;与 fs 区第 1 条为同一缺陷双报) |
|
|
83
|
+
| v2 N16 | hive/hive_mcp/mcp_server.py:566 | medium | _rpc 入口 req.get("method") 对非 dict JSON 形态抛 AttributeError 且早于只包工具调用的 try;main 循环只护 json.loads 的 ValueError——JSON-RPC 2.0 规范允许的批量请求(数组)或任意 str/int 行使整个 MCP server 进程崩溃退出,一行即 DoS | 本轮实跑复现(临时子进程逐 payload 喂 stdin):dict 形态 rc=0;数组形态 rc=1 + AttributeError 'list' object;str/int 同崩——崩溃仅由非 dict 形态触发 | 留档(本会话读核 :565-566 现状未变:无形态守卫) |
|
|
84
|
+
| v6 N38 | src/lib/token_store.ts:76 | medium | auxRoot() 用 resolve(env):不做波浪线家目录展开且锚定宿主 cwd,与文件头声称「同口径」的 md_cg/datapath.py aux_root()(expanduser+abspath)不一致——MDCG_AUX_ROOT 设波浪线/相对形态时密钥环与令牌记录分居两处,触发重复自动签发永不吊销的 designer 令牌 | 隔离探针(node 侧仅计算路径不读写真实令牌):波浪线形态 node 返回字面波浪线目录(锚 cwd)、python 返回真家目录展开——分居实锤;相对形态 node 结果随 chdir 变化;token_store.ts 全文 grep revoke 仅用户提示文案 | 留档(本会话读核 :76-79 resolve(env) 现状未变) |
|
|
85
|
+
| v5 N24 | swarm/swarm_cli.py:78 | medium | cmd_run 调 make_swarm_config 未传 condition_space:用户在 swarm.json 声明的 G-R2 条件空间卡被 CLI 静默丢弃——不进生成配置、不触发 Rust 侧负路由校验、执行链 VM 符号注入失效 | 实跑探针(monkeypatch 截获 cfg 不跑真 swarm):截获 cfg keys 无 condition_space 键;rust_swarm.py:31/:46-47 库层支持完整;绿套件直连 make_swarm_config 绕过 CLI 故全绿而缺口在位 | 留档(本会话读核 :78-81 实参表现状未变) |
|
|
86
|
+
| v2 N7 | hive/exec.py:1517(现行约 :1541,F5 修复上方 +28 行漂移) | medium | call_llm 单发路径(无 tools)缺 _empty_turn 防护:call_llm 对空/缺 choices 回 content="",无条件 ok=True 落盘 EXIT_OK——LLM 服务故障回空包时任务被记成功,空内容 result.json 流入下游合并/验证链(假成功);工具路径 :1348 有完整防护,两分支不对称 | 本轮实跑复现(本地 http.server mock 200+空 choices、哑令牌、临时 job 目录测毕清理):python hive/exec.py → rc=0、result.json ok=true、content='';_empty_turn 存在(:1200-1206 缺陷时点)且 docstring 明言不冒充有效终答,但仅工具路径使用 | 留档(本会话 grep 核实 _empty_turn 现仍仅工具路径一处调用) |
|
|
87
|
+
|
|
88
|
+
### auth 区(4 条目,2 项已修并入 F2、2 项留档)
|
|
89
|
+
|
|
90
|
+
| # | where(缺陷时点) | 严重度 | 问题摘要 | 证据要点 | 状态 |
|
|
91
|
+
|---|------|--------|----------|----------|------|
|
|
92
|
+
| N60(本报告编号;与 inject 区第 1 条同一缺陷双报) | md_cg/mcp_server.py:2887(ref 入口;实际读文件 refindex.py:439-465) | medium(auth 区评级;inject 区对同一缺陷定 **high**,取高者处置) | cg op=ref 的 ref/path/root 均为模型可控参数,直通 refindex.read_ref→probe_ref 的 os.path.join+open,全程无 check_path_root——P1-4 根白名单契约(配置 MDCG_INGEST_ROOT/MDCG_EXPORT_ROOT 即 fail-closed)在读回路径失效,可读白名单外任意本地文件任意行区间;check_path_root 全文仅 5 处调用,ref 分支零调用 | 独立复现(临时目录哑数据测毕清理):对照 ingest 同路径被 PermissionError 拦(P1-4 生效);攻击形态经真实分发路径返回 ok=true 且哑样例密钥两行全量漏出;root 参数覆盖同法读出 victim 首行;record 令牌与 guest 身份均被 require_op 拒——边界为 designer 面 | **已修**(F2) |
|
|
93
|
+
| N61 | md_cg/mcp_server.py:2275(index_code root=a.get("path");index_doc 同型 :2307) | medium | cg op=index_code/index_doc 的 path 参数不经 check_path_root,白名单外目录直接进图(P1-4 点名的『/etc/passwd 进图』形态);进图节点 sensitivity=internal,对无令牌 guest 持久可读——一次 designer 调用即把本地敏感文件变成全 root 低权可读面 | 独立复现:①index_code 白名单外 vault 返回 ok=true indexed=1(对照 ingest 同路径被拦)——越界进图成立;②泄漏通道实测修正见第三节末;③index_doc 对 .md 章节摘要首段进 content(受 MAX_DOC 截断);④guest cg.get 经 op=read 召回命中泄漏串 | **已修**(F2 同补丁顺带,留档清单的处置建议被采纳) |
|
|
94
|
+
| N62 | md_cg/tokens.py:410(tenant=tenant or rec.get("tenant"))+ mcp_server.py:3448(verify_token 传 env MDCG_TENANT) | medium | 令牌的租户绑定被 env 参数静默覆盖(签发时记录的 tenant 仅作缺省值);同时租户登记表的 clearance_cap 夹紧(security.py:316-334 cap_of/principal_for)在权威令牌路径从未接线(全仓 grep 授权路径零调用)——一枚 tenantA 签发的 secret/designer 令牌可对 cap=public 的 tenantB 登记根以 secret+can_admin 运行,多租户密级上限契约失效 | 独立复现(临时哑令牌+临时租户登记表测毕清理):verify_token(tok, tenant="tenantB") → principal{tenant:tenantB, clearance:secret, can_admin:true} 覆盖成立无夹紧;对照 TenantRegistry.principal_for 夹紧到 public(接线后本应有的防护缺席);_resolve_root 不设 MDCG_ROOT 时随 env 切到 tenantB 登记根(设 MDCG_ROOT 冲突时有 fail-closed 拒启一层缓解) | 留档(本会话读核 :410 现状未变;修复涉授权链语义设计超出本轮范围) |
|
|
95
|
+
| N63 | src/lib/token_store.ts:97-105(writeKeyring) | low | 密钥环写入 writeFileSync 直写(无 tmp+rename),偏离本仓原子写纪律(md_cg/tokens.py _write_secret、security.py TenantRegistry._save 均 tmp+os.replace);首启自动签发窗口进程中断留半截令牌文件,后续激活把残缺内容当 keyring 凭据原样喂 MCP,verify_token fail-closed 拒启——写入凭据状态损坏,需手工删密钥环恢复 | 读码核实::99 直写目标文件;readKeyring 任意非空内容原样返回无格式校验并注入 MDCG_TOKEN;python 侧影响链实测(哑令牌):截断令牌 verify_token 抛 TokenError、格式损坏 parse_token 抛「令牌格式非法」,对应 fail-closed 拒启。**TS 侧中断注入复现未运行(无 TS 运行环境)——读码证据,如实标注** | 留档(本会话读核 :96-105 现状未变) |
|
|
96
|
+
|
|
97
|
+
### inject 区(4 条目,1 项已修并入 F2、3 项留档)
|
|
98
|
+
|
|
99
|
+
| # | where(缺陷时点) | 严重度 | 问题摘要 | 证据要点 | 状态 |
|
|
100
|
+
|---|------|--------|----------|----------|------|
|
|
101
|
+
| N60 重复条目(inject 区独立报告) | md_cg/refindex.py:439-466(入口 mcp_server.py:2880-2887) | **high**(越权任意文件读原语口径) | op=ref 是越权任意文件读原语:probe_ref 以调用方自报的 root 与 ref.path 直接 join 后 open 全文回读,无租户根校验、无 check_path_root、无密级闸;designer 令牌 ops_allow=["*"] 恒可触发,签发者可授自定义只读面含 ref;inline ref 字典与 root 参数均模型可控,提示注入即可让常驻 agent 读宿主机任意文件并全文进入模型上下文。同族缺口:index_code/index_doc(即 N61) | 临时目录实测(只读 Principal actor=attacker, ops_allow 含 ref,测毕清理):三形态全部 ok=True 全文回读——①自报 root 指记忆根外 victim;②ref.path 绝对路径(join 丢弃 root);③`../` 上跳;对照组 ops_allow 不含 ref 的令牌被 require_op 拦(op 闸工作、缺口在路径零校验);对照同库 add() 的 node_id 白名单+realpath 双闸有效未见旁路 | **已修**(F2;修复注释自称「两份独立报告合并」本会话读核在位) |
|
|
102
|
+
| N64 | compiler/codegen.py:390(同族 :490-491) | medium | 假成功掩盖失败:赋值目标与裸标识符表达式不经 _py_name 校验直接拼入产物——ASCII Python 关键字作目标/表达式时编译报 success=True 且验证单元终裁 passed=True/confidence=0.85,但产物 compile() 必 SyntaxError;函数名有 _py_name 闸(:525)而赋值目标/表达式标识符漏挂——终裁权威被击穿为橡皮图章 | 本轮实测(python -X utf8,临时脚本测后删):compile_source('class = 5')/('import = 5')/('lambda = 3')/('x = lambda') 全部 success=True、errors=[]、verdict.passed=True/confidence=0.85,对产物 compile 均抛 SyntaxError;对照 'x = 5' 产物可正常 compile;api.py:194 success=len(errors)==0 对产物无 compile 终验 | 留档(本会话读核 :390 f"{stmt.target} = " 现状未变) |
|
|
103
|
+
| N65 | src/lib/roleplay_web.ts:745(同族 :952-960) | low | HTTP 入口校验不一致:/roleplay/api/roles/:id/import 提取的 role_id 与 POST /roleplay/api/roles(role_create)的 body role_id 不做 validRoleId 白名单校验,任意键直落 _roles.json 并透传外部 capability 后端;/meta(:804) 与 chat(:845) 均已挂白名单 | 读码核实:/import 分支仅 decodeURIComponent 取段无 validRoleId 即写 meta 落盘+callTool('role_import');POST /roles p.role_id 未校验直传 role_create 与 writeRole。node 实测:null-proto 对象上赋 __proto__ 键会持久化(JSON.stringify 输出该键、hasOwnProperty 为 true);JSON.parse 回读不污染原型。缓解确认在位:readRoleMeta 空原型(:606-620);mdcg 侧 node_id 白名单拦截 roleplay_${role} 模板注入 | 留档(本会话读核 :745 与 :952-960 现状未变) |
|
|
104
|
+
| N66 | src/lib/roleplay_web.ts:829-891 | medium | /roleplay/api/chat 无 CSRF 防护:不校验 Origin/Referer/Host,readBody 不检查 Content-Type,写操作零鉴权——恶意网页可对本地 webServer 跨站静默写入受害者转录并触发 LLM 生成(持久记忆投毒面);写类端点有 x-edit-key 闸兜底,chat 端点无任何等价防线 | 临时目录 mock 实测(tsc 编译到临时目录,mock webServer/capability/mdcg,哑后端测毕清理):①text/plain 简单请求形态(无 Origin/Referer)POST /roleplay/api/chat → 200、roleplay_chat 被调用、writeTranscript 落图两次、转录文件落盘两行;②伪造 Origin 同样 200;③对照同形态 POST /roleplay/api/translate → 403(P1-2 闸工作)。**未实测前提(如实标注):本机无 Cordis 宿主未做浏览器端到端验证** | 留档(本会话读核 :829-835 现状未变;修复涉合法跨源接入面决策) |
|
|
105
|
+
|
|
106
|
+
### fs 区(6 条目,1 项已修即 F5、5 项留档)
|
|
107
|
+
|
|
108
|
+
| # | where(缺陷时点) | 严重度 | 问题摘要 | 证据要点 | 状态 |
|
|
109
|
+
|---|------|--------|----------|----------|------|
|
|
110
|
+
| v2 N6(fs 区条目,与 legacy 区第 4 条同一缺陷双报) | hive/exec.py:103 | medium | result.json 非原子写:open("w") 直接截断写,无 tmp+rename,超时强杀/崩溃留半截文件且先毁旧完整结果;读者面 wm._read_json 不捕获解析异常 → wm snapshot 裸 traceback;rust 轮询/hive_mcp._result_view/orch._card 同暴露 | 临时目录实测(测毕清理):旧完整结果在位后写 3MB×30 + 4 并发读者 → 145 次读命中 131 次撕裂(28 半截解码失败 + 103 空文件窗口);对照组 exec_cmd._write_result 同场景 2762 次读 0 撕裂;半截 result.json 实跑 wm snapshot → 裸 Traceback(JSONDecodeError 逃出 except WmError) | **已修**(F5) |
|
|
111
|
+
| N67 | hive/wm.py:236(现行 :253——同文件 F4 修复上方增行致漂移,本会话读核 join 在 :253) | medium | cmd_progress 的 --job-id 无路径段校验,os.path.join(wm,"jobs",job_id,...) 可穿越读 wm 仓外任意 JSONL 文件并全文回显;cmd_snapshot 对同款输入有「防穿越删库」校验、hive_mcp._valid_job_id 已修同族穿越(poll/kill),progress 分支漏同类闸 | 临时目录实测(测毕清理):job_id=两穿越形态均返回 ok=True、entries 与 handoff 聚合卡全文回显仓外 progress.jsonl(哑密文标记漏出);对照实测 _valid_job_id 对同形态 =False | 留档(**处置建议未于本轮采纳**:留档材料建议修 wm.py:166 时同 patch 顺带挂闸约三行,本轮 F4 修复面未含——如实记录,见第五节) |
|
|
112
|
+
| N68 | hive/orch.py:417 | medium | _spawn 白名单键透传 mdcg_root 给编排者模型:认知图读写面落点由不可信 LLM 控制可在任意目录创建文件/写入模型可控内容;exec.py 工具分发对编排工具无键过滤,子任务经 spec.get("mdcg_root") → env MDCG_ROOT 优先、spec 兜底——serve 未设 MDCG_ROOT 的部署即生效 | 读码+临时目录实测(测毕清理):pop MDCG_ROOT 后以 mdcg_root=临时 evil_root 调 op=write → 目标目录被创建 _audit.jsonl/_keys.json/hippocampus/inbox.jsonl(含模型可控哑正文标记)等;op=read 同样接受任意目录为图根。补强 nuance(如实):_spawn_schema 未声明 mdcg_root 键,正常调用面不常传,但代码层零过滤、注入可达;.md 节点直写需 audit ACCEPT,medium 定级成立 | 留档(本会话读核 :417-418 键元组现状未变) |
|
|
113
|
+
| N69 | hive/orch.py:417(context_files 通道 :408-411) | medium | context_files 通道绕过 read_file 的全部敏感文件防线:编排者模型可指定凭据类文件全文注入子代理上下文发往外部 LLM 网关——read_file 工具面三道防线(scope_roots+roots+_sensitive_read+PII 脱敏)在 spec.context_files 通道零检查,且该参数在 _spawn_schema 明确声明为模型正常可用 | 读码对比+临时目录实测(哑数据测毕清理):伪造 .ssh 私钥与 .env 经 build_messages → 私钥块与哑样例密钥全文进 messages、无任何脱敏标记;同两路径 tool_read_file 均被 _sensitive_read 拒读(「敏感凭据目录」「密钥/环境凭据文件」)——同文件双通道防线差异实拍。**未实测外发(不触真实网关/密钥)** | 留档(本会话读核 :408-411/:417 现状未变) |
|
|
114
|
+
| N70 | hive/orch.py:269 | low | _save_children 静默吞写盘失败(except OSError: pass,无 log 无重试)→ children 清单丢失,换人续跑重复派发子任务;tmp 固定名 _children.json.tmp 与 fsutil.py 记录的固定临时名教训同款 | 读码+临时环境实测(测毕清理):monkeypatch os.replace 抛 PermissionError → 静默返回 None(无异常无日志);目录不可写同样吞;_load_children 对缺失文件返回 [](接管者视为无子任务→重复派发);对照组实测裸 os.replace 30/30 抛 WinError 5 佐证 Windows 持锁真实存在。**未做真实磁盘锁注入(不可控),风险路径代码级确证** | 留档(本会话读核 :269-276 现状未变) |
|
|
115
|
+
| N71 | md_cg/mdcos.py:2158 | low | review_decide 的 merge 分支为无互斥的读-改-写(读 target→拼接→写回),多实例并发 merge 同一目标可丢失一方合并内容而两条裁决均记 accepted;FileLock 只罩 decisions.jsonl 追加不罩节点读写窗口 | 临时目录实测(测毕清理):两独立实例 + Barrier 确定性交错并发 merge 同一 target → A 的哑合并载荷丢失(终态只含 B 的)、decisions.jsonl 两条裁决均 accepted——结构上无锁即丢合并实拍;此前 15 轮自然并发未复现(窗口亚毫秒)与 low 定级一致:结构性风险、非高频触发 | 留档(本会话读核 merge 分支现状未变) |
|
|
116
|
+
|
|
117
|
+
### 证据形态修正与如实记录(不动摇结论,2 处)
|
|
118
|
+
|
|
119
|
+
1. **N61 泄漏通道修正**(auth 区复核自纠):原证据「模块顶部普通 `#` 注释进图」实测**不成立**(节点判『无注释』);实际进 content 的三条通道为**模块 docstring、函数/类定义上方的前置注释、签名**,及 index_doc 的 **md 章节摘要首段**(受截断)——敏感内容经这三条通道确实进图且 guest 可读,核心结论不变。
|
|
120
|
+
2. **N64 子例证修正**(inject 区复核自纠):原子例证 'ⁱ'(isalpha 但非 XID)实测产物**可** compile(CPython 标识符 NFKC 归一兜底),该子例不成立;但 ASCII 关键字(class/import/lambda)在两处漏挂位置均实测成立,核心结论不变。
|
|
121
|
+
|
|
122
|
+
另如实声明:legacy 区 8 项的「本轮实跑复现」为上游复核会话执行(材料原文);批次 37 声称已修未落盘的 git 取证(03ae053 对 verify_runner.py 无 diff、对 wm.py 仅 +4 行)亦为材料给定,本报告会话未重跑 git 考古、只对现行代码做了读核确认(防御确实不在位 → 重开正当)。
|
|
123
|
+
|
|
124
|
+
---
|
|
125
|
+
|
|
126
|
+
## 四、验证(门禁结果)
|
|
127
|
+
|
|
128
|
+
以下「本报告会话实跑」均为本报告写作会话在仓库根目录实际运行(第一手);「材料口径」为编排/修复会话已跑、本会话未重跑(如实区分):
|
|
129
|
+
|
|
130
|
+
| 命令 | 结果 | 来源 |
|
|
131
|
+
|------|------|------|
|
|
132
|
+
| `python scripts/run_tests.py --jobs 4`(全量) | `===== SUMMARY 174/174 通过,5 跳过(依赖缺失/平台不符) =====`(尾部 PASS 含 hive.test_wm_progress / hive.test_exec_tools / swarm.tests.test_rust_swarm,与材料逐字一致;174 = v7 基线 172 + 本轮两个新守卫套件 compiler/tests/test_lexer_v3n6.py 与 md_cg/test_p1x_ref_root.py 自动发现入列;材料口径退出码 0,本会话因管道 tail 未捕获退出码——如实注明) | **本会话实跑** |
|
|
133
|
+
| `python -X utf8 compiler/tests/test_lexer_v3n6.py` | `=== v3 N6 词法定向断开回归: 15/15 通过 ===` | **本会话实跑** |
|
|
134
|
+
| `python -X utf8 -m md_cg.test_p1x_ref_root` | `P1-X 根白名单守卫: 10/10 通过` | **本会话实跑** |
|
|
135
|
+
| `python -X utf8 -m md_cg.test_p39_verify_flow` | `=== verify flow tests: 11 passed, 0 failed ===`(含新 2e/2f) | **本会话实跑** |
|
|
136
|
+
| `python -X utf8 hive/test_wm_progress.py` | `结果:PASS=49 FAIL=0`(含新 G1-G5) | **本会话实跑** |
|
|
137
|
+
| `python -X utf8 hive/test_exec_tools.py` | `结果:87 通过 / 0 失败`(含新 K1/K2) | **本会话实跑** |
|
|
138
|
+
| `python scripts/check_publish_artifact.py`(`npm run gate` 第 2 环单独复现) | R1 凭据/密钥面 PASS(文件面=0 内容面=0)、R2 私有数据面 PASS、R3 隐私文本 PASS;**R4 非追踪件面 FAIL 命中=1;非追踪=25,允许=24——命中恰为 md_cg/test_p1x_ref_root.py**;`VERDICT=FAIL`——与材料门禁输出同因同置 | **本会话实跑** |
|
|
139
|
+
| `npm run gate`(全链六环) | 材料口径 FAIL(R4 时序性:新守卫文件尚未 git add 登记追踪面);本会话未重跑全链、仅单独复现 R4 环(上 row)——处置:按守卫自身要求 `git add` 登记后复跑即过(v7 先例),**归编排会话提交前裁决,本报告会话未擅自登记/提交** | 材料 + 本会话部分复现 |
|
|
140
|
+
| `cargo test` | **未运行**——Rust 面零改动(`git status` 证实改动面为 compiler/ hive/ md_cg/ scripts/ docs/ 与两个新守卫文件,rust/ 与 swarm/rust_runtime/ 未动) | 双方一致 |
|
|
141
|
+
| `npm test` | **未运行**——TS 面零改动(src/ 与 test/ 未动;遗留 N63/N65/N66 的 TS 文件本轮只读核未改) | 双方一致 |
|
|
142
|
+
|
|
143
|
+
**上游会话已运行、本会话未重跑的验证**(材料原文,如实区分):五项修复的临时攻击复现守卫(修复前红态:F1 六项红→14/14、F2 五项红→10/10、F3/F4/F5 同脚本修复前后各一跑);F2 的 `git stash` 回退对照(旧码下永久守卫 5/10);`verify_linux.sh` 同口径 python suites 41 套(清单 40 + 新守卫)pass=41 fail=0;gate 四段 cogmap/link/wsidx/disc 全 0(F2 中途 cogmap 曾 =1——插入代码致 README 锚点行号漂移,跑 cogmap_sync build 写回标记段后归零,README 用户未提交文案改动保留段外,如实记录);hive/scripts 四入口(orch/et/se/jm)全 0;compiler/tests 全部 9 文件逐一 OK;F3 的 `python -m md_cg.test_interop_judgment` 31/0;F5 全量首跑 173/174(md_cg.test_review_conformance 单套偶发失败→单独复跑 38/0、全量再跑 174/174,该套件不在 hive/exec.py 依赖链上,判定偶发非回归——如实报告)。
|
|
144
|
+
|
|
145
|
+
**git 工作树核对**(本会话 `git status`/`git diff --stat`):改动 12 文件——五个修复补丁(compiler/lexer.py +15、md_cg/mcp_server.py +20、hive/verify_runner.py +21/-3、hive/wm.py +37/-10、hive/exec.py +28/-2)+ 守卫四处(md_cg/test_p39_verify_flow.py +27、hive/test_wm_progress.py +23、hive/test_exec_tools.py +47)+ 两个新守卫文件(compiler/tests/test_lexer_v3n6.py、md_cg/test_p1x_ref_root.py,untracked)+ cogmap 同步两文件(README.md、docs/mdcg/功能调用映射表_v0.1.md)+ scripts/verify_linux.sh(注册新守卫)+ md_cg/whitebox_kb/wisdom/code_solidified.json(先前会话改动,与本轮修复无关)——与五项修复一一对应,无多余改动面。未做任何 commit。
|
|
146
|
+
|
|
147
|
+
---
|
|
148
|
+
|
|
149
|
+
## 五、遗留清单(14 项:medium 10 / low 4)
|
|
150
|
+
|
|
151
|
+
### medium(10 项)
|
|
152
|
+
|
|
153
|
+
| # | where(现行,本会话读核) | 问题 | 留档理由 / 处置线索(材料口径) |
|
|
154
|
+
|---|------|------|------------------------------|
|
|
155
|
+
| v2 N16 | hive/hive_mcp/mcp_server.py:566 | 非 dict JSON 形态(批量数组/str/int)一行打崩 MCP server 常驻进程(DoS) | 材料明示:修复面小(_rpc 入口加 isinstance(req, dict) 守卫),**竞争第 5 席败于 exec.py:103(三报告命中+模板在位)**;本轮仅读码核实未独立复现 |
|
|
156
|
+
| v6 N38 | src/lib/token_store.ts:76 | auxRoot 波浪线/相对路径形态 node 与 python 分居两处 → 重复自动签发永不吊销的 designer 令牌 | 材料未附分诊注;影响面为采用波浪线/相对 MDCG_AUX_ROOT 的沙箱/多用户部署 |
|
|
157
|
+
| v5 N24 | swarm/swarm_cli.py:78 | CLI 静默丢弃 swarm.json 的 condition_space 声明(G-R2 卡不生效) | 材料未附分诊注;修法明确(实参表补一项透传),库层支持完整、仅 CLI 缺口 |
|
|
158
|
+
| v2 N7 | hive/exec.py:1541(缺陷时点 :1517) | call_llm 单发路径缺 _empty_turn 防护:空回包记 ok=true 假成功 | 材料未附分诊注;_empty_turn 与工具路径防护模板均在位(:1224/:1372),单发分支补对称防护即可 |
|
|
159
|
+
| N62 | md_cg/tokens.py:410 + mcp_server.py:3448 | 租户绑定被 env 覆盖 + clearance_cap 夹紧从未接线(多租户密级上限失效) | 材料明示:多租户接线方案涉及授权链语义设计,超出本轮低风险修复范围;_resolve_root 冲突 fail-closed 为一层缓解 |
|
|
160
|
+
| N64 | compiler/codegen.py:390(同族 :490-491) | 赋值目标/裸标识符表达式漏挂 _py_name → ASCII 关键字假成功(终裁橡皮图章) | 材料未附分诊注;函数名闸模板在位(:525),两处补对称校验即可 |
|
|
161
|
+
| N66 | src/lib/roleplay_web.ts:829-891 | /roleplay/api/chat 无 CSRF 防护(跨站静默写转录 + 记忆投毒 + 计费触发) | 材料明示:修复需引入 Origin 校验策略(涉及合法跨源接入面决策),超出低风险范畴;写类端点 x-edit-key 闸在位可参照 |
|
|
162
|
+
| N67 | hive/wm.py:253(材料缺陷时点 :236) | cmd_progress --job-id 无路径段校验:穿越读 wm 仓外 JSONL 全文回显 | **留档材料的处置建议(与 F4 同 patch 顺带挂 _valid_job_id 式闸约三行)本轮未被采纳**——F4 修复面只含 try/finally,如实记录;模板 hive_mcp/mcp_server.py:100-111 在位 |
|
|
163
|
+
| N68 | hive/orch.py:417 | _spawn 白名单键透传 mdcg_root:不可信 LLM 控制认知图落点(任意目录建文件+内容注入) | 材料未附分诊注;.md 节点直写需 audit ACCEPT 为一层缓解,schema 未声明该键降低常态可达性 |
|
|
164
|
+
| N69 | hive/orch.py:417(通道 :408-411) | context_files 绕过 read_file 全部敏感文件防线:凭据类文件全文进 LLM 上下文发往外部网关 | 材料未附分诊注;read_file 三道防线(scope_roots/_sensitive_read/PII 脱敏)模板在位,通道侧补同款检查即可 |
|
|
165
|
+
|
|
166
|
+
### low(4 项)
|
|
167
|
+
|
|
168
|
+
| # | where(现行) | 问题 | 留档理由 / 处置线索 |
|
|
169
|
+
|---|------|------|---------------------|
|
|
170
|
+
| N63 | src/lib/token_store.ts:97-105 | writeKeyring 直写非原子:首启中断留半截令牌 → 后续激活 fail-closed 拒启(可用性,非越权) | 影响为记忆写通道瘫痪直至手工删密钥环;python 侧同款纪律模板(_write_secret/TenantRegistry._save)在位;TS 侧复现受无运行环境所限(读码证据) |
|
|
171
|
+
| N65 | src/lib/roleplay_web.ts:745(同族 :952-960) | import URL 段与 role_create body 的 role_id 不做 validRoleId 白名单:任意键直落 _roles.json 并透传外部后端 | /meta 与 /chat 的白名单+400 模板在位(:804/:845),两处补对称校验即可;readRoleMeta 空原型与 mdcg node_id 白名单两层缓解在位 |
|
|
172
|
+
| N70 | hive/orch.py:269 | _save_children 静默吞写盘失败 → children 清单丢失 → 接管者重复派发 | fsutil.py 的短重试+唯一临时名模板在位;未做真实磁盘锁注入(不可控),风险路径代码级确证 |
|
|
173
|
+
| N71 | md_cg/mdcos.py:2158 | review_decide merge 分支读-改-写无互斥:并发 merge 同目标丢一方内容而双裁决 accepted | 结构性风险、非高频触发(自然并发 15 轮未复现、Barrier 确定性交错实拍);修复需节点级写锁设计 |
|
|
174
|
+
|
|
175
|
+
**优先级建议**(据材料处置线索汇总):v2 N16(修复面最小+DoS 面)与 N67(三行模板在位)为下轮速收候选;N64/N65 为「模板在位补对称校验」类低风险项;v2 N7 假成功与 N69 凭据外发面建议同轮处置(同属「结果/上下文诚实性」);N62 多租户接线与 N66 CSRF 策略需先做接入面设计决策再动代码。
|
|
176
|
+
|
|
177
|
+
---
|
|
178
|
+
|
|
179
|
+
## 六、纪律合规声明
|
|
180
|
+
|
|
181
|
+
1. **定位先读索引**:本报告写作前已读 WORKSPACE_INDEX.md(按职责定位 docs/eval 为报告归域、hive/ 为蜂巢并发引擎、md_cg/ 为记忆系统本体、compiler/ 为编译器、src/ 为 TS 插件源码),未做全盘浏览。
|
|
182
|
+
2. **结论引证**:所有修复与缺陷均引 path:line(缺陷时点快照行号,本轮三文件行号漂移处另注现行行号并经本会话读核);第三节证据要点摘自任务输入的四区复核材料(上游会话读码+实跑,环境细节按仓库口径转录);第四节「本会话实跑」七项为第一手命令与输出原文,材料口径与未跑项(cargo/npm test/gate 全链/git 考古/攻击复现重跑)均如实标注来源,无一冒充。
|
|
183
|
+
3. **修复落盘核验**:五项修复的现行代码本报告会话逐处读核(lexer.py:393-394 既有集合+ :396-410 定向断开、mcp_server.py:2280/:2316/:2902-2906 三闸 + verify_linux.sh 注册、verify_runner.py:102-106 白名单、wm.py:174-190 try/finally、exec.py:116-129 原子写+重试环),14 项遗留的现行现状亦逐一 grep/读核确认(第五节「现行」列),git 工作树改动面与五项修复一一对应。
|
|
184
|
+
4. **安全测试纪律**:材料中全部攻击复现均在系统临时区/同盘仓库外临时目录/临时子进程,使用哑令牌与哑数据(本报告以「哑样例」占位描述,不复写字面量),不触真实数据目录与真实令牌,不触真实网关/密钥外发,测毕清理(材料逐项声明);本报告会话只运行守卫套件与门禁检查器,未做任何攻击复现。
|
|
185
|
+
5. **已修项不重复报**:本轮 8 项 legacy 中 v2 N5/N11 与 v2 N10 经 git 取证证实批次 37 声称已修未落盘(材料给定;本会话读核现行代码防御确实不在位),属重开非重复;#34 AccessDenied hint、#35 会话隔离三层、#37 互验六项、V21 安全审计系列、第 7 轮性能修复均已落盘,本报告未再报。
|
|
186
|
+
6. **隐私脱敏**:全文只写仓库相对路径;材料的本机绝对路径(盘符/用户目录/临时区路径)一律转录为「系统临时区/仓库外同盘临时目录」;哑令牌/哑密钥/哑密码样例一律以占位描述(「哑样例密钥」「哑密文标记」「模型可控哑正文」等),无任何 key/token 字面量;环境变量名与标识符(MDCG_INGEST_ROOT/HIVE_ROLE 等)为源码标识符非凭据值,为证据必需而保留;定稿前经机械扫描复查(见下方自查)。
|
|
187
|
+
|
|
188
|
+
---
|
|
189
|
+
|
|
190
|
+
## 七、跳过项及原因
|
|
191
|
+
|
|
192
|
+
- **cargo test 未运行**:Rust 面零改动(本会话 git status 证实 rust/ 与 swarm/rust_runtime/ 未动,F3-F5 修复会话亦声明无 Rust 改动、cargo 不适用)。
|
|
193
|
+
- **npm test 未运行**:TS 面零改动(src/ 未动;N63/N65/N66 仅读核留档)。
|
|
194
|
+
- **`npm run gate` 全链未于本会话重跑**:材料口径 R4 时序性 FAIL(新守卫 md_cg/test_p1x_ref_root.py untracked、非追踪=25>允许=24);本会话以第 2 环 check_publish_artifact 单独复现同因同置(R1/R2/R3 PASS)——按守卫自身要求 `git add` 登记后复跑即过(v7 先例),**处置归编排会话提交前裁决,本会话未擅自登记或提交**。
|
|
195
|
+
- **TS 侧中断注入复现未运行**(N63):无 TS 运行环境——材料如实标注为读码证据;python 侧影响链已实测。
|
|
196
|
+
- **浏览器端到端 CSRF 未实测**(N66):本机无 Cordis 宿主,webServer 实际监听地址属宿主行为(仓库内无该配置);已实测 mock 服务端形态(text/plain 简单请求直达 + 伪造 Origin 照常处理),跨站「简单请求无预检」为 web 平台标准语义。
|
|
197
|
+
- **真实磁盘锁注入未做**(N70):不可控环境注入,以 monkeypatch 确定性证明 + 对照组裸 os.replace 30/30 WinError 5 佐证。
|
|
198
|
+
- **凭据外发未实测**(N69):不触真实网关/密钥,以 build_messages 侧全文进 messages 实拍 + read_file 双通道对照实拍为界。
|
|
199
|
+
- **ref action=check/prune 巡检分支未挂闸**(F2 范围声明):读图内登记 ref(非 inline 模型可控),按报告修复范围只覆盖 read/get 分支与两索引显式 path,未扩大。
|
|
200
|
+
- **md_cg/whitebox_kb/wisdom/test_navigate_self_bootstrap.py 直跑失败**(F1 验证中途处置):ModuleNotFoundError(缺 aeis_core 依赖)——git stash 仅回退 lexer.py 对照,旧代码同败,为预存环境问题(该文件不在 verify_linux.sh 清单内),与本次改动无关,如实报告。
|
|
201
|
+
- **git 未提交**:commit 需任务方指令;工作树保持五补丁+守卫+cogmap 同步原状。
|
|
202
|
+
|
|
203
|
+
---
|
|
204
|
+
|
|
205
|
+
*报告依据:任务输入的第 8 轮材料(四区复核 22 条确认明细及证据、五项修复的 where/攻击前后对比/守卫/verified_by、留档 15 条中 1 条被 F2 顺带覆盖、门禁结果);本报告会话的修复落盘读核(lexer/mcp_server/verify_runner/wm/exec 五补丁锚点 + 三闸 + verify_linux.sh 注册 + 守卫段落 2e/2f、[G]、[K])、14 项遗留现行读核(第五节「现行」列)、五套守卫实跑(15/15、10/10、11/0、49/0、87/0)、全量回归实跑(174/174)、R4 门禁单独复现(FAIL 同因同置)、git 工作树核对、报告脱敏机械扫描。*
|
|
206
|
+
|
|
207
|
+
*自查双清单:①材料覆盖——四区 22 条目全部入文(legacy 8 / auth 4 / inject 4 / fs 6),0 证伪如实记录,证据形态修正 2 处单列,5 补丁 6 缺陷逐项五要素齐全,留档 15−1(N61 并入 F2)=14 与第五节数目吻合,门禁四项(python/cargo/npm test/gate)与跳过原因一一对应;②纪律——全部结论引 path:line 或注明材料来源,八项第一手实跑命令与输出原文在第四节,未跑项(cargo/npm test/gate 全链/git 考古/攻击复现)无一冒充为已跑,全文无本机绝对路径、无 key/token 字面量(机械扫描盘符/用户目录/token 形态零命中)。*
|
|
@@ -0,0 +1,203 @@
|
|
|
1
|
+
# 缺陷挖掘报告 · 自主迭代 v9(md_cg 二轮深挖)
|
|
2
|
+
|
|
3
|
+
- **日期**:2026-09-25
|
|
4
|
+
- **范围**(生效条件):第 9 轮 = md_cg 二轮深挖,四区复核(recent / retrieval / write / legacy)共 **22 条目**(confirmed 19 / 整项剔除 3)→ 去重后独立缺陷 **16**(本轮新发现 10 项 **N72-N81**:high 1 / medium 6 / low 3;legacy 复测确认 6 项:v8 N62 medium,v8 N71、v7 N51、v7 N52、v7 N50 残腿、v7 负层残余均 low)→ 本轮修复 **5 个补丁覆盖 5 个新缺陷**(N72-N76:high 1 / medium 4)→ 遗留 **11**(medium 3 / low 8)+留档清单中 2 条占位去重说明(跨区重复条目,不承载独立缺陷)
|
|
5
|
+
- **编号口径**:本轮新发现沿历轮 N 口径续编 **N72-N81**(v8 用至 N71);legacy 项沿用原轮次号(v7 N50/N51/N52、v8 N62/N71)
|
|
6
|
+
- **第 7 轮留档两项复测结论**(任务点名显式记录,详见第三节末专节):①**负层全读每查询磁盘 IO**——IO 已被第 7 轮读缓存默认化覆盖,残余为 `_emit` 尾部裸 open ×3 与 `scanned` 审计口径盲区(留档);②**四路召回重复读盘(v7 N50)**——`_read` 系四腿已全部覆盖(稳态增量 0),唯一残腿为 `_path_graph` 种子经 `MdCG.get` 裸 open 恒 ≤5 次(留档);N50 原「同节点重复 open+parse 税」形态经对照实跑**证伪剔除**(见 rejected)
|
|
7
|
+
- **回归**:`python scripts/run_tests.py --jobs 4` 全量 **179/179 通过、5 跳过(依赖缺失/平台不符)、退出码 0**(**本报告会话独立实跑,SUMMARY 行与材料逐字一致**;179 = v8 基线 174 + 本轮 5 个新守卫套件);`cargo test` **未运行**(Rust 面零改动);`npm test` **未运行**(TS 面零改动);`npm run gate` **FAIL——R4 非追踪件面命中恰为本轮 5 个新守卫文件**(未 `git add` 的时序性失败;本会话以第 2 环 `scripts/check_publish_artifact.py` 单独复现同因同置,R1/R2/R3 全 PASS),处置归编排会话提交前裁决(v7/v8 先例)
|
|
8
|
+
- **行号口径**:缺陷行号为缺陷时点快照行号;本轮修复使 `mdcg.py`(:3171 起 +7 行)与 `mdcos.py`(缓存段 +34 行净增,其后行号整体下移)漂移,涉及处本会话另注**现行行号**(均已逐一读核,见第五节「现行」列)
|
|
9
|
+
- **结构口径**(CCG 六要素):功能名(标题)/ 生效条件(范围与口径行)/ 子功能(第二~五节)/ 执行与验证方式(第四节:实跑命令与结果)/ 不适用条件(第七节:跳过与未运行项)
|
|
10
|
+
|
|
11
|
+
---
|
|
12
|
+
|
|
13
|
+
## 一、执行摘要
|
|
14
|
+
|
|
15
|
+
本轮为 md_cg 二轮深挖:四区复核 22 条目、3 项整项剔除(含对 v7 留档两项的复测定谳),修复 5 补丁、留档 11 项。四个主题:
|
|
16
|
+
|
|
17
|
+
1. **第 7 轮读缓存默认化的「治理写前重查」盲区(N72,high,1 修)**:第 7 轮把读缓存改为默认开(28.3×)时,只为 backfill 15 处与 mreview.govern 3 处装配了 `direct_read` 穿透直读,而 consolidate / ccgc / crosscheck / vision_evidence 四文件的治理写面共 **14 处读-改-写读点仍走缓存版 `cg._read`**——常驻进程「检索装载缓存 → 另一进程经统一写口落盘修正 → 同实例执行治理写」的时序真实可达,B 的修正被 A 进程内陈旧代际缓存**静默覆盖丢失**(以真实函数 `ccgc.recalibrate` 复现:默认开组 B 修正幸存=False,`MDCG_READ_CACHE=0` 对照组幸存=True——丢失由默认开引入属实)。本轮 14 处全部改 `direct_read`(与第 7 轮同口径)。
|
|
18
|
+
2. **「落盘了但对账面不可见」三连(3 修,同族缺陷)**:N75——`verify()` 在节点已在目标验证态时的直写分支落盘后不置 `_dirty`,索引增量日志与读缓存代际双双看不见本次写盘(重开后索引 evidence_count 与盘面漂移、同实例 `_read` 命中旧 frontmatter);N74——`discard` 摘除分支索引只 pop 内存不落 tombstone,close 时 compact 的「计数对账重扫+日志重放」把已物理移走节点的 upsert 叠回,**幽灵条目被固化进 _index.json 快照永久存活**;N73——审核队列四增量对账缓存的水位存「读前 stat 的 size」而 `read_jsonl_tail` 读到真实 EOF,stat→read 窗口内的跨进程 append 在下一轮被**重复并入且进程内永不自愈**(review_list 重复 pid、review_stats 虚高)。三者同属「写盘生效、但对增量日志 / 缓存代际 / 快照对账不可见」家族。
|
|
19
|
+
3. **连接层 RMW 无互斥 + 固定临时名(N76,1 修)**:links 全部变更原语(handshake/observe/promote/degrade/isolate/withdraw/decay_all)是 load→改内存→save 的读-改-写,无任何跨进程锁,且 save 用固定临时名 `p+".tmp"`(`fsutil.py` 头部明载的已实名反模式)——并发下后写者整文件覆盖前写者(**20/20 静默丢一方信任更新**)、两写者互踩同一 .tmp 产生内容交织(audit 超单写者合法上限实拍)、`_publish` 只捕 PermissionError 致 rename 被抢先时抛 FileNotFoundError。本轮改 `atomic_write` + `_locked` 连接级全程互斥。
|
|
20
|
+
4. **留档复测与证伪(如实记录)**:**第 7 轮留档两项复测结论显式定谳**(页首口径行 + 第三节末专节);v8 N71(merge 无互斥)三区独立复测全部成立、维持留档不重报(确定性交错:双 ok=True 而一方合并载荷丢失;与本轮 N72 相互独立——merge 基底走 `self.get` 直读盘无缓存陈旧成分,纯无互斥竞态);v8 N62 / v7 N51 / v7 N52 复测维持;两项整项剔除(v7 N50 原「重复 open+parse 税」形态已被第 7 轮读缓存默认开消除;负层「每查询全量 open+parse」已被覆盖,残留仅口径 nit 非缺陷级)。
|
|
21
|
+
|
|
22
|
+
**对输入口径的核验**:输入称「四区 19 confirmed + 3 rejected = 22 条目 → 去重 16 独立缺陷 → 修 5 → 留档 11 + 2 占位」。本会话以 `git status` / `git diff --stat` + 逐处读核核对:改动面恰为——九个修复文件(consolidate.py +13、ccgc.py +5、crosscheck.py +7、vision_evidence.py +7、mdcg.py +7、branches.py +16、fsutil.py +33/-15、mdcos.py +71/-37、links.py 245 行改写)+ `scripts/verify_linux.sh`(+3 行注册 5 个新守卫,现行 :21-23)+ 五个新守卫文件(untracked)——与五项修复一一对应;工作树另有三件非本轮修复的改动如实注明(见第四节 git 核对)。16 − 5 = 11 留档,无多无少。
|
|
23
|
+
|
|
24
|
+
---
|
|
25
|
+
|
|
26
|
+
## 二、修复清单(5 项,逐项 where / 问题 / 修复 / 前后对比 / 守卫)
|
|
27
|
+
|
|
28
|
+
### F1(N72,high)治理写面 14 处读点改 direct_read:读缓存默认开下另进程修正不再被静默覆盖
|
|
29
|
+
|
|
30
|
+
- **where**:`md_cg/readcache.py:57-97`(install 默认开、包装 `cg._read` 为脏代际缓存)× 四文件治理写面 14 处读点——缺陷时点 consolidate.py:678/814/894/965/1067/1125、ccgc.py:757/841、crosscheck.py:344/786/941、vision_evidence.py:296/495/579;修复落点(现行,本会话 grep 逐一读核 14 处 + 4 行 import 全在位)consolidate.py:679/815/895/966/1068/1126、ccgc.py:758/842、crosscheck.py:345/787/942、vision_evidence.py:297/496/580
|
|
31
|
+
- **问题**:第 7 轮读缓存默认化只覆盖了 backfill(15 处)与 mreview.govern(3 处)的写前重查面;四文件治理写面(consolidate 主流/验证基底回填/晋升及回滚/上下文化及回滚、ccgc link/recalibrate、crosscheck 扫描/主流程写前重查/回滚、vision_evidence 收集/执行/回滚)读-改-写读点仍走缓存版 `cg._read`——写前重查/回滚比对命中旧代际缓存即写回陈旧 frontmatter/content,跨进程合作写者的修正被静默覆盖。`readcache.py:24-25` 的「跨进程改写不保证可见」诚实边界**不覆盖本形态**:B 是全合作写者(走 `_write_node` 统一写口、durable=True 落盘),且第 7 轮已为同语义面装 direct_read,治理写前重查不在豁免范围。crosscheck.rollback 的 write_id 防护所验 fm 本身出自缓存,不构成防护。
|
|
32
|
+
- **修复**(最小改动:14 处 `cg._read(e)`/`_cg._read(entry)` → `direct_read(cg, e)`/`direct_read(_cg, entry)`,四文件各加一行 `from .readcache import direct_read`):穿透缓存直读盘上真值,与第 7 轮 backfill/govern 同口径;未动 readcache.py 本体与任何写路径。
|
|
33
|
+
- **前后对比**(守卫实测,临时库测毕清理):前——A 常驻实例检索装载缓存 → B 另一实例以 `_write_node(durable=True)` 落盘「重要修正」→ A 执行治理写(recalibrate/link/crosscheck/vision_evidence)时写前重查命中旧代际缓存,B 修正被静默覆盖(旧代码守卫 6 红:recalibrate 即缺陷报告原样复现幸存=False;`MDCG_READ_CACHE=0` 对照组同流程幸存=True,证实丢失由默认开缓存引入)。后——14 处读点全部走 direct_read 穿透读,B 修正幸存=True 且 A 自身治理写入照常生效,同一守卫 40/40 全绿;检索读面(search/_read_many)缓存行为零变化。
|
|
34
|
+
- **守卫**:新增 `md_cg/test_govern_directread.py`——红守卫=缺陷指定口径的 recalibrate 双实例复现(G1,含缓存关对照组 G1e)+ 同形态覆盖 ccgc.link / crosscheck 主流程与回滚 / vision_evidence 执行与回滚(G2-G6,旧代码确定性红);G7-G12 为 consolidate 六读点口径守卫(root 入口内部自建新实例、单次调用首触即盘上真值,断言为「B 修正幸存且流程不回归」,修前修后均绿、非红证明——守卫文件头已如实注明)。执行轨迹:修前 PASS 34 / FAIL 6(G1c/G2d/G3b/G4b/G5b/G6b)→ 修后 PASS 40 / FAIL 0。已注册 `scripts/verify_linux.sh`(现行 :21-23)。**本会话实跑:PASS 40 / FAIL 0**。
|
|
35
|
+
|
|
36
|
+
### F2(N75,medium)verify() 直写分支显式置 _dirty:noop 形态写盘对索引与缓存可见
|
|
37
|
+
|
|
38
|
+
- **where**:缺陷时点 `md_cg/mdcg.py:3166-3170`(confirmed/weakened 直写分支落盘后只原地改 index 条目 `e["evidence_count"]`);修复落点现行 `md_cg/mdcg.py:3171-3177`(注释 5 行 + 修复行 `self._dirty[node_id] = e`——材料口径 :3175,**本会话读核实为现行 :3177**)
|
|
39
|
+
- **问题**:节点已在目标验证态(verified→verified / doubted→doubted)时,verify 尾部 `set_verification` 走 stamp noop 提前返回(trust.py:192-193/695-696,不写盘不调 `_sync_index` 标脏),本次直写落盘对索引增量日志**完全不可见**——重开后索引 evidence_count/confidence 与盘面漂移(forgetting.py:358、scrub.py:181/582/716、metacognition.py:176/193 均按索引条目 evidence_count 做决策即拿旧值),且 readcache 代际不推进、同实例 `_read` 返回旧 frontmatter。
|
|
40
|
+
- **修复**(一行 + 注释):直写分支落盘并原地更新 `e["evidence_count"]` 后显式 `self._dirty[node_id] = e`——`_DirtyDict.__setitem__` 使 write_gen 单调自增(mdcg.py:805-811)→ ① readcache 代际哨兵失效(同实例 `_read` 不再命中旧 frontmatter)② `_dirty` → flush/close → `_index_log`/compact 快照可见本次写盘。口径与既有 `_sync_edge_entry`(:1664)/ goal 状态写回(:1962)相同;不走 `_stage`(对已存在条目会重复计桶)。未动 trust.py 的 noop 幂等语义(语义锁断言见守卫)。
|
|
41
|
+
- **前后对比**(守卫实测,临时库测毕清理):前——noop 形态 verify 落盘后 write_gen 0→0、_dirty 不含节点、同实例 `_read` 缓存视图 evidence_count=0 vs 盘面 1、close 重开后索引 0 / 盘面 1 漂移固化(compact 计数对账只对账 .md 数量,内容级改写不触发重扫,mdcg.py:1003)。后——write_gen 推进、节点标脏入增量日志、缓存视图即读盘上真值(=1)、重开后索引与盘面对账一致(均 1);noop 幂等语义与 verify 返回载荷形态不变,置信度步长(+0.05/−0.15)与降级门槛行为不变。
|
|
42
|
+
- **守卫**:新增 `md_cg/test_verify_dirty_reconcile.py`——三段会话(S1 预置验证态并 close 落快照 → S2 noop 形态 verify → S3 close 重开对账);红项 8 个(cf3-cf6/wk3-wk6:写代际不推进/未标脏/缓存视图陈旧/重开索引漂移),语义锁 10 项(noop code/changed=False、返回载荷、置信度、验证态保持、未误降级)修前修后均绿。实现过程一次修正如实注明:初版单会话双 verify 的重开对账项被 close() 无快照时的 rebuild 全量扫描兜底掩蔽,改为「先有快照再 noop 会话」三段形态即如实见红。修前 PASS 10 / FAIL 8 → 修后 PASS 18 / FAIL 0。已注册 verify_linux.sh。**本会话实跑:PASS 18 / FAIL 0**。
|
|
43
|
+
|
|
44
|
+
### F3(N74,medium)discard 摘索引走 _unstage 落 tombstone:幽灵条目不再固化进快照
|
|
45
|
+
|
|
46
|
+
- **where**:缺陷时点 `md_cg/branches.py:261`(单行 `(cg.index.get("nodes") or {}).pop(nid, None)`);修复落点现行 `md_cg/branches.py:261-276`(本会话读核:`_unstage` 调用 + 防御式回落 + 注释在位)
|
|
47
|
+
- **问题**:discard 摘除分支索引只 pop 内存、不写删除记录(未走 `_unstage`),且其内部 flush(branches.py:262-267 缺陷时点)把 fork 阶段仍在 `_dirty` 的分支条目作为 **upsert 持久化**进 `_index_log`;close 时 compact 的计数对账(盘面 .md 数 2 ≠ 索引节点数 3)触发重扫,`_apply_log(self._scan_nodes())`(mdcg.py:1010-1012)把已物理移走(publish 至 `_branches/br1/`)的分支 upsert **叠回干净扫描之上**——幽灵条目连同目录指纹固化进 `_index.json` 快照,此后重开指纹校验放行、幽灵永久存活(get()=None、检索候选白跑、dangling 不归零)。对照正确实现:forget 移文件后调 `_unstage` 落删除记录(mdcos.py forget 注释明载同构坑)。
|
|
48
|
+
- **修复**(最小改动):摘除改走 `cg._unstage(nid)`(getattr 防御式获取,异常/不可用时回落原 pop,鸭型 cg 兼容)——`_unstage`(mdcg.py:1971-1989,本会话读核)= pop 内存 + 桶计数减一 + `_dirty[nid]=None`(tombstone)+ 立即 flush,与 forget 的正确模式同口径。修复后时序:fork 阶段 upsert 被 tombstone 覆盖(重放按序 pop)→ discard 尾部 flush 只落 branch_summary 等合法 upsert → close 的 compact 不再把幽灵叠回。未动 discard 其余语义(必填标记校验/权限/冷归档/审计)。
|
|
49
|
+
- **前后对比**(守卫实测,临时库测毕清理):前——discard 返回时 `_index_log=[('mem_base@br1','upsert'),('branch_summary_br1','upsert')]`,close 重开后索引节点含幽灵 `mem_base@br1`(get=None)。后——discard 返回时日志含该 nid 的删除记录(tombstone),重开后索引节点=['branch_summary_br1','mem_base'],索引与盘面 .md 集合对账一致,主支与教训节点完好可读,分支文件冷归档物理保留,返回载荷形态不变。
|
|
50
|
+
- **守卫**:新增 `md_cg/test_branch_discard_tombstone.py`——三段(主支入库落快照 → fork→discard(fork 后不 flush,忠实保留前置)→ close 重开断言);红项 3 个(B2 未落 tombstone / B3 重开后索引含幽灵 / B5 集合对账不一致),语义锁 7 个修前修后均绿。修前 PASS 7 / FAIL 3 → 修后 PASS 10 / FAIL 0。已注册 verify_linux.sh。**本会话实跑:PASS 10 / FAIL 0**。
|
|
51
|
+
|
|
52
|
+
### F4(N73,medium)read_jsonl_tail 返回真实 EOF + 四缓存水位改存消费位置:尾窗并发 append 不再重复并入
|
|
53
|
+
|
|
54
|
+
- **where**:`md_cg/fsutil.py:227-259`(read_jsonl_tail,现行 def :228,本会话读核)× mdcos 四增量对账缓存(`_pid_status` 现行 :1708、`_inbox_phash_index` :1744、`_inbox_records` :1776、`_decisions_records` :1807;水位行现行 :1739/:1771/:1802/:1833)——缺陷时点四缓存定义 :1708/:1739/:1768/:1793;根因配套缺陷时点 fsutil.py:228(无界 yield 读到 EOF)+ 水位存回 stat 时刻旧值
|
|
55
|
+
- **问题**:四缓存均 stat 先于读、水位存回 **stat 时刻的 size**,而 `read_jsonl_tail` 读到真实 EOF——跨进程 append 恰落在 stat 与 read 之间时,新记录本轮已并入但水位偏小,下一轮增量从旧水位**重读同一条**:列表型缓存(`_inbox_records`/`_decisions_records`)重复并入且**进程内永不自愈**(稳态 size 只增不触发全量重建)→ review_list 待审清单重复 pid、review_stats records/noop 计数虚高翻倍、`_cascade_dedup` 对同一兄弟提案连写两条 reject 裁决(mdcos.py:1982-2001 快照在循环前取、写 decisions 后不刷新——读码推演成立)。write 区同对象条目(缺陷时点 :1786-1789)为同一缺陷,随本修复一并消解。
|
|
56
|
+
- **修复**:① `read_jsonl_tail` 由无界 yield 生成器改为一次性读到 EOF 后返回 `(解析记录列表, offset+读到的字节数)`——end_offset 是真实消费位置(窗口内并发 append 的字节已计入);坏行容错、ends_mid_line 补 \n 语义不变;文件不存在返回 `([], None)`。docstring 明载「读后再 stat 不可取:re-stat 可能大于已消费位置,下轮跳过未读记录(丢账比重复更糟)」。② 四缓存统一:full 路径 `read_jsonl_tail(path, 0)`、增量路径 `read_jsonl_tail(path, 水位)`,水位一律存 end(end 为 None 时回落 stat size),mtime 仍存读前 stat 值。零解析快路径与 size 回退全量重建兜底不变。全库 grep 证实 `read_jsonl_tail` 仅 mdcos.py 一处导入、四处调用——签名变更无其他消费方。
|
|
57
|
+
- **前后对比**(守卫实测,临时库测毕清理;注入法=monkeypatch 拦 mdcos 模块级名字,目标函数被调(=stat 已发生)时先 append 一条再委托原函数,等价真实交错):前——decisions 装载后 stat 前注入 p3、读窗内注入 p4 → 盘上 3 条而 review_stats records=4、noop=4(虚高),第三次调用仍 4(自愈=False);inbox 同窗后 review_list 中同一 pid 出现 2 次;首装全量路径同形翻倍。后——窗口轮 records==盘上且下一轮/第三次调用不变(4==4、3==3)、review_list 无重复 pid、noop 计数与盘上一致;`_pid_status` dict 后写覆盖免疫(proposals==盘上去重 pid 数)语义锁保持。
|
|
58
|
+
- **守卫**:新增 `md_cg/test_tail_watermark_race.py`——四场景(A decisions 尾窗 / B inbox 尾窗 / C dict 覆盖免疫锁 / D 首装全量路径同窗);红项 6 个(A3/A4/A5/B3/B4/D2,旧代码实跑红),A1/A2/B1/B2/C1/D1 基线/窗口轮/免疫锁修前修后均绿。修前 PASS 6 / FAIL 6 → 修后 PASS 12 / FAIL 0。已注册 verify_linux.sh。**本会话实跑:PASS 12 / FAIL 0**。
|
|
59
|
+
|
|
60
|
+
### F5(N76,medium)links save 原子写 + _locked 全程互斥:并发连接变更不再丢更新/撕裂
|
|
61
|
+
|
|
62
|
+
- **where**:缺陷时点 `md_cg/links.py:85-99`(save 固定临时名段);修复落点现行 `md_cg/links.py:85-118`(save 改 `atomic_write` + 新增 `_locked` 上下文管理器,本会话读核)× 六变更原语五处调用点(现行 :333 handshake、:360 observe、:433 `_transition`(覆盖 degrade/isolate/withdraw)、:446 promote、:489 decay_all)
|
|
63
|
+
- **问题**:连接层全部变更是 load→改内存→save 的读-改-写,无任何跨进程锁;save 用固定临时名 `p+".tmp"`(违反 `fsutil.atomic_write` 以 mkstemp 唯一临时名规避的已实名反模式,fsutil.py:6-8 明载「第二写者截断第一写者内容」)——并发下后写者整文件覆盖前写者(**丢一方信任更新,20/20 实证**),两写者互踩同一 .tmp 产生内容交织(audit 超单写者合法上限实拍);`_publish` 只捕 PermissionError,tmp 已被另一写者 rename 走时抛 FileNotFoundError 直接外抛(缺陷报告读码成立、当时未实证,本轮守卫红跑实际触发)。
|
|
64
|
+
- **修复**:① save 废除固定临时名,改走 `fsutil.atomic_write`(mkstemp 唯一临时名、同目录 rename 原子替换、失败清理;POSIX 下 mkstemp 天然 0600 等价旧 chmod 兜底)。② 新增 `_locked`:以 `FileLock(links_file(path))` 为 load→mutate→save 全程连接级互斥(既有基建,锁文件=连接文件+".lock",超时/严格性沿用 FileLock 默认 10s/best-effort——与全库写路径口径一致);五调用点各自包住完整读-改-写段。③ save 不自持锁(FileLock 不可重入,docstring 明载「调用方持锁」口径;外部直接调 save 单次写自身仍原子)。
|
|
65
|
+
- **前后对比**(守卫实测,临时库测毕清理):前——(a)双线程 Barrier 对齐 save 点并发 observe 不同连接,双方都返回 ok=True 而终态一方 evidence_count=0(静默丢更新,20/20 同形);(b)同窗并发下 `_links.json` 内容交织致 load 解析失败两连接全丢,且实拍 publish 抛 FileNotFoundError(WinError 2——读码分支实证);audit 侧互踩可超限。后——两写者 RMW 完全串行(对齐窗自然消失,barrier 3s < FileLock 10s 无死锁);终态两连接 evidence_count 均 1、audit 恰为顺序重放基线、跨原语(observe×degrade)两方效果都幸存、文件恒可解析、固定临时名不再出现;单写者路径行为零变化(序列化格式不变)。
|
|
66
|
+
- **守卫**:新增 `md_cg/test_links_concurrent_write.py`——复现口径=缺陷报告 Barrier 对齐双线程(monkeypatch save 为对齐版,BrokenBarrierError 捕获放行);S1 observe×observe(静默丢更新红项 + audit 顺序重放对照基线 + 固定 .tmp 不再出现)、S2 observe×degrade 跨原语家族。红证跑法:`git stash push -- md_cg/links.py` 后跑守卫 PASS 4 / FAIL 5(含 FileNotFoundError 实拍、撕裂两连接全丢、丢降级),stash pop 还原修复后 PASS 9 / FAIL 0。实现过程一次基线修正如实注明:audit 基线初版硬编码 2 是错的(未声明版本会多记一条),改为顺序重放对照动态测定(=3)。已注册 verify_linux.sh。**本会话实跑:PASS 9 / FAIL 0**。
|
|
67
|
+
|
|
68
|
+
---
|
|
69
|
+
|
|
70
|
+
## 三、发现明细(四区 confirmed 19 / 整项剔除 3)
|
|
71
|
+
|
|
72
|
+
以下每项「证据」为上游复核会话的读码+实跑(材料原文,复现均在临时库/临时环境、测毕清理);标注★者本报告会话另做了现行代码读核。
|
|
73
|
+
|
|
74
|
+
### recent 区(3 confirmed:2 新 + 1 legacy 复测;1 rejected)
|
|
75
|
+
|
|
76
|
+
| # | where(缺陷时点) | 严重度 | 问题摘要 | 证据要点 | 状态 |
|
|
77
|
+
|---|------|--------|----------|----------|------|
|
|
78
|
+
| N72★ | readcache.py:57-97 × consolidate.py:678 等 14 读点 | high | 读缓存默认开后治理写面读-改-写未同步 direct_read(详 F1) | 临时库真实函数复现:A 建节点装载缓存→B 经 `_write_node(durable=True)` 落盘修正→A 执行 recalibrate → 默认开组 B 幸存=False、`MDCG_READ_CACHE=0` 对照组幸存=True;crosscheck.rollback 的 write_id 防护所验 fm 出自缓存不构成防护;读点实为 14 处而非候选所列 7 处 | **已修**(F1) |
|
|
79
|
+
| N73★ | mdcos.py:1708/1739/1768/1793 四缓存 + fsutil.py:228 | medium | 尾部增量缓存水位存读前 stat 旧值致窗口 append 重复并入、进程内永不自愈(详 F4) | monkeypatch 注入 stat→读窗口内并发 append(等价真实交错):盘上 3 条而 records=4、noop=4,第三次调用仍 4;inbox 同窗后 review_list 同 pid 出现 2 次;受损面=review_stats/review_list/审计口径(`_pid_status` dict 后写覆盖不受损) | **已修**(F4;write 区 :1786-1789 条目同对象随修消解) |
|
|
80
|
+
| v8 N71★ | mdcos.py:2157-2173(现行 :2178 读 / :2190 写) | low | 【留档复测·维持 v8 留档不新报】merge 裁决分支无互斥读-改-写仍成立 | 确定性交错复现(monkeypatch MdCGOS.get 在 cg1 首读返回前让 cg2 完整执行 merge):B 先 merge ok=True、A 后 merge ok=True,盘上含甲增量=True 含乙增量=False、decisions 两条均 accepted(双 ok+丢一方);git show 9102df8 证实第 7 轮该分支唯一 hunk 为收尾 upsert 化未加锁。与本轮 N72 独立:merge 基底走 self.get 直读盘(mdcg.py),无缓存陈旧成分,纯无互斥竞态 | 留档维持(见第五节) |
|
|
81
|
+
| ~~v7 N50 形态~~(rejected) | mdcos.py:951/968 | — | **证伪剔除**:N50「同节点重复 open+parse 税」形态已被第 7 轮读缓存默认开消除 | 40 节点临时库(带 tags+edges)连续两次同参 search_rrf:`MDCG_READ_CACHE=0` 对照=87 次节点 open/查询(重复税形态);默认开第 1 次 7 次(装载)、第 2 次 `_read` 面 0 次;稳态残余 5 次全部来自 `_path_graph` 种子 get 直读——盘上真值设计语义、每次查询恒定量与库规模无关。备注:原证据「节点文件 open 降为 0」仅对无边库成立,不改变 rejected 处置 | 剔除(残腿见 v7 N50 残腿条目) |
|
|
82
|
+
|
|
83
|
+
### retrieval 区(6 confirmed:4 新 + 2 legacy 复测;0 rejected)
|
|
84
|
+
|
|
85
|
+
| # | where(缺陷时点) | 严重度 | 问题摘要 | 证据要点 | 状态 |
|
|
86
|
+
|---|------|--------|----------|----------|------|
|
|
87
|
+
| N77★ | writepipe.py:436-437(全仓唯一失效点);mdcos.py:1264/1407(query 缓存读写);mdcg.py:1196-1580(add 无失效) | medium | query 热缓存失效缺口:直接写 API(add / review_decide 的 accept·edit·merge)全部不失效——`MDCG_HOTCACHE=1` 下写后 ≤300s 内 search_rrf(含生产 mdcg_recall→recall 链)返回写前陈旧结果且仅带 cached=True 标记无陈旧告警 | 实跑复现(MDCG_HOTCACHE=1):首查 ids=[nodeA]→add(nodeB)+flush 后再查 cached=True 仍=[nodeA]、invalidations=0,新实例真值=[nodeA,nodeB];生产链 e2e:propose+review_decide(accept) ok=True 后同实例 recall 仍 [nodeA];grep 全仓源码唯一 `_hc.invalidate` 在 writepipe.py:437(仅 op=='write' 走 default_pipeline);默认 MDCG_HOTCACHE 未设不挂载(opt-in),开即错 | 留档(medium,暴露面窄于默认路径项) |
|
|
88
|
+
| N78★ | hotcache.py:61-62(_ENV_SWITCHES);mdcg.py:364(MDCG_CN_GRAMS 每次调用读 env) | medium | query 缓存键进程级开关快照漏 MDCG_CN_GRAMS:运行期翻转后同 query 命中另一口径缓存(静默错答);同型暴露:SCORE_MODE 模块级属性切换同样不在键内 | 实跑复现:首查(默认开)ids=[fullnode, gramnode]→同进程设 MDCG_CN_GRAMS=0 后同 query 再查 cached=True 仍旧值,新实例(同开关)真值=[fullnode]——gramnode 系另一口径陈旧结果;`_ENV_SWITCHES` 只枚举 5 个 env 名确认缺登(与 2026-09-24 补 env_switch 键的修复同类漏登) | 留档(medium,同 opt-in 前提;修复=补登一行) |
|
|
89
|
+
| N79★ | mdcg.py:2648-2649(S3 提前记,现行 :2649)+ :2930-2931(_emit 再记,现行 :2931) | low | S3 扩散层 record_access 双记:每个 S3 tier 查询 access_log 落两条同 ids 同 tier 记录、access_counts 翻倍落盘;且提前记录发生在 _emit 的 S5 降权重排之前,记录集可能与最终 results 不一致 | 实跑复现(MdCG 基类 + 双开关开):单次 search tier=T2b_spread_activation,access_log 恰 2 条完全相同记录→该批节点各计 2;对照开关关走 T2_global_like 仅 1 条。暴露面补充:S3 段仅存在于基类 MdCG.search,生产 MdCGOS.search 覆写(mdcos.py:733)不含 S3——生产 MCP 检索不经此段,暴露面为直接使用基类且显式开 S3 的调用方 | 留档(low;修复=删提前记录一处) |
|
|
90
|
+
| N80★ | mdcg.py:2454(现行 :2455)+ :2134(get 同型裸调);对照 _read 契约 :2146-2150 | low | P2-20 越界处置契约不一致:_read 对越界 path 返回 (None,None) 跳过,但 MdCG.search 负层段与 MdCG.get 把 `_node_disk_path` 放 try 外且只捕 OSError——索引被污染(P2-20 威胁模型,快照无完整性校验)时一条越界条目使基类整库检索 / get 以 ValueError 崩溃而非降级跳过 | 实跑复现(投毒 index['nodes'] 两条 `../escaped*.md` 条目):`_read(bad)`→(None,None)(契约内);基类 search→ValueError 且栈顶 _node_disk_path raise(:1188);**生产暴露面实测修正**:同投毒下 MdCGOS.search/search_rrf 均 ok(负层经 _neg_coverage→self._read 优雅跳过),生产可达的是 get——op=get 与 mdcg_get 工具均 cg.get(nid) → ValueError 直达调用方 | 留档(low,触发前提为索引被污染) |
|
|
91
|
+
| v7 负层留档复测★ | mdcos.py:718-730(已覆盖);残余 mdcg.py:2917-2921(现行 :2918-2924 _emit 尾部裸 open ×3) | low | 【v7 留档复测·**IO 已被覆盖,审计口径未消**】残余有二:① _emit 尾部对 covered_neg[:3] 裸 open 直读(不经 _read 不入读缓存,每查询恒 ≤3 次,S5 开启另有 ≤10 次同型——读码确认未实跑计数);② scanned 审计口径盲区——负层读取不计入 meta.scanned | 复测实跑(60 knowledge+8 rejected,包装 nodefile.loads 计数):首查 loads=71(60 全池+8 负层+3);第 2 查同 query 增量恰 3 次=covered_neg[:3] 裸 open;负层 8 次读经 self._read 全部缓存命中(增量 0)——IO 覆盖结论成立;include_neg False/True 的 meta.scanned 均=60(首查真实多读 8 个文件但 scanned 不变),盲区原样存在 | 留档(残余两项,low) |
|
|
92
|
+
| v7 N50 残腿★ | mdcos.py:979(_path_graph 种子 self.get,现行 :979)+ mdcg.py:2130-2142(get 裸 open) | low | 【v7 留档复测·**_read 系重复读已覆盖,get() 种子读未覆盖**】四路中经 self._read 的部分(lexical 全池、entity 重读、graph 邻居读)已被读缓存覆盖(稳态第 2 查增量 0);唯一残余:≤5 个种子经 MdCG.get 裸 open+loads(读缓存不覆盖),每查询固定 ≤5 次(graph 零产出也在边循环前发生) | 复测实跑(40 节点含 tags/edges):首查 loads=45(lexical 40+entity 首见 5);第 2 查增量恰 5 次、结果 ids 逐位一致;严格归因(patch MdCGOS.get 计数+栈采样):5 次全部来自 search_rrf→_path_graph:979 self.get→mdcg.py:2134-2137 裸 open;`_path_entity`/`_path_graph` 邻居均 self._read(增量 0)——v7 遗留表「读缓存默认开后自动受益」假设对 get 腿为假 | 留档(残腿,low;修复=种子腿改走 _read_many 即并入缓存) |
|
|
93
|
+
|
|
94
|
+
### write 区(5 confirmed:4 新独立 + 1 同对象重复条目;1 rejected)
|
|
95
|
+
|
|
96
|
+
| # | where(缺陷时点) | 严重度 | 问题摘要 | 证据要点 | 状态 |
|
|
97
|
+
|---|------|--------|----------|----------|------|
|
|
98
|
+
| N74★ | branches.py:261 | medium | discard 幽灵固化:摘索引只 pop 内存不写 tombstone,内部 flush 把 fork 阶段分支条目作为 upsert 持久化,close 时 compact 重扫+日志重放把已移走节点叠回——幽灵固化进 _index.json 快照,重开指纹校验放行、永久存活(详 F3) | 独立复现(系统临时区临时库,测毕清理):discard 返回时 _dirty={}(无 tombstone)、_index_log=[分支 upsert, summary upsert];盘面 LAYERS 内 .md 计数 2,close 计数对账 2≠3 触发重扫叠回;重开后索引含 mem_base@br1 且 get(mem_base@br1)=None | **已修**(F3) |
|
|
99
|
+
| N75★ | mdcg.py:3166-3170 | medium | verify() 直写分支不置 _dirty:noop 形态写盘对索引增量日志与读缓存代际完全不可见(详 F2) | 独立复现 ×2:set_verification(verified) 并 close 后重开,verify(n1,'第二次外部证据','confirmed') 返回 confirmed、verification.code=noop/changed=False;盘面 evidence_count=1/confidence=0.65,重开后索引 0/None——漂移固化实拍(计数对账只对账数量不触发重扫);readcache 子主张同库复现:_read 缓存视图 0 vs _read_uncached 盘面 1 | **已修**(F2) |
|
|
100
|
+
| N76★ | links.py:85-99 | medium | 连接层全部变更 load→改→save 无锁 + save 固定临时名:并发丢一方信任更新(20/20)、互踩 .tmp 内容交织(audit 超上限实拍)、FileNotFoundError 分支(读码成立当时未实证)(详 F5) | 独立复现:双线程 Barrier 对齐 save 点并发 observe → 20/20 轮静默丢一方更新(终态一方 evidence_count=0、无异常);双 Barrier 对齐 save 与 publish → 终态 audit=3 条超单写者合法上限 2——两写者共享同一 .tmp 交织写的直接证据;fsutil.py:6-8 明载固定临时名反模式 | **已修**(F5) |
|
|
101
|
+
| (N73 同对象重复条目) | mdcos.py:1786-1789 | low | 审核队列水位存旧值致重复并入(review_list 重复 pid、review_stats 翻倍、_cascade_dedup 双 reject)——与 recent 区 N73 为**同一缺陷对象**(同根因同修法),随 F4 一并消解 | 独立复现(双实例,注入等价并发落窗):A propose 装载水位 249 → B propose(n2) → 读前注入第三实例 propose(n3) → 第一次并入 n2、n3 但水位存 498(读前 stat size)→ 第二次从旧水位重读 n3:缓存 4 条 vs 盘面 3 条;二次后果维持读码推演定性(本轮未单独实跑,推演依据本轮读核成立) | **已修**(随 F4 消解,不重复占坑) |
|
|
102
|
+
| N81★ | mdcos.py:2239(现行 :2258) | low | deletions_log(restore 强制检查闸门与 is_tombstoned 依据)经 append_jsonl 裸追加无 strict 锁——并发 forget 交错丢 tombstone 记录,丢失使已删节点绕过「恢复时删除检查」被无 force 恢复 | 读码+多进程压测(系统临时区临时库,测毕清理):forget 全程无 FileLock、裸追加;fsutil.py:189-197 文档自述 Windows CRT _O_APPEND 两步交错丢记录;对照组 _record_decision 因「裁决记录不能丢」专门用 strict FileLock(:1950-1951);本轮压测复现(6 进程×40 条、每条 ~250B 加大窗口):期望 240、完整解析 232、**丢失 8**(坏行 0=覆盖式丢失);restore 删除检查闸门按 read_jsonl(deletions_log) 命中判定,tombstone 丢失即无 force 放行恢复 | 留档(low;修复=改走带锁 ShardedLog 或 FileLock,_record_decision 已有同型模式) |
|
|
103
|
+
| ~~v8 N71 重报~~(rejected) | mdcos.py:2157-2191 | — | **剔除(不作为本轮新发现重报)**:与本缺陷同对象的 recent 区复测条目已确认维持留档处置;按「已修项/留档勿重复报」纪律不重复立项 | 本轮读核现状与 v8 留档时未变:merge 分支仍是 self.get→内存拼接→_write_node 定向 upsert 的无互斥读-改-写;FileLock 仅罩 inbox/decisions 追加不罩节点读写窗口 | 剔除(留档维持,见 recent 区条目) |
|
|
104
|
+
|
|
105
|
+
### legacy 区(5 confirmed:全部为历轮留档复测;1 rejected)
|
|
106
|
+
|
|
107
|
+
| # | where(缺陷时点) | 严重度 | 问题摘要 | 证据要点 | 状态 |
|
|
108
|
+
|---|------|--------|----------|----------|------|
|
|
109
|
+
| v8 N62★ | tokens.py:410 + mcp_server.py:3468(均现行读核在位) | medium | 【留档复测成立】租户绑定被 env 覆盖且静默 + 注册表 clearance_cap 夹紧从未接线(多租户密级上限失效):verify_token 的 tenant 形参直取 env(MDCG_TENANT),`tenant=tenant or rec.get("tenant")` 使 env 值优先于令牌记录绑定且无一致性校验(对照 MDCG_CLEARANCE 有冲突告警而 MDCG_TENANT 静默);TenantRegistry.cap_of/principal_for 全仓无生产调用点 | 临时环境复现(临时令牌文件/租户登记表/双根,测毕清理):issue designer clearance=secret tenant=tenA → 设 MDCG_TOKEN/MDCG_TOKEN_FILE/MDCG_TENANT=tenB 后 `_build_principal()` 输出 err=None、tenant='tenB'(绑定被静默覆盖)、clearance='secret'(cap_of('tenB')='public' 未夹紧)、_resolve_root 解析到 rootB,全程无 stderr 告警;principal.tenant 下游参与可见性过滤(mdcos.py recent_events);git log 证实 tokens.py v8(批次 40)零改动未在已修清单内 | 留档(medium;建议下轮专项,至少先补 MDCG_TENANT 冲突告警对照既有模式) |
|
|
110
|
+
| v8 N71★ | mdcos.py:2157-2191(现行 :2178-2190) | low | 【留档复测成立,=recent 区同对象】review_decide merge 分支读-改-写无互斥(详 recent 区) | 双进程确定性复现(monkeypatch 屏障:_write_node 等双方 read_done 标记齐才放行——栈级等价放大亚毫秒窗口):child A/B 均返回 ok=true、重开读终态 content 丢失一方载荷、decisions.jsonl 两条均 accepted(假成功留痕);mdcos.py FileLock 使用点仅 audit 轮转/inbox/decisions 日志,不罩目标节点;第 7/8 轮修复面均未含(F4 只改收尾为定向 upsert 未加锁) | 留档维持(low,坑满顺延) |
|
|
111
|
+
| v7 N51★ | mdcos.py:800 + 872-887(现行 :800 + :875-887) | low | 【留档复测成立】T2/T3 截断后重打分仍在位:try_stage 无 scored 形参(内部自调 _score),T2 在 cut_by_relevance 内已对全量 hits 打分、try_stage 对截断后集合再打;T3 对 docs_all 打分截断后又对 picked 重打 | 600 节点临时库实测(计数器包装 MdCGOS._score):一次 search tier=T3_global_scan、_score 调 4 次、per-call docs=[0,0,600,500]、共打分 1100 文档;结构读核与 v7 留档一致;v7 五修 F1-F5 面与 v8 安全专项均不含,未修 | 留档(low 性能项,坑满顺延) |
|
|
112
|
+
| v7 N52★ | postings.py:122-159(现行读核在位) | low | 【留档复测成立、维持窄受益判断】发布表指纹校验仍逐目录 os.stat(无 TTL 化/折叠为索引 mtime 单点校验),S7 启用者每查询恒付 O(目录数) stat;S7 仍只接在父类 MdCG.search(双开关默认关),生产覆写 MdCGOS.search 零 postings 引用 | 读核:stale_reason 逐目录 _mtime_ns、逐根级文件 stat、再 stat _index.json,无 TTL/折叠;临时库实测(双开关开、建真快照后)3 次 search → stale_reason 恰调 3 次,单目录库单次走满指纹校验 stat 2 次;postings.py 自 cd9cce0 后未动 | 留档(low 性能项且触发面窄,坑满顺延) |
|
|
113
|
+
| v7 N50 残腿(同对象)★ | mdcos.py:979 + mdcg.py:2130-2136(现行读核在位) | low | 【legacy 区同对象记录,=retrieval 区 v7 N50 残腿】稳态每次 search_rrf 恒 5 次种子节点文件 open+parse(不经读缓存);与 retrieval 区条目为同一缺陷对象,随其处置不重复占坑 | 临时库实测(30 知识+10 add_rejected,builtins.open 计数限临时 root 前缀):search 同查询 Q1 opens=40/scanned=30、Q2 opens=0;栈级归因稳态每次 search_rrf 仍 5 次 open 全部来自 mdcos.py:979→mdcg.py:2136(MdCG.get 直接 open,不走 readcache 包装的 _read);四条 _read 腿零残留 | 留档(随 retrieval 区条目处置) |
|
|
114
|
+
| ~~负层全读~~(rejected) | mdcos.py:718-725(调用点 :797) | — | **剔除(已被覆盖)**:负层 `_neg_coverage` 走 self._read(构造期默认装配 readcache),同进程稳态零磁盘读,「每查询全量 open+parse」形态不再成立 | 临时库实测(30 知识+10 rejected,默认环境读缓存缺省开):同查询 search Q1 opens=40/scanned=30、Q2 opens=0;残留仅口径 nit(首查负层读盘 opens=40 vs scanned=30 不计入,但负覆盖结果集已经 meta.covered_neg 无条件披露,mdcg.py:2946)——非缺陷级,不重复报 | 剔除(残余口径 nit 归入 v7 负层留档复测条目) |
|
|
115
|
+
|
|
116
|
+
### 第 7 轮留档两项复测结论(显式定谳,任务点名记录)
|
|
117
|
+
|
|
118
|
+
1. **负层全读每查询磁盘 IO(v7 遗留项)**:**IO 面已被第 7 轮读缓存默认化覆盖**——60 knowledge+8 rejected 库实测首查 loads=71(全池 60+负层 8+_emit 尾部 3)、第 2 查增量恰 3 次(即 `_emit` 尾部裸 open),负层 8 次读经 `self._read` 全部缓存命中(增量 0);**残余未消**:①`_emit` 尾部 covered_neg[:3] 裸 open 每查询恒 ≤3 次(S5 另 ≤10 次,读码确认)②`scanned` 审计口径盲区(负层读取不计入 meta.scanned,include_neg True/False 均=60)→ 残余两项留档(low)。legacy 区对该缺陷原形态的「每查询全量 open+parse」主张同步**整项剔除**(如上表)。
|
|
119
|
+
2. **四路召回重复读盘(v7 N50)**:**`_read` 系四腿(lexical 全池 / entity 对 tag 命中重读 / graph 邻居 / chain)已全部被读缓存覆盖**——稳态第 2 查磁盘读增量 0;**唯一残腿未覆盖**:`_path_graph` 的 ≤5 个种子经 `MdCG.get` 裸 open+loads(mdcos.py:979→mdcg.py:2130-2136,不经缓存包装的 `_read`),每查询固定 ≤5 次(graph 路零产出也在边循环前发生);N50 原「同节点重复 open+parse 税」形态经 `MDCG_READ_CACHE=0` 对照(87 次/查询)vs 默认开(第 2 次 `_read` 面 0 次)**证伪剔除**——v7 遗留表「读缓存默认开后自动受益」的假设对 `_read` 腿为真、对 get 腿为假。
|
|
120
|
+
|
|
121
|
+
### 占位去重说明(留档清单 2 条,不承载独立缺陷)
|
|
122
|
+
|
|
123
|
+
- `branches.py:261`(跨区重复条目):与已选修复目标 N74 为同一缺陷对象(同 where 同根因,证据完全一致),留档槽仅为保持候选清单与输出一一对应。
|
|
124
|
+
- `mdcos.py:1786-1789`:与已选修复目标 N73 同根因同修法,随 F4 一并消解,不重复占坑。
|
|
125
|
+
|
|
126
|
+
---
|
|
127
|
+
|
|
128
|
+
## 四、验证(门禁结果)
|
|
129
|
+
|
|
130
|
+
以下「本报告会话实跑」均为本报告写作会话在仓库根目录实际运行(第一手);「材料口径」为编排/修复会话已跑、本会话未重跑(如实区分):
|
|
131
|
+
|
|
132
|
+
| 命令 | 结果 | 来源 |
|
|
133
|
+
|------|------|------|
|
|
134
|
+
| `python scripts/run_tests.py --jobs 4`(全量) | `===== SUMMARY 179/179 通过,5 跳过(依赖缺失/平台不符) =====`,退出码 0——**与材料口径逐字一致**(尾部 PASS 含 hive.test_wm_progress / hive.test_exec_tools / swarm.tests.test_rust_swarm;179 = v8 基线 174 + 本轮 5 个新守卫套件自动发现入列) | **本会话实跑** |
|
|
135
|
+
| `python -X utf8 -m md_cg.test_govern_directread` | `结果:PASS 40 / FAIL 0`(=材料修后绿态;材料红证 34/6) | **本会话实跑** |
|
|
136
|
+
| `python -X utf8 -m md_cg.test_verify_dirty_reconcile` | `结果:PASS 18 / FAIL 0`(材料红证 10/8) | **本会话实跑** |
|
|
137
|
+
| `python -X utf8 -m md_cg.test_branch_discard_tombstone` | `结果:PASS 10 / FAIL 0`(材料红证 7/3) | **本会话实跑** |
|
|
138
|
+
| `python -X utf8 -m md_cg.test_tail_watermark_race` | `结果:PASS 12 / FAIL 0`(材料红证 6/6) | **本会话实跑** |
|
|
139
|
+
| `python -X utf8 -m md_cg.test_links_concurrent_write` | `结果:PASS 9 / FAIL 0`(材料红证 git stash 回退旧码 4/5,含 FileNotFoundError 实拍) | **本会话实跑** |
|
|
140
|
+
| `python scripts/check_publish_artifact.py`(`npm run gate` 第 2 环单独复现) | R1 凭据/密钥面 **PASS(文件面=0 内容面=0)**、R2 私有数据面 PASS、R3 隐私文本 PASS;**R4 非追踪件面 FAIL 命中=5**——恰为 `md_cg/test_branch_discard_tombstone.py`、`test_govern_directread.py`、`test_links_concurrent_write.py`、`test_tail_watermark_race.py`、`test_verify_dirty_reconcile.py` 五个新守卫(非追踪=29、允许=24);`VERDICT=FAIL`——与材料门禁输出同因同置,且补全了材料截断的命中清单 | **本会话实跑** |
|
|
141
|
+
| `npm run gate`(全链) | 材料口径 FAIL(R4 时序性:5 个新守卫尚未 `git add` 登记追踪面,材料输出被截断仅见 4 文件名);本会话未重跑全链、仅单独复现 R4 环(上 row)——按守卫自身要求 `git add` 登记后复跑即过(v7/v8 先例),**归编排会话提交前裁决,本报告会话未擅自登记/提交** | 材料 + 本会话部分复现 |
|
|
142
|
+
| `cargo test` | **未运行**——Rust 面零改动(本会话 `git status` 证实改动面为 md_cg/ hive/ scripts/,rust/ 与 swarm/ 未动) | 双方一致 |
|
|
143
|
+
| `npm test` | **未运行**——TS 面零改动(src/ 与 test/ 未动;遗留项中 TS 文件零涉及) | 双方一致 |
|
|
144
|
+
|
|
145
|
+
**上游会话已运行、本会话未重跑的验证**(材料原文,如实区分):五项修复的守卫红证(修前各一跑:govern_directread 34/6、verify_dirty_reconcile 10/8、branch_discard_tombstone 7/3、tail_watermark_race 6/6、links_concurrent_write 首跑 6/3 → 基线修正后 `git stash push -- md_cg/links.py` 旧码复跑 4/5);F5 的 git stash 回退对照;修复核对 diff(F1 恰 14 处替换+4 行 import、F2 单行+hunk@3168、F3 hunk@258、F4 `--stat` +33/+71、F5 import+save+五调用点);相关既有套件(test_ccgc 84/0、test_p34_crosscheck 51/0、test_p39_vision_evidence 53/0、test_p6_consolidate 82/0、test_trust 127/0、test_branches 43 通过、test_propose_tail_index 8/0、test_p23_links 58/0、test_readcache_default_on 10/0 等);md_cg/test_*.py 全目录逐套执行 147 文件全绿(含五个新守卫)。四区复核的全部攻击/竞态复现(临时库+注入法,测毕清理)亦为上游会话执行(材料原文)。
|
|
146
|
+
|
|
147
|
+
**git 工作树核对**(本会话 `git status` / `git diff --stat` + 逐处读核):改动面 = **九个修复文件**(md_cg/consolidate.py +13、ccgc.py +5、crosscheck.py +7、vision_evidence.py +7、mdcg.py +7、branches.py +16、fsutil.py +33/-15、mdcos.py +71/-37、links.py +245/-165)+ **scripts/verify_linux.sh**(+3 行注册 5 个新守卫,现行 :21-23)+ **五个新守卫文件**(untracked)——与五项修复一一对应。另有三件非本轮修复组成的改动,如实注明:① `hive/test_exec_tools.py` +22——本轮全量回归超时归因后的 K2 守卫加固(reader 线程 daemon 化防进程挂死、Windows 读者瞬态句柄把 replace 50 次重试耗尽时计数不中断、新增「写成功 ≥1」断言防压测全饿死时 K2 空转),diff 内注释自证日期 2026-09-25,非五项修复触点;② `md_cg/whitebox_kb/wisdom/code_solidified.json`——材料明示为本轮之前已存在的工作区变更(本会话 diff 读核:仅删除一行缓存命中指纹记录);③ 一件与工程无关的非追踪图片文件(R4 允许清单内,不涉本轮改动)。未做任何 commit。
|
|
148
|
+
|
|
149
|
+
---
|
|
150
|
+
|
|
151
|
+
## 五、遗留清单(11 项:medium 3 / low 8)
|
|
152
|
+
|
|
153
|
+
### medium(3 项)
|
|
154
|
+
|
|
155
|
+
| # | where(现行,本会话读核) | 问题 | 留档理由 / 处置线索(材料口径) |
|
|
156
|
+
|---|------|------|------------------------------|
|
|
157
|
+
| N77 | writepipe.py:437(全仓唯一 `_hc.invalidate`);mdcos.py query 缓存读写 | query 热缓存失效缺口:add / review_decide(accept·edit·merge)不失效,`MDCG_HOTCACHE=1` 下写后 ≤300s 内 search_rrf/recall 返回写前陈旧结果且仅 cached=True 无陈旧告警 | 以 MDCG_HOTCACHE=1 opt-in 为前提(默认不挂载),暴露面窄于默认路径入选项;修复方向明确(add/review_decide 写点补 _hc.invalidate),可下轮带 |
|
|
158
|
+
| N78 | hotcache.py:61-62(_ENV_SWITCHES)+ mdcg.py:364(CN_GRAMS 每调用读 env) | query 缓存键进程级开关快照漏 MDCG_CN_GRAMS(及 SCORE_MODE 模块级切换):运行期翻转开关后同 query 命中另一口径缓存(静默错答) | 同 opt-in 前提(缓存挂载方才有键问题);修复为 _ENV_SWITCHES 补登一行,可下轮顺手带 |
|
|
159
|
+
| v8 N62 | tokens.py:410 + mcp_server.py:3468(均现行在位) | 租户绑定被 env 覆盖且静默 + clearance_cap 夹紧从未接线(多租户密级上限失效);tenB(cap=public) 借 MDCG_TENANT 即可以 secret 密级读 rootB | medium 安全项,但暴露需多租户部署形态(令牌文件+租户登记表),且接线 cap_of 含行为决策(夹紧 vs 拒绝),修复风险高于本轮所选五项;建议下轮专项(至少先补 MDCG_TENANT 冲突告警,对照 MDCG_CLEARANCE 既有模式) |
|
|
160
|
+
|
|
161
|
+
### low(8 项)
|
|
162
|
+
|
|
163
|
+
| # | where(现行,本会话读核) | 问题 | 留档理由 / 处置线索 |
|
|
164
|
+
|---|------|------|---------------------|
|
|
165
|
+
| N79 | mdcg.py:2649 + :2931(S3 提前记/_emit 再记) | S3 扩散层 record_access 双记:access_log 两条同 ids 同 tier、access_counts 翻倍落盘;提前记录在 S5 降权重排前,记录集可能与最终 results 不一致 | 生产 MdCGOS.search 覆写不含 S3(暴露面仅显式开 S3 的直接引擎调用方);修复=删提前记录一处,改动面小可下轮带 |
|
|
166
|
+
| N80 | mdcg.py:2455(现行)+ :2134(get 裸调) | P2-20 越界处置契约不一致:索引被污染时 MdCG.get(生产 op=get/mdcg_get 直达)以 ValueError 崩溃、基类 MdCG.search 整库检索崩溃而非按 _read 契约 (None,None) 降级跳过 | 触发前提为索引被污染(P2-20 威胁模型);修复=两处调用移入 try/捕 ValueError 降级,可下轮带 |
|
|
167
|
+
| N81 | mdcos.py:2258(现行;缺陷时点 :2239) | deletions_log 裸追加无 strict 锁:并发 forget 交错丢 tombstone(240 条丢 8 条实拍),丢失使已删节点绕过恢复删除检查被无 force 恢复 | 修复=forget 的追加改走带锁 ShardedLog 或 FileLock(_record_decision :1950-1951 已有同型模式) |
|
|
168
|
+
| v8 N71 | mdcos.py:2178 读 / :2190 写(现行;缺陷时点 :2157-2191) | review_decide merge 分支读-改-写无互斥:并发 merge 同目标丢一方内容而双裁决 accepted(假成功留痕);本轮三区复测均成立(确定性交错双实拍) | low 留档项坑满顺延;修复=merge 段加节点级 FileLock(与 N72 相互独立:merge 基底直读盘,无缓存陈旧成分) |
|
|
169
|
+
| v7 N51 | mdcos.py:800 + :875-887(现行) | T2/T3 截断后重打分仍在位(600 节点库一次 search 打分 1100 文档:600+500 双打分) | low 性能项坑满顺延;修复=try_stage 增加 scored 形参透传 |
|
|
170
|
+
| v7 N52 | postings.py:122-159(现行) | 发布表指纹校验仍逐目录 os.stat(无 TTL/折叠),S7 启用者每查询恒付 O(目录数) stat;S7 仍只在父类 MdCG.search(双开关默认关) | low 性能项且触发面窄,坑满顺延 |
|
|
171
|
+
| v7 N50 残腿 | mdcos.py:979 + mdcg.py:2130-2136(现行) | 稳态每次 search_rrf 恒 5 次种子节点文件 open+parse(MdCG.get 裸 open 不经读缓存,graph 零产出也发生) | 本轮复测证明 v7 遗留表「读缓存自动受益」假设对 get 腿为假;修复=种子腿改走 _read_many 即并入缓存 |
|
|
172
|
+
| v7 负层残余 | mdcg.py:2918-2924(现行) | ① _emit 尾部 covered_neg[:3] 裸 open 每查询恒 ≤3 次(S5 另 ≤10 次);② 负层读取不计入 meta.scanned 的审计口径盲区 | low 性能/口径项坑满顺延(IO 主面已被读缓存覆盖,见第三节复测专节) |
|
|
173
|
+
|
|
174
|
+
**优先级建议**(据材料处置线索汇总):N77/N78 为「opt-in 开关面的缓存正确性」同族(修复面小:补失效挂点 + 补登键),建议同轮速收;v8 N62 多租户接线需先做夹紧语义设计决策(或先补 MDCG_TENANT 冲突告警最小止血);N79/N80/N81 均为单点小修;v7/v8 性能与竞态留档项(N51/N52/N50 残腿/N71/负层残余)坑满顺延。
|
|
175
|
+
|
|
176
|
+
---
|
|
177
|
+
|
|
178
|
+
## 六、纪律合规声明
|
|
179
|
+
|
|
180
|
+
1. **定位先读索引**:本报告写作前已读 WORKSPACE_INDEX.md(按职责定位 docs/eval 为报告归域、md_cg/ 为记忆系统本体、scripts/ 为工程管线),未做全盘浏览。
|
|
181
|
+
2. **结论引证**:所有修复与缺陷均引 path:line(缺陷时点快照行号,本轮 mdcg.py/mdcos.py 行号漂移处另注现行行号并经本会话读核——F2 修复行材料称 :3175、本会话读核实为现行 :3177,以读核值为准);第三节证据要点摘自任务输入的四区复核材料(上游会话读码+实跑);第四节「本会话实跑」八项为第一手命令与输出原文(全量回归、五守卫、R4 复现、git 核对),材料口径与未跑项(cargo/npm test/gate 全链/红证重跑/攻击复现重跑)均如实标注来源,无一冒充。
|
|
182
|
+
3. **修复落盘核验**:五项修复的现行代码本报告会话逐处读核——F1 四文件 14 处 direct_read + 4 行 import(grep 计数 6/2/3/3 逐一列出)、F2 mdcg.py:3171-3177、F3 branches.py:261-276(_unstage 调用+防御回落)、F4 fsutil.py read_jsonl_tail 返回 (records, end) + mdcos 四缓存水位行(:1739/:1771/:1802/:1833)、F5 links.py save→atomic_write + `_locked` 五调用点(:333/:360/:433/:446/:489);11 项遗留的现行现状亦逐一 grep/读核确认(第五节「现行」列);verify_linux.sh 5 守卫注册(:21-23)读核在位。
|
|
183
|
+
4. **安全测试纪律**:材料中全部复现均在临时库/临时环境(tempfile 系统临时区),使用哑令牌与哑数据(哑租户标识以 tenA/tenB 等占位描述),不触真实数据目录与真实令牌,测毕清理(材料逐项声明);本报告会话只运行守卫套件与门禁检查器,未做任何攻击/竞态复现。
|
|
184
|
+
5. **已修项不重复报**:本轮 legacy 项全部为历轮留档的**复测记录**(v7 N50/N51/N52、v8 N62/N71),复测结论为「维持留档」或「部分剔除」,不作为新缺陷重复立项;v8 N71 在 write 区的重报条目按「留档勿重复报」纪律剔除;第 1-8 轮已修清单(见 docs/eval/缺陷挖掘_自主迭代_v1~v8.md 第二节)未再报;F1 与第 7 轮 backfill/govern 的 direct_read 为**补齐漏装面**(第 7 轮修复未覆盖的 14 处),非重复修复。
|
|
185
|
+
6. **隐私脱敏**:全文只写仓库相对路径;材料的本机绝对路径(盘符/用户目录/临时区路径)一律转录为「系统临时区临时库/临时环境」;哑令牌/哑密钥样例以占位描述,无任何 key/token 字面量;环境变量名与标识符(MDCG_HOTCACHE/MDCG_TENANT 等)为源码标识符非凭据值,为证据必需而保留;定稿前经机械扫描复查(见下方自查)。
|
|
186
|
+
|
|
187
|
+
---
|
|
188
|
+
|
|
189
|
+
## 七、跳过项及原因
|
|
190
|
+
|
|
191
|
+
- **cargo test 未运行**:Rust 面零改动(本会话 git status 证实 rust/ 与 swarm/ 未动)。
|
|
192
|
+
- **npm test 未运行**:TS 面零改动(src/ 与 test/ 未动,本轮缺陷与修复全部在 md_cg/python 面)。
|
|
193
|
+
- **`npm run gate` 全链未于本会话重跑**:材料口径 R4 时序性 FAIL(5 个新守卫文件 untracked、非追踪=29>允许=24,材料输出截断);本会话以第 2 环 `scripts/check_publish_artifact.py` 单独复现同因同置(R1/R2/R3 全 PASS、R4 命中恰为五个新守卫)——按守卫自身要求 `git add` 登记后复跑即过(v7/v8 先例),**处置归编排会话提交前裁决,本会话未擅自登记/提交**。
|
|
194
|
+
- **守卫红证未在本会话重跑**(含 F5 的 git stash 回退旧码跑法):上游修复会话已跑且逐项留痕(修前红/修后绿数字见第二节),本会话重跑会反复 stash/unstash 工作树,风险大于收益——以修复落盘读核 + 修后绿态实跑 + 全量回归替代佐证,如实标注。
|
|
195
|
+
- **四区复核的攻击/竞态复现未在本会话重复**:上游复核会话已在临时库执行并逐项声明「测毕清理」,本报告会话未重跑(第三节证据来源均标注为材料原文)。
|
|
196
|
+
- **N77 生产链 e2e / N79 S5 计数 / N73 `_cascade_dedup` 双 reject 二次后果**:上游材料自身声明的「读码推演成立、本轮未单独实跑」部分,本报告照实转录并保留其定性标注,未升格为实证。
|
|
197
|
+
- **git 未提交**:commit 需任务方指令;工作树保持五补丁 + 五守卫 + 守卫注册 + K2 加固原状。
|
|
198
|
+
|
|
199
|
+
---
|
|
200
|
+
|
|
201
|
+
*报告依据:任务输入的第 9 轮材料(四区复核 19 confirmed + 3 rejected 明细及证据、五项修复的 where/问题/修复/前后对比/守卫/verified_by、留档未修 15 条中 2 条占位去重 + 2 条跨区重复、门禁结果);本报告会话的修复落盘读核(五补丁 14+1+1+四缓存+五调用点锚点 + verify_linux.sh 注册)、11 项遗留现行读核(第五节「现行」列)、五套新守卫实跑(40/0、18/0、10/0、12/0、9/0)、全量回归实跑(179/179、退出码 0)、R4 门禁单独复现(FAIL 同因同置且补全命中清单)、git 工作树核对、报告脱敏机械扫描。*
|
|
202
|
+
|
|
203
|
+
*自查双清单:①材料覆盖——四区 22 条目全部入文(recent 3+1 / retrieval 6 / write 5+1 / legacy 5+1),confirmed 19 与剔除 3 一一对应,去重后 16 独立缺陷(新 N72-N81 共 10 + legacy 复测 6)数目吻合,5 补丁逐项五要素齐全,修 5 + 留档 11 = 16 无多无少,2 条占位去重说明单列,第 7 轮留档两项复测结论显式定谳(专节 + legacy/rejected 双向记录),v8 N71 三区复测与不重报处置如实入文,门禁四项(python/cargo/npm test/gate)与跳过原因一一对应,材料截断的 R4 命中清单经本会话复现补全;②纪律——全部结论引 path:line 或注明材料来源,八项第一手实跑命令与输出在第四节(全量回归、五守卫、R4 复现、git 核对),未跑项(cargo/npm test/gate 全链/红证/攻击复现)无一冒充为已跑,F2 行号材料口径(:3175)与读核值(:3177)的偏差如实注明,工作树三件非修复改动(K2 加固/先前会话 json/无关图片)如实注明,全文无本机绝对路径、无 key/token 字面量(机械扫描盘符/用户目录/token 形态零命中)。*
|