@furongjun1999/dsh-memory 0.6.1 → 0.7.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (105) hide show
  1. package/README.md +49 -18
  2. package/docs/README.md +1 -0
  3. package/docs/eval/cons200_/345/206/262/347/252/201/346/243/200/346/265/213/351/200/211/351/235/242_/345/256/236/346/226/275/350/256/260/345/275/225_v1.0.md +223 -0
  4. package/docs/eval/cons200_/345/206/262/347/252/201/346/243/200/346/265/213/351/200/211/351/235/242_/345/256/236/346/226/275/350/256/260/345/275/225_v1.1.md +340 -0
  5. package/docs/eval/issue50_/345/205/203/346/225/260/346/215/256/351/200/217/344/274/240/344/270/216/345/205/234/345/272/225_/344/277/256/345/244/215/350/256/260/345/275/225_v1.0.md +437 -0
  6. package/docs/eval/issue50_/345/215/212/351/207/215/345/244/215/345/276/205/345/256/232/345/244/215/346/240/270_/344/277/256/345/244/215/350/256/260/345/275/225_v1.0.md +488 -0
  7. package/docs/eval/issue50_/345/276/205/345/256/232/345/244/215/346/240/270/345/205/245/351/230/237_/344/277/256/345/244/215/350/256/260/345/275/225_v1.0.md +428 -0
  8. package/docs/eval/issue50_/350/257/273/351/235/242/344/277/235/346/212/244/345/217/252/350/256/244/346/230/276/345/274/217/346/235/245/346/272/220_/344/277/256/345/244/215/350/256/260/345/275/225_v1.0.md +271 -0
  9. package/docs/eval/issue50_/351/207/215/350/246/201/345/272/246/345/220/214/346/272/220/344/270/216/344/277/235/346/212/244/350/257/255/344/271/211_/344/277/256/345/244/215/350/256/260/345/275/225_v1.0.md +306 -0
  10. package/docs/eval/issue51_/344/270/200/351/224/256/345/256/211/350/243/205/345/244/261/350/264/245_/345/275/222/345/261/236/345/210/244/345/256/232_v1.0.md +58 -0
  11. package/docs/eval/issue52_/346/235/241/344/273/266/345/205/210/350/241/214/344/270/216/346/210/252/346/226/255/345/217/257/350/247/202/346/265/213_/344/277/256/345/244/215/350/256/260/345/275/225_v1.0.md +360 -0
  12. package/docs/eval//344/270/211/346/241/243/350/207/252/346/262/273_/346/255/245/351/252/244/342/221/241/346/241/243/344/275/215/345/215/225/344/270/200/345/205/245/345/217/243_/350/220/275/347/240/201/350/256/260/345/275/225_v1.0.md +651 -0
  13. package/docs/eval//344/270/211/346/241/243/350/207/252/346/262/273_/346/255/245/351/252/244/342/221/242/345/217/230/346/233/264/345/215/225/344/270/216/345/233/236/346/273/232/345/216/237/350/257/255_/350/220/275/347/240/201/350/256/260/345/275/225_v1.0.md +439 -0
  14. package/docs/eval//344/270/211/346/241/243/350/207/252/346/262/273_/346/255/245/351/252/244/342/221/243/345/207/206/345/205/245/350/257/273/346/225/260_/350/220/275/347/240/201/350/256/260/345/275/225_v1.0.md +1337 -0
  15. package/docs/eval//344/270/211/346/241/243/350/207/252/346/262/273_/346/255/245/351/252/244/342/221/244/346/224/266/345/256/230/344/270/216/345/205/250/351/223/276/351/252/214/346/224/266_/350/220/275/347/240/201/350/256/260/345/275/225_v1.0.md +1817 -0
  16. package/docs/eval//345/207/272/350/264/247/351/235/242/345/206/222/347/203/237_/350/277/233/350/264/247/351/227/250/347/246/201_v1.0.md +460 -0
  17. package/docs/eval//345/217/221/345/270/20308_/350/207/252/350/277/255/344/273/243/344/270/216/347/235/241/347/234/240_/345/233/276/346/243/200/347/264/242/350/267/257/344/270/216/346/235/203/351/207/215_v1.0.md +97 -0
  18. package/docs/eval//345/217/221/345/270/20309_/346/243/200/347/264/242/351/235/242/344/270/211/346/211/271/346/224/266/345/217/243_v1.0.md +66 -0
  19. package/docs/eval//345/275/222/344/270/200/345/261/202/347/274/272/347/234/201/347/277/273/345/205/263_/344/277/256/345/244/215/350/256/260/345/275/225_v1.0.md +458 -0
  20. package/docs/eval//347/254/2543/345/261/202stg/347/273/223/346/236/204/347/264/242/345/274/225_/345/256/236/346/226/275/350/256/260/345/275/225_v1.0.md +250 -0
  21. package/docs/hive//346/243/200/347/264/242/347/256/227/346/263/225/345/217/243/345/276/204/345/257/271/347/205/247_v0.1.md +136 -11
  22. package/docs/hive//346/243/200/347/264/242/350/267/257/345/276/204/344/270/216/350/256/244/347/237/245/347/273/223/346/236/204/345/245/221/347/272/246_v0.1.md +32 -2
  23. package/docs/mdcg/README/350/257/246/347/273/206/347/211/210_v0.4.10.md +88 -0
  24. package/docs/mdcg//345/212/237/350/203/275/350/260/203/347/224/250/346/230/240/345/260/204/350/241/250_v0.1.md +40 -40
  25. package/docs/mdcg//345/217/221/345/270/203/351/227/250/347/246/201/351/223/276_v0.1.md +47 -11
  26. package/docs/mdcg//347/235/241/347/234/240/345/221/250/346/234/237_/350/277/220/347/273/264/345/211/215/346/217/220/344/270/216/347/273/264/346/212/244/346/214/207/345/215/227_v1.0.md +183 -0
  27. package/docs/plans/stg/346/235/241/344/273/266/345/214/226/344/270/216/347/273/223/346/236/204/347/264/242/345/274/225_/350/256/276/350/256/241_v0.1.md +124 -0
  28. package/docs/plans//347/235/241/347/234/240/344/270/216/350/207/252/350/277/255/344/273/243_/345/212/237/350/203/275/344/274/230/345/214/226/350/256/276/350/256/241_v0.4.md +547 -0
  29. package/docs/plans//350/256/260/345/277/206/350/207/252/345/244/204/347/220/206/344/270/211/346/241/243/350/207/252/346/262/273_/350/256/276/350/256/241_v0.2.md +207 -0
  30. package/md_cg/admission.py +718 -0
  31. package/md_cg/autonomy_modes.py +642 -0
  32. package/md_cg/bench_e2e_locomo_qa.py +11 -4
  33. package/md_cg/chain.py +47 -0
  34. package/md_cg/consistency.py +133 -8
  35. package/md_cg/forgetting.py +38 -6
  36. package/md_cg/freshness.py +527 -0
  37. package/md_cg/generation.py +409 -0
  38. package/md_cg/hotcache.py +4 -1
  39. package/md_cg/lifecycle.py +30 -2
  40. package/md_cg/mcp_server.py +191 -26
  41. package/md_cg/mdcg.py +594 -39
  42. package/md_cg/mdcos.py +869 -38
  43. package/md_cg/nodefile.py +74 -1
  44. package/md_cg/protect.py +79 -4
  45. package/md_cg/provenance.py +1 -1
  46. package/md_cg/review_cli.py +31 -2
  47. package/md_cg/rollback.py +411 -0
  48. package/md_cg/rollback_cli.py +104 -0
  49. package/md_cg/semantic/canonical.py +22 -0
  50. package/md_cg/semantic/unify.py +73 -22
  51. package/md_cg/semantic/unify_fixture.json +25 -0
  52. package/md_cg/sleep.py +1297 -0
  53. package/md_cg/stg.py +400 -50
  54. package/md_cg/stgidx.py +281 -0
  55. package/md_cg/sustain.py +146 -9
  56. package/md_cg/test_auto_defaults.py +424 -0
  57. package/md_cg/test_autonomy_admission.py +1098 -0
  58. package/md_cg/test_autonomy_modes.py +1972 -0
  59. package/md_cg/test_b1_auto_id_multiproc.py +7 -0
  60. package/md_cg/test_b1b2_write_face.py +7 -0
  61. package/md_cg/test_b3_merge_keeps_content.py +7 -0
  62. package/md_cg/test_boundary_hit.py +410 -0
  63. package/md_cg/test_cons200_scan_selection.py +791 -0
  64. package/md_cg/test_en_pipeline.py +22 -13
  65. package/md_cg/test_generation_guard.py +352 -0
  66. package/md_cg/test_h4_sustain_snapshot.py +14 -4
  67. package/md_cg/test_i50a_half_dup_defer.py +408 -0
  68. package/md_cg/test_i50b_defer_to_review_queue.py +545 -0
  69. package/md_cg/test_i50c_meta_passthrough.py +608 -0
  70. package/md_cg/test_i50d_importance_source.py +531 -0
  71. package/md_cg/test_i50e_readside_protection.py +656 -0
  72. package/md_cg/test_issue39_utf8_stdio.py +9 -1
  73. package/md_cg/test_issue52_scan_condition_first.py +677 -0
  74. package/md_cg/test_linkref.py +7 -0
  75. package/md_cg/test_mode_parity.py +1393 -0
  76. package/md_cg/test_mutation_rollback.py +805 -0
  77. package/md_cg/test_n204_n205_n226_n227_n228_n229_exit_gates.py +1 -1
  78. package/md_cg/test_n212_n213_n224_generation_gates.py +14 -8
  79. package/md_cg/test_n214_n215_n221_n222_write_face_gates.py +7 -0
  80. package/md_cg/test_n230_dirty_replay.py +375 -0
  81. package/md_cg/test_p2_mcp.py +8 -0
  82. package/md_cg/test_p2_six_elements.py +463 -0
  83. package/md_cg/test_p3_legacy_closure.py +433 -0
  84. package/md_cg/test_p4_freshness.py +680 -0
  85. package/md_cg/test_p8_subgraph_chain.py +14 -1
  86. package/md_cg/test_p9_forget_protect.py +7 -0
  87. package/md_cg/test_p9c_dedup_hints.py +7 -0
  88. package/md_cg/test_policy_required_ccg.py +5 -1
  89. package/md_cg/test_protocol.py +7 -0
  90. package/md_cg/test_rank_parity_score_mode.py +6 -0
  91. package/md_cg/test_semantic_canonical.py +5 -3
  92. package/md_cg/test_sleep.py +611 -0
  93. package/md_cg/test_sleep_p1.py +784 -0
  94. package/md_cg/test_stgidx_index_parity.py +1020 -0
  95. package/md_cg/test_time_core_lint.py +968 -0
  96. package/md_cg/test_unify_default_off.py +701 -0
  97. package/md_cg/test_unify_scope.py +182 -0
  98. package/md_cg/test_writelimit.py +36 -9
  99. package/md_cg/test_writepipe.py +5 -2
  100. package/md_cg/weights.py +15 -1
  101. package/md_cg/whitebox_kb/aeis_core/time_core.py +8 -0
  102. package/md_cg/writepipe.py +101 -2
  103. package/package.json +3 -2
  104. package/skills/plugin.json +1 -1
  105. package/utf8_boot.py +237 -0
@@ -0,0 +1,439 @@
1
+ # 三档自治 · 步骤③「变更单与回滚原语通用化」——落码记录 v1.0
2
+
3
+ **日期**:2026-10-02 | **批次**:设计 v0.2 步骤③(`docs/plans/记忆自处理三档自治_设计_v0.2.md` §十三.3 落码顺序第 3 条;含 §十一 本批执行项「回滚实测」) | **基线**:HEAD `0960392e`(步骤②「档位单一入口」提交;工作树干净) | **被测面**:本工作树(未提交;基线 HEAD 未变——本轮实读 `git rev-parse HEAD` = `0960392e0886cc046aa80156decf49c4b9b6e12f`)
4
+
5
+ **本报告为本次 ask 唯一写入文件**:除本文件外未写任何工作区文件、未改源码、未 `git add/commit/push`(机械核对见 §7.3)。
6
+
7
+ **v1.0 · 读者反馈轮修订(2026-10-02)**:按读者反馈逐条处置(能补证据的补、能说清的改措辞、误报的说明不改)——新增/订正 15 处:三组键集对照与占位可分辨性(§3.3)· `record_hash` 十键(§7.1)·「三缓存」与 `flush` 落点(§3.4)· 动作分类 A–E 表(§1.1)·「39 键」单位实测(§二)· `L1a2_*` 标签来源(§二)· 栈一 22/38 口径与不跑理由订正、栈二读数边界(§4.4)· 5 处 DIFF 解读(§5.2)· 命令串「首次态」实测(§3.5)· ④ 红项面按逐项 dump 订正为 Q5+R5+S1+T2(§4.2)· 回滚留痕实测与台账措辞订正(§6.1 第 3 条)· 可回滚清单/权限不对称/快照面误读/在役库加密未知(§6.1)· 报告自洽口径订正(§6.2)· B 剥离路径的意义(§3.4 第 3 行)·「P4 附证」按实测改写(§3.4 第 2 行)。本轮新增探针落 `%TEMP%`:`step3_rv_probe.py`、`step3_dump4.py`/`step3_dump4b.py`(库根全在沙箱;`-B` 不写字节码),读数在正文以〔本报告实跑(读者反馈轮)〕标注。
8
+
9
+ **证据分级(沿用本仓 eval 体例)**:
10
+
11
+ - 〔本报告实跑〕=撰写轮亲手执行并计数(守卫正向 / 变异自证 / python 全量 / 读码);
12
+ - 〔工作流采集·实施段实跑〕=实施段在本工作流内实跑、由编排材料原样给到本报告(探针 / CLI 演练 / 定向回归 / 逐字节读数);
13
+ - 〔工作流采集·复现段〕=复现员在**改动前**树上独立取得(§二);
14
+ - 〔工作流采集·复核段〕=独立复核员实跑(§五)。
15
+
16
+ **行号规则**:`HEAD:` 前缀 = 从 `git show HEAD:<文件>` 导出的修前版实读行号;无前缀 = 工作树现版实读行号。两者均为本轮读码;与采集材料原引用(复现腿 site、实施 changes 的 `路径:行`)逐处核对结果见 §1.2 注。**不以 git HEAD 为基线源**(守卫与变异表的基线源=工作区源码+表内锚点,漂移即 `ANCHOR-MISS` + exit 2,fail-closed)。
17
+
18
+ **关联**:上游步骤②(`0960392e`:档位单一入口 + 热路径 B/C/D 出变更单 + 裁决执行桥)——本批在其执行桥上做**执行时点补全**、在其载荷上加三字段;下游步骤④ R1–R4 准入读数(设计 §七)——本批产出的 `_protected_history` 前像 + 实测回滚记录即 R3「破坏可逆且回过」的数据面(留池 §6.1)。同类体例先例:`docs/eval/三档自治_步骤②档位单一入口_落码记录_v1.0.md`。
19
+
20
+ ---
21
+
22
+ ## 一、缺陷定义与真实站点(行号以本轮读码所见为准)
23
+
24
+ ### 1.1 缺陷定义(修前四条;均为设计条款未落,非猜测)
25
+
26
+ | # | 缺陷定义 | 设计真源条款 |
27
+ |---|---|---|
28
+ | **D1** | **变更单三字段缺失**:mutation 载荷只有 7 键(`action`/`action_name`/`target`/`after`/`reason`/`primitive`/`meta`)——无**前像**(执行时点可回滚句柄)、无**影响面**(边/索引条目/聚合行读数)、无**回滚命令**;按设计 §四 取用即 `KeyError`(§二 腿1a–1c 实测) | §四 |
29
+ | **D2** | **受保护快照面未推广**:`_protected_history/<id>/` + `_protected_audit.jsonl` 只对受保护节点生效;非受保护节点的 B 合并 / C 改写 / D 软删**无前像、无审计**(结构性缺失、不抛异常;受保护对照片与三腿见 §二 腿2a-*) | §四 原语① |
30
+ | **D3** | **回滚原语未接统一口径**:`restore` 原语在位且可用,但 `md_cg/autonomy_modes.py` 全文 0 次引用、全仓仅一处文案提及(`HEAD:md_cg/mdcos.py:2555`「trash/ 可 restore」);合并聚合行无「定向剥离」实现(`AGG_MARK` 全仓仅 2 处:定义 + 生成);无统一回滚入口、无回滚命令载体 | §四 原语②③ |
31
+ | **D4** | **回滚实测守卫缺失**:无 B/C/D 任一动作的「落 → 回滚 → 逐字节比对前像」演练,也无「回滚后不得残留(索引/边/聚合行)」红项面 | §十一 |
32
+
33
+ **动作分类 A–E(`md_cg/autonomy_modes.py:81-88` 实读;读者反馈轮补——下文所有「A 类/E 类」均指此表)**:A=新增节点(`A_ADD`,动作名「新增」)· B=合并(新内容并入既有节点,`B_MERGE`)· C=改写(既有节点就地改,`C_REWRITE`)· D=删除(软删,`D_DELETE`)· E=权重/生命周期(`E_WEIGHT`)。本批回滚只覆盖 B/C/D——**E 类**落到 `rollback_action_unknown` fail-closed(§5.2 ①);**A 类**(新增)在 `rollback.preimage:103` 的动作类闸直接返回 None(新增不破坏既有内容、无需前像),§5.2 ① 的「`preimage()` 对 A 类/目标缺失→None」即此两条。
34
+
35
+ ### 1.2 真实站点(修前实读 → 修后实读)
36
+
37
+ | 站点(修前实读) | 修前事实 | 修后落点(工作树实读) |
38
+ |---|---|---|
39
+ | `HEAD:md_cg/autonomy_modes.py:283-296`(唯一构造点;键集 `294-296`) | `mutation_payload` 只产 7 键;`mutation_view:261-279` 同 | 现版 `297-330`(键集 `324-330`);`mutation_view:267-294` 带三键 |
40
+ | `HEAD:md_cg/mdcos.py:2482-2592`(`_mutation_execute` 全函数) | **全函数无快照/前像/影响面采集**;返回体 `2589-2592` 仅 5 键(kind/action/target/primitive/executed) | 现版 `def:2489`;前像拍摄点 `2552-2554`;`PreimageError` fail-closed `2599-2609`(`preimage_unavailable`);补全点 `2633-2637` |
41
+ | `HEAD:md_cg/mdcos.py:2526-2535`(B 执行分支)/ `2536-2559`(C 执行分支,`self.add` `2557-2558`) | 动作直落,前像无处生 | 现版 `2555-2588`(前像在动作**之前**;分支体语义不变) |
42
+ | `HEAD:md_cg/mdcos.py:2555` | 全函数唯一 `restore` 提及=文案 | 现版 `2584` 同款文案;实体引用在现版 `md_cg/rollback.py:309`(`cg.restore(tgt, force=True)`) |
43
+ | `HEAD:md_cg/mdcos.py:2364-2393`(`_record_decision`) | 裁决记录无 `mutation` 键(执行时点载荷无处持久化) | 现版 `2376-2382`(`rec["mutation"]`;`proposal` 链无该键、rec 形状逐位不变;`record_hash` 十键定义见 §7.1) |
44
+ | `HEAD:md_cg/mdcos.py:2895-2916`(`_forget_apply`) | 软删执行体无快照 | 现版 `2940-2961`(本体未动;前像由执行桥在调用**前**拍) |
45
+ | `HEAD:md_cg/mdcos.py:2964-3024`(`restore` 本体) | 原语在、可用;无任何统一口径引用 | 现版 `3009-3069`(本体未动;被 `rollback._rollback_delete` 消费) |
46
+ | `HEAD:md_cg/protect.py:215-245`(`snapshot`)/ `262-265`(`_allow`) | 快照仅由 `_allow` 的 override 路径与工具面 `md_cg/mcp_server.py:1223-1224` 调用 | 现版 `snapshot` `215-245` **一字未动**;新入口 `snapshot_preimage` `248-295` |
47
+ | `HEAD:md_cg/forgetting.py:84`(`AGG_MARK = "聚合"`)/ `380-414`(`aggregate_line`,生成行 `412`) | 聚合行只能生成,**无剥离/回退实现** | 现版同(未动);剥离在 `md_cg/rollback.py:182-215`(`strip_aggregate_lines`) |
48
+ | `md_cg/test_mutation_rollback.py` | **不存在**(腿3 实测 `os.path.exists=false`) | 新增 805 行:P/Q/R/S/T 五组 59 断言 + 8 处定点变异(`_SRC_MUTATIONS:607`) |
49
+ | `HEAD:md_cg/test_autonomy_modes.py:265` | 全文件「前像」仅 2 次、同一行注释(「前像式核对」,非断言) | 现版 `:273` 同注释;新增 K 组(`828-830` 起,12 断言)+ 变异 ⑮⑯(`_SRC_MUTATIONS:936`) |
50
+
51
+ **注**:采集材料原引用与本轮实读逐处一致——`autonomy_modes.py:294`(键集)、`283-296`(构造点)、`mdcos.py:2589-2592`(返回体)、`2482-2592`(全函数)、`2526-2535`/`2557-2559`/`2555`、`2895-2916`(`_forget_apply`)、`2964-3024`(`restore`)、`protect.py:215-245`/`:263`、`forgetting.py:84`/`380-414`、`test_autonomy_modes.py:265`、`mcp_server.py:1224`(工具面 snapshot 调用点,现版 `1223-1224`)。
52
+
53
+ ### 1.3 修前形态一句话
54
+
55
+ 前像/影响面/回滚命令**键不存在**(按设计取用即 `KeyError`);B/C/D 三动作执行后**零前像零审计**(受保护节点对照有——同一覆写动作在 self 层生成快照 + 双条审计);`restore` 与聚合行剥离**未接线**;回滚守卫**不存在**——即「回滚」只存在于设计文本,工程面上无落点。
56
+
57
+ ---
58
+
59
+ ## 二、修前现场(〔工作流采集·复现段〕;逐条 payload/异常/崩溃点)
60
+
61
+ **来源与边界(如实)**:以下腿由本工作流「缺陷复现员」在**尚未改动的**树上独立复现(全部 `reproduced=true`),交本报告原样引用。实验库根一律系统临时目录合成库(脚本 `C:\Users\test\AppData\Local\Temp\step3_repro_5l5jydkg\repro_step3.py` 与 `repro_step3b.py`——本轮实读两文件仍在案)。「仅用临时目录」自证:全部库根在 `%TEMP%\step3_*`(5 个实验根共 37+ 文件,全为合成库);实验前后 `git status --porcelain` 仅 `?? .zcode/`(会话起始既有)、`git diff --stat` 空、HEAD 仍 `0960392e`——工作区零改动。
62
+
63
+ **读数标签说明(读者反馈轮补)**:腿 1a 的实验分**两段脚本**——第一段 `repro_step3.py`(标签 `L1a_*`);第二段 `repro_step3b.py`(文件内段落标题原样为「#### LEG 1a2: C 改写 —— 三字段 KeyError + 提议/执行双时点 + 队列原文 ####」,标签 `L1a2_*`)。即 **`L1a2_*` =「腿 1a 的第二脚本」读数**(同腿续测:双时点与 inbox 原文);腿 1c 引用的 `L1a2_REC_*`(inbox 原始记录读数)即该第二脚本产出——腿编号与标签前缀不一致点在此说明,非另一批次。
64
+
65
+ ### 腿 1a · 变更单「前像(可回滚句柄,执行时点)」缺失——C 改写
66
+
67
+ - **payload**:confirm 档(`MDCG_AUTONOMY=confirm`)合成库(tempfile 沙箱 lib_c/lib_c2):`cg.add('c_1','PASSED 探针正文 初版')` 后 `pipe.execute(cg, {content_kind:'text', content:'PASSED 探针正文 改写版', layer:'knowledge', node_id:'c_1'})` 出 C 变更单 → 提议与 accept 之间第三方覆写 c_1 为「第三方版」→ `cg.review_decide(pid,'accept')`。
68
+ - **异常/崩溃点**:载荷键集实测 `['action','action_name','after','meta','primitive','reason','target']`(无 before/before_image/pre_image/snapshot)——**按设计 §四 从载荷取前像句柄 ⇒ `KeyError: 'before'`**;执行桥返回 mutation 键集 `['action','executed','kind','primitive','target']`(无前像)。
69
+ - **后果读数**:accept 后 c_1 为「改写版」,第三方版被**无痕覆写**,无任何可回滚句柄(`lib_c/_protected_history` isdir=False、`_protected_audit.jsonl` exists=False)。时点实测:出单时点目标仍旧(`L1a2_AT_PROPOSE_STILL_OLD=true`)、执行确认发生在 accept 时点(`L1a2_AT_EXEC_IS_THIRD_PARTY=true`)、执行覆写第三方(`L1a2_EXECUTED_OVERWRITES_THIRD_PARTY=true`)——「回滚本变更而非第三方改动」语义**无任何落点**。
70
+ - **site**:`md_cg/autonomy_modes.py:294`(mutation_payload 键集);`md_cg/mdcos.py:2589-2592`(`_mutation_execute` 返回体;全函数 2482-2592 无快照/前像采集)。`reproduced=true`。
71
+
72
+ ### 腿 1b · 变更单「影响面(执行时点读数:边/索引条目/聚合行)」缺失
73
+
74
+ - **payload**:同腿1a 的 C 覆写流程(库 lib_c),并在执行时点由探针自采三类读数(索引条目 / frontmatter.edges / 聚合行计数)。
75
+ - **异常/崩溃点**:载荷与执行体均无 `impact`/`impact_scope`/`readings` 字段(`L1b_PAYLOAD_IMPACT_FIELD=false`、`L1b_EXEC_MUTATION_IMPACT_FIELD=false`)——**按设计取影响面字段 ⇒ `KeyError: 'impact'`**;执行时点三类读数**实际可采**(`L1b_AT_EXEC_INDEX_ENTRY_KEYS` 读数=该节点**单个索引条目含 39 个键**——单位核实见下;`edges=[]`;聚合行 0 行)——「可采而未采」结构性缺失,无异常抛出。
76
+ - **单位核实(读者反馈轮补)**〔本报告实跑(读者反馈轮)〕:合成库建普通 knowledge 节点后实测 `len(cg.index["nodes"]["a_1"]) == 39`(键清单:`access_count, branch_id, branched_from, bucket, bucket_zh, content_hash, content_kind, created_at, depends_on, derived_from, derived_relation, edges, effective_from, effective_until, harness, has_neg_conditions, immutable, importance, importance_source, last_access, layer, lifecycle_state, path, postcondition_terms, protected, protection_reason, rejection_terms, self_state, session, spatial, subgraph, tags, temporal, time_window, valid_from, valid_until, verification_basis, verification_state, writer`)——「39 键」= **单个节点的索引条目键数**(不是全库条目数)。
77
+ - **site**:`md_cg/mdcos.py:2589-2592`;`md_cg/autonomy_modes.py:283-296`。`reproduced=true`。
78
+
79
+ ### 腿 1c · 变更单「回滚命令(可执行命令串)」缺失
80
+
81
+ - **payload**:同腿1a;另读**原始队列记录** `lib_c2/hippocampus/inbox.jsonl` 中 pid 对应记录全文(第二来源,不止 `review_list` 视图)。
82
+ - **异常/崩溃点**:载荷/队列槽/执行体均无 `rollback`/`rollback_cmd`/`undo` 字段——**按设计取回滚命令 ⇒ `KeyError: 'rollback_cmd'`**;原始队列记录 JSON 全文 `before/rollback/impact` 计数 = **0/0/0**(`L1a2_REC_MENTIONS_*`);`_mutation_execute` 源码 `'rollback'` 0 次、`'before'` 0 次;队列槽键集与载荷同为 7 键(`L1a2_REC_SLOT_KEYS`)。
83
+ - **site**:`md_cg/autonomy_modes.py:283-296`(唯一构造点);`md_cg/mdcos.py:2482-2592`。`reproduced=true`。
84
+
85
+ ### 腿 2a-B · 受保护快照面未推广——B 合并(非受保护节点)无快照/无审计
86
+
87
+ - **payload**:合成库 lib_b:`cg.add('m_1', BODY%'9090', layer='knowledge')` → `cg.remember_gated('m_n1', BODY%'9595')` 出 B 变更单(`moved_to=review_queue`)→ `cg.review_decide(pid,'accept')` 执行 `forgetting.reinforce`。
88
+ - **异常/崩溃点**:accept 执行成功(ok=true、新值 9595 落盘、聚合行生成),但 `lib_b/_protected_history` isdir=False、`_protected_audit.jsonl` exists=False——**无快照、无审计**;无异常抛出(结构性缺失)。
89
+ - **site**:`md_cg/mdcos.py:2526-2535`(B 执行分支);`md_cg/forgetting.py:488-558`(reinforce 不调 protect.snapshot);`md_cg/protect.py:215-245` 与 `:263`(snapshot 仅由 `protect._allow` 的 override 路径与 `mcp_server.py:1224` 工具面调用)。`reproduced=true`。
90
+
91
+ ### 腿 2a-C · 受保护快照面未推广——C 改写(与受保护节点对照)
92
+
93
+ - **payload**:同腿1a(lib_c:非受保护 knowledge 节点 c_1 覆写);对照片 lib_p:self 层节点 p_1 二次 `cg.add(..., override=True)` 覆写。
94
+ - **异常/崩溃点**:非受保护 C 覆写:`lib_c/_protected_history` isdir=False、`_protected_audit.jsonl` exists=False;**对照片(受保护 self 层,同一覆写动作)**:`lib_p/_protected_history/p_1/20261002-194013.md` 生成(内容=旧版全文)且 `_protected_audit.jsonl` actions=`['snapshot','override_write']`——快照面**只对受保护节点生效**,C 未推广。
95
+ - **site**:`md_cg/mdcos.py:2557-2559`(C 执行分支 `self.add`);`md_cg/protect.py:269-281`(`guard_write` 仅在受保护命中时 `_allow`→snapshot)。`reproduced=true`。
96
+
97
+ ### 腿 2a-D · 受保护快照面未推广——D 软删(非受保护节点)无快照/无审计
98
+
99
+ - **payload**:合成库 lib_d:`cg.add('d_1', BODY%'7070')` → `cg.forget_gated('d_1')` 出 D 变更单 → `cg.review_decide(pid,'accept')` 执行软删(`_forget_apply`)。
100
+ - **异常/崩溃点**:软删成功(`cg.get('d_1')` is None、`trash/d_1.md` 在、`_deletions.jsonl` 1 条),但 `lib_d/_protected_history` isdir=False、`_protected_audit.jsonl` exists=False——非受保护节点删除不发生快照;无异常抛出(结构性缺失)。
101
+ - **site**:`md_cg/mdcos.py:2895-2916`(`_forget_apply` 无快照);`md_cg/protect.py:285-293`(`guard_forget` 仅在受保护命中时 `_allow`→snapshot)。`reproduced=true`。
102
+
103
+ ### 腿 2b · 软删 restore 原语在、但未接统一回滚口径
104
+
105
+ - **payload**:lib_d/lib_d2:D 变更单 accept 执行软删后 `cg.restore('d_1')`(无 force)与 `cg.restore('d_1', force=True)`;并读全仓引用面。
106
+ - **异常/崩溃点**:**对照片**:restore 无 force 返回 `{'ok': false, 'error': 'tombstoned', 'reason': '探针'}`、force=True 返回 ok=true 且节点复活(原语在且可用);**缺陷面**:`autonomy_modes.py` 全文 `'restore'` 0 次、`_mutation_execute` 仅 1 处 `'restore'` 且为文案(`mdcos.py:2555`)、变更单载荷无回滚命令字段——restore **未被任何统一回滚口径引用**(`review_cli` 子命令仅 list/stats/accept/reject/edit/merge/rounds,无 rollback/undo/restore)。
107
+ - **site**:`md_cg/mdcos.py:2964-3024`(restore 本体);`md_cg/autonomy_modes.py:283-296`(0 处 restore);`md_cg/mdcos.py:2555`(唯一提及为文案)。`reproduced=true`。
108
+
109
+ ### 腿 2c · 合并聚合行「定向剥离回退」缺失(AGG_MARK 面)
110
+
111
+ - **payload**:lib_b:合并前正文 body0(不含 9595),B 单 accept 执行后 body1(含聚合行);全仓 `AGG_MARK` 引用面 grep。
112
+ - **异常/崩溃点**:`L2c_BODY1_STARTS_WITH_BODY0=true`、聚合行实测为 `- 【聚合 10-02 19:40】…指标面监听端口 9595/HTTP…`;全仓 `AGG_MARK` 仅 2 处(`md_cg/forgetting.py:84` 定义、`:412` 生成),**无剥离/回退实现**;`dir(forgetting)` 中 strip/rollback/undo/revert 函数为空表;`forgetting.py` 全文『定向剥离/剥离回退/unmerge』0 次——合并后的正文无定向剥离回退路径(唯一回退只能是受保护快照,而 B 不生成快照,见腿2a-B)。
113
+ - **site**:`md_cg/forgetting.py:84`、`380-414`。`reproduced=true`。
114
+
115
+ ### 腿 3 · 回滚实测守卫缺失(§十一「落→回滚→逐字节比对前像」未落;含红项面缺失)
116
+
117
+ - **payload**:文件级探针:`md_cg/test_mutation_rollback.py` 存在性;grep 现有守卫与全仓测试面;运行 `python -X utf8 -m md_cg.test_autonomy_modes` 记录基线。
118
+ - **异常/崩溃点**:`os.path.exists(md_cg/test_mutation_rollback.py)=false`(无回滚面守卫文件);`test_autonomy_modes.py` 中『影响面』『回滚命令』『rollback』『逐字节』计数全为 0,唯一『前像』2 次均在同一行注释(`HEAD:md_cg/test_autonomy_modes.py:265`「前像式核对」,非断言);全仓无 B/C/D「落→回滚→逐字节比对前像」演练,也无『回滚后不得残留(索引/边/聚合行)』红项面。**基线实测**:`python -X utf8 -m md_cg.test_autonomy_modes` → `EXIT_CODE=0`、输出『三档自治档位守卫:126 通过,0 失败』(grep 计数 126 PASS / 0 FAIL 复核一致)——126 断言绿为改动前参照面(该基线日志在案:`%TEMP%\step3_repro_5l5jydkg\guard_baseline.log` 尾部「126 通过,0 失败」,本轮实读)。
119
+ - **site**:`md_cg/test_mutation_rollback.py`(不存在);`md_cg/test_autonomy_modes.py:265`。`reproduced=true`。
120
+
121
+ ### 附 · 对照片与边界自证(受保护快照既有行为基线、仅临时目录、工作区零改动)
122
+
123
+ - **受保护快照既有行为实测(改动前基线)**:快照文件 `_protected_history/p_1/20261002-194013.md`(旧版全文)+ `_protected_audit.jsonl` actions=`['snapshot','override_write']`。
124
+ - **自证**:全部库根在 `C:\Users\test\AppData\Local\Temp\step3_*`(`SANDBOX_UNDER_TEMP=true`,5 个实验根共 37+ 文件全为合成库);实验后 `git status --porcelain` 仅 `?? .zcode/`(会话起始既有,非本批产物)、`git diff --stat` 空、HEAD 仍 `0960392e`——工作区零改动、未 `git add/commit/push`。
125
+ - **边界说明**:本报告文件当时未创建——复现段硬边界「不得编辑工作区任何文件」优先,该路径属落码阶段交付面;另跑守卫后 `%TEMP%` 残留 6 个 `autonomy_modes_sandbox_*`(合成库、非在役数据,测试自身已知留池)。
126
+ - **site**:`md_cg/protect.py:215-245`、`262-265`;`md_cg/test_autonomy_modes.py:126`(基线)。`reproduced=true`。
127
+
128
+ ---
129
+
130
+ ## 三、修法契约与落点
131
+
132
+ ### 3.1 交付三件与落点总表(修后 = 工作树实读)
133
+
134
+ | # | 契约项 | 落点(工作树实读) | 状态 |
135
+ |---|---|---|---|
136
+ | 1 | **变更单字段完备**:mutation 载荷补三字段——`before`(前像=**执行时点**快照引用)· `impact`(执行时点影响面:边/索引条目/聚合行)· `rollback`(可执行回滚命令串) | `md_cg/autonomy_modes.py`:`mutation_payload:297-330`(键恒在,提议时点占位 None/None/`""`)、`mutation_view:267-294`(同口径)、`mutation_executed:333-352`(执行时点补全唯一构造点);`md_cg/mdcos.py`:`_mutation_execute` 前像点 `2552-2554`、补全返回 `2633-2637`;`_record_decision` `2376-2382`(落 `decisions.jsonl` 的 `rec["mutation"]`) | 已落 |
137
+ | 2 | **回滚原语通用化(§四 四条)**:快照面从「仅受保护节点」推广为**一切 C/D/B 动作**(同面复用、语义泛化);软删 trash+restore 接进统一口径;合并聚合行定向剥离;分数类不属本批 | `md_cg/protect.py:248-295`(`snapshot_preimage` 新入口;既有 `snapshot`/`history`/`_allow`/`guard_*` **一行未改**)+ `md_cg/rollback.py`(统一回滚入口)+ `md_cg/rollback_cli.py`(命令载体) | 已落 |
138
+ | 3 | **回滚实测(§十一)**:B/C/D 每种破坏性动作各演一次「落 → 回滚 → 逐字节比对前像」;C 覆盖「目标被覆写后回滚」;含红项面「回滚后不得残留(索引/边/聚合行都要回)」 | 守卫 `md_cg/test_mutation_rollback.py`(805 行、59 断言:P 前像面 / Q C 改写 / R B 合并 / S D 删除 / T 单点与边界);回滚命令串经 **subprocess 实测演练**(不是进程内直调) | 已落 |
139
+
140
+ ### 3.2 契约偏离声明(两处,均为探针实测后的决定,未绕开)
141
+
142
+ 1. **三字段实值落 `decisions.jsonl` 的 `rec["mutation"]`**:三字段的**键面**在 `mutation_payload`(唯一构造点,提议时点即占键、取值 None/`""`;「执行时点填充」的**明示出处**=该函数 docstring `autonomy_modes.py:301-314` 与键面注释 `:327-329`:「执行时点三字段(键恒在;提议时点 = 未执行,占位 None/'')」;消费者可分辨性见 §3.3 末);**执行时点实值**由执行桥补全并经 `_record_decision` 落进裁决记录——inbox 条目是 append-only(`mdcos.propose` 落盘后不可原地改),补全形态只能随裁决记录持久化。契约原文「落点:autonomy_modes.mutation_payload + mdcos._mutation_execute(探针后定)」按此理解实现。
143
+ 2. **D 回滚 = 「restore + 前像校准」而非纯 restore**:探针实测 restore 的 add 全量重建与原件**不逐字节**(多 `sensitivity: null` 键,见 §3.6 P4);契约要求「回滚后逐字节比对前像」,故 restore 消费 trash/删除清单之后,按前像校准一次;`restore_bytes_equal=False`、`calibrated=True` 读数**如实返回**(不假装 restore 本身逐字节)。
144
+
145
+ ### 3.3 三字段结构与执行时点语义
146
+
147
+ ```text
148
+ mutation_payload(...) → { # 提议时点(extra.mutation,随 inbox 落盘)
149
+ action, action_name, target, after, reason, primitive, meta,
150
+ before: None, # 执行时点快照引用;提议时点不拍(设计 §四:回滚只撤销本变更)
151
+ impact: None, # 执行时点影响面;None = 未执行
152
+ rollback: "", # 可执行回滚命令串;"" = 未执行
153
+ }
154
+ 执行桥 accept(动作落盘之前):
155
+ preimage() → {before: "_protected_history/<id>/<ts>-<微秒>.md",
156
+ impact: {edges:{declared,children,parents},
157
+ index:{present,path,layer,importance,merge_count,
158
+ protected,tags},
159
+ agg_lines:[行号…]},
160
+ rollback: 'python -X utf8 -m md_cg.rollback_cli --root "<root>" --pid <pid>'}
161
+ mutation_executed(slot, before, impact, rollback) # 唯一补全点:载荷 10 键 + kind + executed(=12 键,见下表)
162
+ → 返回体 result["mutation"] → _record_decision → decisions.jsonl rec["mutation"]
163
+ ```
164
+
165
+ - **前像=执行时点**(设计 §四 明文):提议时点**不拍**。从提议到 accept 之间目标可能被第三方改动——回滚必须撤销**本变更本身**。判据双证:守卫 Q 场景把「第三方覆写后回滚到第三方版本」演出来;T 组「预置最旧快照」判别场景——实现若取最旧快照(≈提议时点语义)立即转红(变异 ② 实测红 2)。
166
+ - **快照面复用决策(探针后定)**:**复用** `_protected_history/<id>/` + `_protected_audit.jsonl`(面复用、语义泛化),不新建平行面——受益:§七 R3 读数(「存在实测回滚记录」)与 §九 台账天然以该面为数据源;约束:**受保护节点既有快照行为一字不变**——`snapshot()`/`guard_*`/`_allow`/`history()` 一行未动,前像是**新入口** `protect.snapshot_preimage`(差别仅两处:文件名带微秒后缀 `%Y%m%d-%H%M%S-%06d` 防同秒互踩;审计 `action="preimage"` 且 reason 交代动作类/pid)。
167
+ - **执行桥时序**:`_mutation_execute` 在动作原语落盘**之前**调 `rollback.preimage`(唯一采集点);目标在位而拍摄失败 ⇒ `PreimageError` ⇒ `preimage_unavailable` **fail-closed**(不执行、不落裁决、提案保持 pending)。
168
+ - **三组键集对照(读者反馈轮补;〔本报告实跑(读者反馈轮)〕C 场景合成库实测——消费者可据此写读码)**:
169
+
170
+ | 层 | 键集(键数) | 实测读数标签 |
171
+ |---|---|---|
172
+ | 提议时点载荷(`mutation_payload`;随 inbox 落盘) | `action, action_name, after, before, impact, meta, primitive, reason, rollback, target`(**10**) | `B_PAYLOAD_KEYS` |
173
+ | 执行时点载荷(accept 返回体 `result["mutation"]`;执行桥经 `mutation_executed` 补全) | 上 10 键 + `executed` + `kind`(**12**) | `B_EXEC_MUTATION_KEYS` |
174
+ | `decisions.jsonl` 的 `rec["mutation"]` | 与执行时点载荷**同 12 键** | `B_REC_MUTATION_KEYS` |
175
+ | `rec["result"]`(裁决记录内) | 仍只 `ok/node_id/error/state` 白名单子集(本次实测 `{ok, node_id}`) | `B_REC_RESULT_KEYS` |
176
+
177
+ 补全语义(`autonomy_modes.py:343-352` 实读):`out = dict(payload)` 逐键复制 → 补 `kind`/`executed` → 仅在实参非 None/非空时覆写 `before`/`impact`/`rollback`(不把 None 伪装成实值);**原载荷不原地改**(「提议时点载荷」与「执行时点载荷」两个事实都保留)。
178
+ - **占位可分辨性(读者反馈轮补)**:提议时点与执行时点由**键面**即可判别——`before: None`/`impact: None`/`rollback: ""`(提议)对 `str`/`dict`/非空 `str`(执行后);且 `executed` 布尔键**只出现在执行时点载荷**(提议载荷无该键,实测两键集差恰为 `{executed, kind}`)。「明示」出处见 §3.2①。
179
+
180
+ ### 3.4 回滚原语四条落点(设计 §四)
181
+
182
+ | # | 原语 | 落点与形态(工作树实读) |
183
+ |---|---|---|
184
+ | 1 | 受保护快照面推广为一切 C/D/B | `protect.snapshot_preimage(cg, node_id, action, pid)` `:249`(写同一面、同一 `_write_node` 序列化);执行桥在动作前经 `rollback.preimage:90` 调用(唯一采集点) |
185
+ | 2 | 软删:trash + 删除清单 restore | `rollback._rollback_delete:308`:`cg.restore(force=True)`(既有原语)→ 前像校准(`_land:219` 重写 fm+正文、索引条目 `_node_entry` 同源重算、**三缓存**=`subgraph`/`chain`/`trust` 三个反查缓存失效,`rollback.py:235-237`)→ 读数 `calibrated/restore_bytes_equal/replayed` 如实;`os.replace` 搬进 trash 的原件即字节级前像(**读者反馈轮实测**:`trash/d_1.md` 与执行时点前像文件**逐字节相同**,读数 `D_TRASH_BYTES_EQ_PREIMAGE=true`;另见 P4:restore 重建 ≠ 原件) |
186
+ | 3 | 合并:聚合行定向剥离 | `rollback.strip_aggregate_lines:182`:**前缀 + 追加段**判据(合并原语是追加式的)——逐段剥掉「`\n` + 含 `forgetting.AGG_MARK` 的非空行」,收尾剥净「追加段纯换行尾」(P7);非追加式形态不手术(返回原样+空剥离表)。B 回滚正文取剥离结果(`stripped_ok=True` 时逐字节==前像),fm **全量取前像**(merge_count/last_merge_at/importance(+0.05 可被 1.0 截断)/merge_sources/protected/lifecycle_state 均不可逆)。**为什么不是直接整段取前像(读者反馈轮补)**:回滚正文的最终判据始终是「== 前像」——`stripped_ok=False` 时正文**直接取前像**(退化路径,§6.1 第 8 条);strip 承担的是设计 §四 明文要求的「定向剥离」原语本身与**可判别读数**(`removed_lines` 逐行列出被剥聚合行,使「合并追加的恰是这几行」可独立核对),并把部分剥离/非追加形态转成显式读数而非静默兜底 |
187
+ | 4 | 分数类(E 权重/生命周期) | **不属本批**(设计 §四 明文「各模块既有 rollback」);留池 §6.1 |
188
+
189
+ 其余结构单点:`rollback.command_for:75`(命令串唯一构造点);`rollback.rollback_mutation:356`(统一入口:C/B/D 分派 + 残留核对 + 逐字节比对 + `flush`——**`flush` 的落点(读者反馈轮补)**=**索引增量日志**(`_dirty → ShardedLog(index_log_dir) append`,`mdcg.py:1794-1817`):节点盘面由 `_write_node`/`restore` 直接写文件,`flush` 只保证「索引条目」这一持久面与盘面同代);失败语义一律 fail-closed(`mutation_missing` / `rollback_gap` / `rollback_action_unknown` / `preimage_missing` / `preimage_unreadable`);`rollback_cli.py`(`_root:48` / `_mutation_record:59` / `main:73`)——未执行(reject/fail-closed/pending)或无 `rec["mutation"]` ⇒ `decision_not_found` 非零退出(不许凭空猜一个前像)。
190
+
191
+ ### 3.5 回滚命令形态与 CLI 实测输出〔工作流采集·实施段实跑 + 本报告实跑(读者反馈轮:首次态)〕
192
+
193
+ **形态**(载荷 `rollback` 字段原文,取自 C 场景实跑):
194
+
195
+ ```text
196
+ python -X utf8 -m md_cg.rollback_cli --root "C:\Users\test\AppData\Local\Temp\demo_report_cufa4jho\c" --pid prop_064741eabc17
197
+ ```
198
+
199
+ **CLI 实测输出**(同场景 subprocess 实跑,`rc = 0`):
200
+
201
+ ```json
202
+ {"ok": true, "action": "C", "target": "c_1",
203
+ "preimage": "_protected_history/c_1/20261002-213017-609587.md",
204
+ "rollback_command": "python -X utf8 -m md_cg.rollback_cli --root \"…\\c\" --pid prop_064741eabc17",
205
+ "actor": "rollback-cli", "bytes_equal_preimage": true,
206
+ "residual": {"agg_lines_restored": true, "edges_restored": true, "index_restored": true},
207
+ "restored_path": "knowledge/orphan/c_1.md", "method": "preimage"}
208
+ ```
209
+
210
+ - CLI 读回链:`decisions.jsonl` 找 pid 最后一条 `accept` 记录 → `rec["mutation"]`(执行时点载荷)→ 统一入口。
211
+ - **实测演练方式**(守卫内):`shlex.split(cmd, posix=False)`(Windows 路径反斜杠在 posix 模式会被当转义)+ 剥引号 + 首令牌 `python` 换 `sys.executable` + `subprocess.run(shell=False, encoding="utf-8")`——演练的是**字段里那条命令串本身**(只在解释器令牌上等价替换)。
212
+ - 每个动作的**首次**回滚都经**进程内统一入口**(判据可被定点变异打到),CLI 随即做**幂等重放**——该段代码注释原文为「命令串实测演练(CLI subprocess;**此刻为幂等重放**)」(`test_mutation_rollback.py:363`);即**守卫内**命令串演练验证的是**重放态**。**「命令串在未回滚的首次态可执行」由本轮实测单独实证**〔本报告实跑(读者反馈轮)〕:C 场景 accept 后**不做**任何进程内回滚、直接执行载荷里的命令串 ⇒ `rc=0`、`ok=true`、`bytes_equal_preimage=true`、`method=preimage`;D 场景同法 ⇒ `rc=0`、`method=restore+preimage_calibration`、`replayed=false`、`calibrated=true`、`restore_bytes_equal=false`(首刀校准读数的首次态样本)。两场景随后重放均 `rc=0`。
213
+
214
+ ### 3.6 探针读数(〔工作流采集·实施段实跑〕;合成库 · `tempfile.mkdtemp` · 不触在役数据)
215
+
216
+ | 探针 | 读数 | 结论 |
217
+ |---|---|---|
218
+ | P1 `protect.snapshot()` 对普通节点 | 可用:写 `_protected_history/<id>/<ts>.md`、内容与节点盘面**逐字节相同**、audit `('snapshot','显式快照(rel)',rel)`;**同秒二次快照互踩**(返回同一路径、文件数=1) | 快照面可直接复用;秒级命名在同秒多次拍摄时会覆盖——前像入口必须另加去重熵 |
219
+ | P2 快照 → `cg._write_node` 回写 | 与快照分**逐字节相同**;被覆写后再从旧快照恢复 → 逐字节相同 | 「从快照恢复」机制成立(非加密库) |
220
+ | P3 `reinforce` 合并后 → 快照恢复 | 逐字节相同 | B 的回滚有快照级兜底 |
221
+ | P4 D 软删 → `restore(force=True)` | **重建 ≠ 原件**:diff 定位为**多一行 `sensitivity: null`**(restore 显式传 `sensitivity=None` 经 add 的 `**extra` 落 fm;原文件无该键) | D 回滚需要前像校准(§3.2 偏离②) |
222
+ | P5 执行桥时点 | 出单时目标未被改;**accept(`review_decide`)才执行**;裁决 rec 的 `result` 当时只保留 ok/node_id/error/state | 前像=「执行时点」的采集位点确定在 `_mutation_execute` 动作落盘前;补全形态需要新落点(`rec["mutation"]`) |
223
+ | P6 边读数路径 | `fm.edges`(声明式)经 `subgraph.parents_index/children_index` 聚合(缓存可失效);`add` 全量重建 fm 会把未显式传入的 `edges` 清空(既有行为) | 影响面的「边」面取 `children/parents/declared` 三读数;C 回滚的「边恢复」是可判别判据 |
224
+ | P7 `nodefile.dumps` | `:313` 给不以换行结尾的正文**补一个尾换行**(读回多出该换行) | 剥离函数必须剥净「追加段纯换行尾」,否则 `stripped_ok` 恒 False(实施中发现并修正) |
225
+
226
+ ### 3.7 逐字节比对读数(§十一「落 → 回滚 → 逐字节比对前像」)〔工作流采集·实施段实跑〕
227
+
228
+ | 动作 | 场景(守卫组) | 落(accept 执行) | 回滚读数 | 逐字节比对前像 |
229
+ |---|---|---|---|---|
230
+ | **C 改写** | Q 组:出单 → **第三方覆写** → accept → 回滚 | 正文=改写版;声明式边被 `add` 全量重建清空(既有行为) | `method=preimage`;`residual` 三面 True;索引条目==前像重算条目(逐位) | **== 执行时点前像**(=第三方版本字节);`!=` 提议时点初版(「初版」不在回滚后正文) |
231
+ | **B 合并** | R 组:`remember_gated` MERGE → accept → 回滚 | 聚合行已追加、`merge_count=1` | `method=strip_aggregate_lines`;`stripped_ok=True`;`removed_lines` 恰 1 行(本次聚合行);fm 回退(merge_count→无、importance→0.5) | **== 前像**(合并前正文,含写盘尾换行口径) |
232
+ | **D 删除** | S 组:`forget_gated` → accept → 回滚 | 节点离位、trash 原件在案、删除清单在案 | `method=restore+preimage_calibration`;`restore_bytes_equal=False`(如实:restore 重建多 `sensitivity:null`);`calibrated=True`;幂等重放 `replayed=True` | **== 前像**(校准后;盘面 vs 快照文件二进制比对) |
233
+
234
+ **残留核对(红项面)**:三组回滚的 `residual` 三键(`agg_lines_restored` / `edges_restored` / `index_restored`)全 True——聚合行剥净、`part_of` 父边回案(Q 组:覆写清空 → 回滚恢复)、索引条目与「前像文件重算条目」逐位相等(`_node_entry` 与 `_scan_nodes` 同源单点)。
235
+
236
+ ---
237
+
238
+ ## 四、验证数字
239
+
240
+ ### 4.1 守卫正向〔本报告实跑〕
241
+
242
+ ```text
243
+ python -X utf8 -m md_cg.test_mutation_rollback → 59 通过,0 失败;exit 0;首行「锚点自检:PASS(test_mutation_rollback.py;不以 git HEAD 为基线源)」
244
+ python -X utf8 -m md_cg.test_autonomy_modes → 138 通过,0 失败;exit 0;首行「锚点自检:PASS(test_autonomy_modes.py;不以 git HEAD 为基线源)」
245
+ ```
246
+
247
+ - 新守卫 59 断言(P 14 / Q 15 / R 11 / S 9 / T 10——分组计数以输出行计,合计 59 复核一致);扩展套件 138 断言(原 126 → +K 组 12)。
248
+ - 输出文件在案:`%TEMP%\step3_mutroll_plain.txt` / `%TEMP%\step3_automodes_plain.txt`(本轮实跑落盘)。
249
+
250
+ ### 4.2 变异自证〔本报告实跑〕
251
+
252
+ ```text
253
+ python -X utf8 -m md_cg.test_mutation_rollback --mutate → PASS;未变异基线红项=0;8 处逐处「命中预期」;exit 0
254
+ python -X utf8 -m md_cg.test_autonomy_modes --mutate → PASS;未变异基线红项=0;16 处逐处「命中预期」;exit 0
255
+ ```
256
+
257
+ **新守卫 8 处(红项数=本轮实跑读数)**:
258
+
259
+ | # | 变异(把判据赖以成立的实现打坏) | 红项数 | 红项面 |
260
+ |---|---|---|---|
261
+ | ① | 执行桥不拍前像(执行时点前像整支失效) | **30** | P3 + Q12 + R7 + S6 + T2(三动作「前像在案/回滚成功/逐字节/残留/命令串演练」整体转红) |
262
+ | ② | 前像取最旧快照(≈提议时点语义回归) | **2** | T 组时点判别两条 |
263
+ | ③ | 定向剥离恒等空转(`strip_aggregate_lines` 不剥) | **1** | R「走定向剥离且剥离精确」(stripped_ok/method/removed 三条件同挂一条) |
264
+ | ④ | 回滚不落盘(`_land` 空转) | **13** | Q5 + R5 + S1 + T2(逐字节/残留/盘面/索引对拍/边恢复/时点判别——本轮逐项 dump 实测,见下) |
265
+ | ⑤ | D 回滚不做前像校准(restore 字节差残留) | **2** | S「读数如实」+ S「回滚后盘面逐字节==前像」 |
266
+ | ⑥ | 受保护路径被污染(`_allow` 多拍前像) | **4** | P 组「guard 快照恰好 1 张」等四条(受保护既有行为被判据钉死) |
267
+ | ⑦ | 前像名去微秒(同秒互踩) | **4** | P 组「同秒两次=两个文件」「各拍各自时点」「命名形态判别」等 |
268
+ | ⑧ | 执行记录不落 mutation(`rec["mutation"]` 摘除) | **3** | Q/R/S 三条「命令串实测演练」(CLI `decision_not_found` 非零退出;进程内入口不受影响——语义相符) |
269
+
270
+ > **④ 红项面订正(读者反馈轮)**:原稿枚举「Q5 + R4 + S4」与删断言探针实测(删 S 组后 13→12,差 1)不自洽——按逐项 dump 订正为 **Q5 + R5 + S1 + T2**(全组 13 项清单见本节末「删断言探针」段)。
271
+
272
+ **扩展套件 16 处(红项数=本轮实跑读数;⑦⑨ 为既有变异随 K 组连带更新,⑮⑯ 为本批新增)**:
273
+
274
+ | # | 变异 | 红项数 | 备注 |
275
+ |---|---|---|---|
276
+ | ① | 档位不生效(mode 恒返回表内缺省) | 9 | 既有 |
277
+ | ② | confirm 也直落(decide 把 confirm 格判成 allow) | 39 | 既有 |
278
+ | ③ | 矩阵整表坍缩成 full | 46 | 既有 |
279
+ | ④ | 写链档位闸不生效(`_gate_autonomy` 恒放行) | 6 | 既有 |
280
+ | ⑤ | 合并档位闸不生效(`_autonomy_gate_merge` 恒放行) | 10 | 既有 |
281
+ | ⑥ | 删除档位闸不生效(`forget_gated` 直调软删) | 4 | 既有 |
282
+ | ⑦ | accept 不执行(执行桥空转) | **18** | 既有;锚点移至前像拍摄行并复测,红 **9→18**(K 组连带) |
283
+ | ⑧ | 幂等键丢掉目标(内容签名回归) | 4 | 既有 |
284
+ | ⑨ | kind 不落 rec(变更单退化成提案) | **20** | 既有;红 **10→20**(K 组连带) |
285
+ | ⑩ | 档位路径绕过 can_admin 闸(实修缺陷形态) | 2 | 既有 |
286
+ | ⑪ | gated 面档位闸不生效(`_autonomy_gate_rewrite` 恒放行) | 15 | 既有 |
287
+ | ⑫ | gated 面档位闸跳过资格探针(write_qualify 摘除) | 2 | 既有 |
288
+ | ⑬ | 执行桥 C 目标消失判据摘除(upsert 回归) | 3 | 既有 |
289
+ | ⑭ | SHIM 登记丢失(`_SHIMS` 去掉 autonomy_modes) | 2 | 既有 |
290
+ | ⑮ | 执行桥不拍前像(执行时点前像整支失效) | **8** | **本批新增**(K 组连带) |
291
+ | ⑯ | 执行时点补全摘除(`mutation_executed` 空转) | **9** | **本批新增** |
292
+
293
+ **删断言探针**〔工作流采集·复核段,复核自跑〕:内存改 `_GROUPS`(零文件改动)——删掉 S 组后本体 59→50(S 组=9 条);自证驱动变异⑤「D 回滚不做前像校准」红项 **2→0** 判红项数不符;①30→24、④13→12、⑧3→2 同判不符——自证整体 FAIL rc=1(对照不删组 rc=0)⇒ 变异表对断言组有判别力(自证不是空转)。
294
+
295
+ **本轮独立复跑与 ④ 红项面订正〔本报告实跑(读者反馈轮)〕**:内存去 `g_s`(独立库根)后——本体 59→50(S 组=9 条);变异④红项 **13→12**、⑤ **2→0**、① **30→24**、⑧ **3→2**;自证整体 FAIL rc=1——**复核的四个数字逐个复现一致**。**④ 的红项面按逐项 dump 订正为 Q5+R5+S1+T2**,全组下 13 项实测清单:Q「逐字节比对前像」「残留核对三面全回」「盘面逐字节==前像」「索引不残留」「边恢复」5 条 + R「逐字节比对前像」「盘面逐字节==前像」「聚合行不残留」「fm 回退」「残留核对」5 条 + S「盘面逐字节==前像」1 条 + T「时点判别场景回滚成功」「回滚到执行时点」2 条;删 S 组后 12 项、差集恰为 S 组那 1 条——与「13→12」自洽。原稿枚举「Q5 + R4 + S4」系笔误(若 S 为 4,删组应差 4),以本轮实测为准。
296
+
297
+ ### 4.3 python 全量〔本报告实跑〕
298
+
299
+ ```text
300
+ python -X utf8 scripts/run_tests.py → ===== SUMMARY 306/306 通过,5 跳过(依赖缺失/平台不符) ===== ;EXIT=0
301
+ ```
302
+
303
+ - PASS/FAIL/SKIP 行数实读计数:**306 / 0 / 5**(输出文件 `%TEMP%\step3_report_fullsuite.txt`)。
304
+ - **与采集读数并列(如实)**:采集(工作流脚本 world-read#3)为「**305/306 通过,5 跳过**」+「失败:`md_cg.test_issue39_utf8_stdio`」、**退出码 1**。两轮为同一未提交工作树(4 改 + 3 新增,与实施段自述改动面一致);本报告对该失败项**单跑 3 次**(`python -X utf8 -m md_cg.test_issue39_utf8_stdio`)均 `20 passed, 0 failed, 0 skipped`、exit 0——本轮不可复现。差异原因未定(不猜测);无采集时刻文件哈希可事后比对,故只并列两个读数、不下结论。
305
+ - 跳过 5 项(依赖缺失/平台不符):`md_cg.test_p44_md_whitebox`、`md_cg.test_md_access_parity`、`md_cg.test_wisdom_md_store`(白箱库/语料真源缺失,.gitignore 忽略需本地生成)+ `swarm.tests.bench_swarm_scale`、`swarm.tests.bench_swarm_parallel`(负载敏感、仅串行执行;`--jobs 4` 默认跳)——与本次改动无关。
306
+
307
+ ### 4.4 容器两栈退出码〔工作流采集;本报告未复跑——理由如下〕
308
+
309
+ | 栈 | 既定命令(`README.md:585-590` 发版门禁) | 退出码 | 读数(采集转录) |
310
+ |---|---|---|---|
311
+ | **栈一** | `docker run --rm -v "$(pwd):/work" -w /work -e CARGO_TARGET_DIR=/tmp/target rust:bookworm bash scripts/linux_verify.sh full` | **0** | `结果: 22 pass / 0 fail` | `[PASS] smoke_test (linux)` | `=== 汇总: 38 pass / 0 fail ===` |
312
+ | **栈二** | `docker run --rm -v "$(pwd):/work" -w /work node:22-bookworm bash -c "npm install --include=dev && npm run build && node --import tsx --test test/*.test.ts"` | **0** | `# cancelled 0` | `# skipped 3` | `# todo 0` | `# duration_ms 11477.010094` |
313
+
314
+ **读数解读(读者反馈轮补)**:`38`=`scripts/linux_verify.sh` 的 `record` 段计数(脚本 `:112-116`:`=== 汇总: $pass pass / $fail fail ===`)——按脚本可数的段=cargo test/build 2 + python 清单 23 + hive 4 + 变异自证 8 + smoke 1 = **38(整栈口径)**;`22`=同一输出里的另一行「结果: 22 pass / 0 fail」,形态是**单个套件自身的总结行**(同段惯例:如 `test_policy_required_ccg` 的「结果:28 pass / 0 fail」)——与 38 **不是同一层级、非包含关系**,不可直接比较;该行具体归属哪条套件,材料未附容器日志、**无从确证(不猜)**。
315
+
316
+ **栈二读数边界(读者反馈轮补)**:材料只给出尾部四行(cancelled/skipped/todo/duration)与退出码 0——**pass/fail 明细未随材料、本报告未复跑**;`# skipped 3` 表明至少 3 项子测试被识别并跳过,但「实际执行了几个测试、通过几个」在文本内**不可证成**(列入 §6.2)。
317
+
318
+ **未复跑声明(如实;理由经读者反馈轮订正)**:本机 `docker version` Server **28.4.0**、镜像 `rust:bookworm` 与 `node:22-bookworm` 均在本地(本轮实读)——能力在位;但两条既定命令**都会在工作树写产物**:栈一脚本内显式 `mkdir -p hive/target/release; cp "$CARGO_TARGET_DIR/release/hive" hive/target/release/hive`(`scripts/linux_verify.sh:33-36`,注释自陈「target/ 在 .gitignore 内」)+ python 段与自证段的 `__pycache__` 等;栈二 `npm install && npm run build` 写 `node_modules/`、`lib/`。与本 ask 硬边界「只写这一个文件」相抵,故**主动不跑**,两栈读数按工作流采集转录(§六 列为未覆盖面)。
319
+
320
+ ### 4.5 定向回归与相邻套件〔工作流采集·实施段实跑〕
321
+
322
+ ```text
323
+ python -X utf8 scripts/run_tests.py md_cg → 229/229 通过,3 跳过(白箱库/语料真源依赖缺失,与改动无关),exit 0
324
+ scripts/test_judgment_manifest.py → 20 通过 / 0 失败(新测试文件无需登记 manifest,与步骤②先例一致)
325
+ ```
326
+
327
+ `test_mutation_rollback` 与 `test_autonomy_modes` 均在执行清单内且 PASS。
328
+
329
+ ---
330
+
331
+ ## 五、独立复核判定与它列出的 uncovered
332
+
333
+ ### 5.1 判定与复核载体〔工作流采集·复核段〕
334
+
335
+ - **判定:ACCEPT。**
336
+ - **复核载体**=工作树未提交改动(4 修改:`autonomy_modes`/`mdcos`/`protect`/`test_autonomy_modes`;3 新增:`rollback.py`/`rollback_cli.py`/`test_mutation_rollback.py`),基线 HEAD `0960392e`。
337
+ - **复核红线自证(转录)**:全部实验在系统临时目录合成库执行,跑完已全部清理;`git status` 与开始时逐字一致;未编辑工作区任何文件;不采信执行者自述(复核自写探针、自跑命令)。
338
+
339
+ ### 5.2 复核依据(四组腿,转录)
340
+
341
+ **【① 退化/容错路径:可判定输出、不崩、路径真的发生】** p1 **31/31**、p6 **6/6**、p7 **4/4** 通过(自写探针,`tempfile.mkdtemp` 合成库)。可判定读数而非『没抛』:`rollback_mutation(None,None)`→`mutation_missing`;缺 before→`rollback_gap`;E 类→`rollback_action_unknown`;前像文件缺失→`preimage_missing`;`_open_content`→None→`preimage_unreadable`;`preimage()` 对 A 类/目标缺失→None(A 类=新增节点,定义见 §1.1 动作分类表)。目标缺失:回滚与 accept 两条路径均 fail-closed,且『不重建』用**非空集合**实证——库内保留无关节点后独立扫描 `.md` 集合(1 个)在失败前后逐位不变(P2/P3);accept 失败时节点字节未变、`decisions.jsonl` 无该 pid、恢复后重试成功(S5c-e)。旧形态输入(修前 rec):步骤②形态 rec(mutation 无 before)→ `rollback_gap` rc=1;无 mutation 键 rec→`decision_not_found` rc=1(S6a-c)。容错分支真的发生:patch 实例 get 抛异常时 `collect_impact` 仍返回读数(`present=True`,S2d);B 腿剥离退化 `stripped_ok=False`/`method=preimage`(B8 部分剥离、B10 全量覆写 removed 空);D 腿 trash 缺失→`not_in_trash` rc=1(D'1)、二次 CLI→`replayed=True`(D11)。
342
+
343
+ **【② 合法输入逐位对照(改动前实现 oracle)】** 用 `git archive HEAD` 只读导出旧树(确认无 `rollback.py`、`protect.py` 无 `snapshot_preimage`),与现行树各建独立合成库跑同一观测脚本,逐键对照:**35 SAME / 5 DIFF**。SAME 覆盖:snapshot 命名形态+字节==盘面、`guard_write`/`guard_forget` 返回体与审计行、history、索引条目、写链新写返回、forget/restore 返回体与恢复正文、trash、普通 proposal 链 rec 形状(prop9 SAME)、`record_hash` 口径(固定 pid/t 手工 rec 两树 sha1 相同且加 `mutation` 键不变)。**5 处 DIFF 全部为本批契约**:payload 新增 `before`/`impact`/`rollback` 占位(None/None/`''`,旧键值 SAME)+变更单 accept 返回体/rec 多『mutation』键(`rec['result']` 仍只 ok/node_id/error/state)。**五处的读法(读者反馈轮补)**:材料原文未逐条编号;按材料枚举的**键**计=`before`+`impact`+`rollback` 三占位键(3)+ accept 返回体新增 `mutation` 键(1)+ `rec` 新增 `mutation` 键(1)=5——此为按材料原文的键数解读、**非复核逐条编号**;如需逐条编号明细须向复核方索取原文。**前像=执行时点**:C/B/D 三腿前像文件字节==accept 前一刻盘面(p8 L1-L3);C 腿第三方覆写后前像==第三方字节且 `!=` 提议初版(S3c/S3c2);预置最旧快照场景回滚到执行时点而非最旧(T'1-3)。
344
+
345
+ **【③ 守卫本体与变异自证(复核自跑)】** `python -X utf8 -m md_cg.test_mutation_rollback` → 锚点自检 PASS,**59 通过 0 失败** rc=0;同命令 `--mutate` → 8 处变异全命中(红项 **30/2/1/13/2/4/4/3**)PASS rc=0,与落码记录逐项相符。`python -X utf8 -m md_cg.test_autonomy_modes` → **138 通过 0 失败** rc=0;`--mutate` → 16 处全命中 rc=0。删断言探针(内存改 `_GROUPS`,不改文件):删掉 S 组后→本体 59→50(S 组=9 条);自证驱动变异⑤『D 回滚不做前像校准』红项 2→0 判红项数不符,①30→24、④13→12、⑧3→2 同判不符,自证整体 FAIL rc=1(对照不删组 rc=0)。**本轮独立复跑四个数字逐个一致**(详解与 ④ 红项面订正见 §4.2 末两段)。
346
+
347
+ **【④ 不得静默可观测面】** D 回滚读数如实双证:手工 restore(不经 rollback 模块)实得字节 `!=` 前像、差异行 `sensitivity: null`;CLI 输出 `calibrated=true`/`restore_bytes_equal=false`/`method=restore+preimage_calibration`,校准后盘面逐字节==前像(独立比较),二次 CLI `replayed=true`。`preimage_unavailable` 时 accept 返回 `{ok:false,error:preimage_unavailable}` 且节点字节未变、裁决未落盘、恢复后重试成功。CLI `rc=0` 完成/`rc=1` 未回滚语义、`--reason` 进返回体、`residual` 三面全回均实测可观测。
348
+
349
+ ### 5.3 它列出的 uncovered(如实)
350
+
351
+ **材料边界声明(先说清)**:本 ask 交给本报告的材料为「`独立复核=ACCEPT`,依据=<复核自述全文>」——**未见独立命名的 uncovered 清单原文**。以下 3 条为从材料明文读数中可考的「复核未覆盖面/未收口事项」,逐条标出处;**不代补、不臆造**:
352
+
353
+ | # | 未覆盖面(出处) | 性质 |
354
+ |---|---|---|
355
+ | 1 | **python 全量与容器双栈不在复核覆盖面内**——出处=工作流脚本给复核员的任务约束原文「不要重复跑全量与容器——脚本随后会跑」;两栈读数归编排侧采集(§4.4),全量归编排侧(§4.3) | 分工设计使然;由编排链路覆盖,非缺口 |
356
+ | 2 | **复核全部在合成库/临时目录执行**——出处=复核自述「全部实验在系统临时目录合成库执行,跑完已全部清理」 | 在役数据根上的行为未由复核直接验证;本批红线本就禁止触在役根(设计内约束),如实登记 |
357
+ | 3 | **「仍未被覆盖/仍可疑的面」清单原文未随材料传到我**——复核任务收尾要求含该清单(「凡你没独立复现的,如实列入 uncovered」),但传入本报告的只有 verdict 与 basis | **本报告答不了**是否另有未列项;须向复核方索取原文。对照先例:步骤②的复核曾另列 uncovered 四条(文档面/行为面/沙箱残留/容器面) |
358
+
359
+ ---
360
+
361
+ ## 六、边界与未覆盖(含本轮明确不修而留池的面)
362
+
363
+ ### 6.1 留池(明确不修,记录在案)
364
+
365
+ 1. **R1–R4 准入读数与时间窗**(设计 §七):未做;本批产出的 `_protected_history` 前像 + `residual`/`bytes_equal_preimage` 实测记录即 R3「破坏可逆且回过」的现成数据面。
366
+ 2. **计划输入面**(设计 §五):plan 档 A/B/E 现恒 `forbid`(无计划即计划外);未做。
367
+ 3. **§九 变更单台账**(生成/裁定/驳回/回滚四计数):未做。现状(**读者反馈轮实测**):生成/裁定可由 `decisions.jsonl` 汇总,但**「回滚计数」无独立留痕**——回滚不写台账、`accept` 记录不改状态(实测:C 回滚前后 `decisions.jsonl` **字节不变**、`_audit.jsonl` **零新增**;D 回滚经 `restore` 写 `_audit.jsonl` 两条 `op=add`/`op=restore`,但**不含 pid/变更单号**)——即「此变更已被回滚」在现有记录里**无逐单可查标记**(幂等重放是唯一现成校验路径)。要做台账须先设计回滚留痕。
368
+ 4. **加密库前像的逐字节边界**:覆写 `_seal_content` 的实例每次封装熵不同——前像语义为「明文内容 + 结构可恢复」,`bytes_equal_preimage` 仅在非加密库(含全部守卫合成库)上成立;已在 `protect.snapshot_preimage` docstring 与 `rollback.py` 模块 docstring 如实登记。**在役部署是否为加密库,本报告不可知**(在役数据根不在本轮可触面内);若为加密库,第 1 条的 R3 数据面应改用「明文内容 + 结构可恢复」口径读数——`bytes_equal_preimage` 在该库上如实为 False。
369
+ 5. **`_protected_history` 前像无轮转/清理策略**:C/D/B 动作每次执行各留一张前像,长期增长面未评估(census 剪枝已覆盖该目录两层下钻,`ARCHIVE_DIRS` 既有登记)。
370
+ 6. **`rollback_cli` 的权限面**:与 `review_cli`(designer/can_admin)不同,回滚 CLI 直用 `MdCGOS`(无 principal 层闸)——语义为「执行记录既有授权的撤销」;如需对齐裁决面的权限模型,另行裁定。
371
+ 7. **E 分数类(权重/生命周期)**:不属本批(设计 §四 明文「各模块既有 rollback」)。
372
+ 8. **B 腿剥离退化路径是有意语义**(`stripped_ok=False` 时正文取前像、`method=preimage`)——回滚判据是「回到前像」,非缺口;如实登记以免被读成兜底失灵。
373
+ 9. **「可回滚清单」缺口(读者反馈轮登记)**:回滚命令只在**执行后**的 `rec["mutation"]`(decisions.jsonl)里;审批人在 inbox 看到的永远是占位,CLI 要手输 `--pid`。现**无**工具/清单汇总「哪些变更单可回滚、哪些已回滚」——留池(与第 3 条台账同源)。
374
+ 10. **回滚权限不对称(读者反馈轮登记)**:`rollback_cli` 无 principal 层闸(同第 6 条)——任何能读库根且持 pid 的进程都可执行回滚;`review_cli` 有 designer/can_admin。现状如实:权限模型未对齐,留池另行裁定。
375
+ 11. **快照面语义与误读风险(读者反馈轮补)**:前像与受保护快照写**同一目录、同一审计文件**(面复用,§3.3)——但**目录存在 ≠ 节点受保护**:受保护判据始终是 `protect.is_immutable/is_protected`(guard 入口 `protect.py:269-293`);审计行可按 `action` 区分(`snapshot` vs `preimage`)。是否存在把「`_protected_history/<id>/` 存在」当受保护判据的消费者——本轮**未做全仓消费者普查**,留池。
376
+
377
+ ### 6.2 验证边界(本轮未覆盖/不可证的面)
378
+
379
+ 1. **容器两栈未由本报告复跑**(§4.4 理由:读写挂载会写工作树,与硬边界相抵);读数为工作流采集转录。
380
+ 2. **定向回归 229/229 与 `judgment_manifest` 20/0 为实施段实跑转录**,本报告未复跑(§4.5)。
381
+ 3. **python 全量两轮读数不同**(采集 305/306 失败 `md_cg.test_issue39_utf8_stdio` 退出码 1;本报告 306/306 退出码 0)——该失败项本报告单跑 3 次全绿、本轮不可复现;差异原因未定(§4.3)。
382
+ **编排侧补记(2026-10-02 收口轮):差异已定因并修复。** 机制=在役 serve(pid 9588)心跳的原子写协议(tmp→rename)在 `hive/jobs` 目录闪现 `_serve.tmp<pid>`——探针实测(45s / 448 次采样):含 `_serve*` 口径的目录清单变化 **62 次**(全为该 tmp 的 +/− 对;tmp 存续约 0.35s、占空比约一半),排除 `_serve*` 后 **0 次**。本守卫 `_pool_listing`(`md_cg/test_issue39_utf8_stdio.py:239`)未排除 `_serve*`,两个采样点之间被闪现命中即假红(两次采样独立近似下概率约四分之三)——与 `scripts/test_utf8_boot_guard.py:470-482` 2026-10-01 按同一归因修复的形态同源(该处已排除;hive 组三处同族判据以 `startswith("h")` 天然排除)。**修复**=同名排除(与先例逐字同口径;其余任何新增照旧判违规,判据强度不变)。**修复后读数(编排侧亲测)**:单跑 20/20 rc=0;全量连跑两轮 **306/306、306/306** rc=0。全仓同族残点排查=仅此一处(已清)。
383
+ 4. **在役数据根零触碰**(红线使然);全部证据来自合成库——在役数据上的行为未由本报告直接验证。
384
+ 5. **报告数字的核对口径(读者反馈轮订正)**:行号均为本轮实读;数字链已按读者反馈逐项复核并**订正 1 处**(④ 红项面枚举,见 §4.2)——不再自称「全文自洽」,剩余一致性由读者/后续复核核对。
385
+ 6. **栈二 pass/fail 明细不可证成**(材料只给尾部四行;本报告未复跑,见 §4.4)。
386
+ 7. **`issue39` 两轮差异与 `%TEMP%` 沙箱残留的相关性**:**未验证、不猜测**。机制上二者无关(`issue39` 是 stdio 编码面测试;沙箱残留是守卫 `rmtree` 在 Windows 被锁句柄挡住的既有留池现象——步骤②留池第 1 条已登记)。
387
+
388
+ ### 6.3 报告自身边界(如实)
389
+
390
+ - **本报告实跑**的面:守卫正向(59/138)、变异自证(8+16 处红项数)、python 全量(306/306)、`issue39` 单跑 3 次、全部行号读码;**读者反馈轮另跑**:键集 dump、CLI 首次态(C/D)、回滚留痕(decisions/audit 前后)、trash≡前像字节、④ 逐项 dump 与去 S 组复跑(探针 `%TEMP%\step3_rv_probe.py`、`step3_dump4.py`/`step3_dump4b.py`)。
391
+ - **本报告未跑**的面:容器两栈、定向回归 229/229、`judgment_manifest` 20/0、§二 复现腿本体(复现段产物,本轮实读其脚本与基线日志在案)。
392
+ - **唯一写入文件**:本报告(§7.3 机械核对)。
393
+
394
+ ---
395
+
396
+ ## 七、不动面对拍与红线自查
397
+
398
+ ### 7.1 无档位/无变更单路径逐位一致(采集读数 + 本轮复跑)
399
+
400
+ - full 档全动作直落(H 组);proposal 链 accept/noop 原路径(F 组);库层 `MdCG.add`/`_write_node`/`MdCGOS.forget` 与合并原语不含档位判据(G 组);`_record_decision` 对无 `mutation` 键的 result **不落新键**(proposal rec 形状逐位不变,`record_hash` 只算**固定十键**——十键=`pid, round, decision, status, redteam_verdict, issues, verify_hash, reason, actor, t`(`mdcos.py:2313-2314` 实读;对十键取 sort_keys 紧凑 JSON 的 sha1))。定向回归 229/229 全绿覆盖(§4.5);复核 ② 的 prop9 SAME 与 `record_hash` 口径另证(§5.2)。
401
+ - **受保护节点快照行为一字不变**:`protect.py` 既有函数(`snapshot`/`history`/`_allow`/`guard_*`/`mark`)本轮读码逐行对照 HEAD 与工作树**一致**(`snapshot` `215-245`、`_allow` `262-265`、`guard_write` `269-281`、`guard_forget` `285-293`);守卫 P 组把 `snapshot` 命名/审计形态、`guard_write|guard_forget` override 的快照数与审计面钉死;变异 ⑥(把前像挂钩塞进 `_allow`)实测红 4。
402
+
403
+ ### 7.2 红线自查
404
+
405
+ - 一切实验走 `tempfile.mkdtemp` 合成库(含子进程 CLI 演练),**未触任何在役数据根**;未改 `data/policy.json`(git 面仅 §7.3 所列文件);未削弱任何 forbidden;未 `git add/commit/push`;未改归档/纪律面(`zcode/AGENTS.md`、纪律真源等零改动)。
406
+ - 本报告落盘前后除本文件外 `git status --porcelain` 一致;本报告为本 ask 唯一写入文件。
407
+
408
+ ### 7.3 git 面(本轮实读)
409
+
410
+ ```text
411
+ M md_cg/autonomy_modes.py (载荷三字段 + mutation_executed)
412
+ M md_cg/mdcos.py (_mutation_execute 执行时点补全 + _record_decision 落 rec["mutation"])
413
+ M md_cg/protect.py (snapshot_preimage 新入口)
414
+ M md_cg/test_autonomy_modes.py (K 组 + 变异表更新)
415
+ ?? .zcode/ (会话起始既有,非本批产物)
416
+ ?? docs/eval/三档自治_步骤③变更单与回滚原语_落码记录_v1.0.md (本报告)
417
+ ?? md_cg/rollback.py (新:统一回滚入口/影响面/定向剥离/命令构造)
418
+ ?? md_cg/rollback_cli.py (新:回滚命令载体)
419
+ ?? md_cg/test_mutation_rollback.py(新:回滚面守卫)
420
+ ```
421
+
422
+ `git rev-parse HEAD` = `0960392e0886cc046aa80156decf49c4b9b6e12f`(基线未变)。
423
+
424
+ ---
425
+
426
+ ## 附 A:本批新增/修改的判据与「生效条件:」注释(本仓惯例)
427
+
428
+ - 新增/修改函数均带上方「生效条件:」注释并按实测同步 docstring:`protect.snapshot_preimage:248-295`、`autonomy_modes.mutation_payload:297-330`/`mutation_view:267`/`mutation_executed:333-352`、`rollback` 全模块(`command_for:75`/`preimage:90`/`collect_impact:120`/`read_preimage:159`/`strip_aggregate_lines:182`/`_land:219`/`_rollback_rewrite:265`/`_rollback_merge:278`/`_rollback_delete:308`/`_residual:342`/`rollback_mutation:356`)、`mdcos._mutation_execute`(执行时点补全段 `2546-2554`/`2599-2609`/`2633-2637`)、`mdcos._record_decision`(`2376-2382`)、`rollback_cli._root:48`/`_mutation_record:59`/`main:73`。
429
+ - 守卫数字汇总:**59 + 138 断言全绿;8 + 16 处定点变异全命中;python 全量 306/306(本报告实跑)**〔见 §四〕。
430
+
431
+ ## 附 B:本报告证据来源对照(每个数字谁跑的)
432
+
433
+ | 数字/事实 | 来源 |
434
+ |---|---|
435
+ | 守卫正向 59/138、变异 8 处(30/2/1/13/2/4/4/3)、变异 16 处(9/39/46/6/10/4/18/4/20/2/15/2/3/2/8/9)、python 全量 306/306、`issue39` 单跑 3 次、全部行号读码 | 〔本报告实跑〕 |
436
+ | 探针 P1–P7、CLI 实测输出、逐字节比对读数、定向回归 229/229、`judgment_manifest` 20/0、容器双栈退出码 | 〔工作流采集·实施段实跑 / 编排侧〕 |
437
+ | 9 条复现腿(payload/observed/site/reproduced)、126 基线、受保护对照片、复现沙箱与基线日志 | 〔工作流采集·复现段〕 |
438
+ | 复核判定 ACCEPT、四组核实腿、35 SAME/5 DIFF、删断言探针数字 | 〔工作流采集·复核段〕 |
439
+ | 读者反馈轮实测:键集 dump、CLI 首次态(C/D)、回滚留痕(decisions/audit)、trash≡前像字节、④ 逐项 dump 与去 S 组复跑、39 键单位 | 〔本报告实跑(读者反馈轮)〕 |