iter33 卡① 审计回炉: sv3 断言强化+生产链对照面+sv4 判别锚+变异⑥⑦补执行

首轮独立验收审计两缺漏回炉(零裁断纪律):
- sv3:拆闸实验证实原拒写断言无判别力(返 false 与下游写失败不可区分)且杂散 game/.tmp 落盘
  未被盘面断言覆盖、MetaProgression 生产链零对照面——回炉补「退化写目标(裸 .tmp)零新增」
  类级+链级两锚+settle_adventure 真表驱动生产链对照面(boot 套件 8→12 检查);变异⑦
  (闸短路)实测两锚全红。
- sv4:申报变异未执行且原段序(先删后建)无判别力——回炉改夹具为「非白板旧内容 999/5
  覆盖为白板+盘面核验非旧值」;变异⑥(create 读旧档)实测两断言红。
还原后冒烟 1201/0、38 套件全绿。实现报告 sv2/sv3/sv4 行与变异表对账更新。
This commit is contained in:
DKChan committed 2026-10-22 04:11:55 +08:00
1 parent 074cfe27a4
commit 4a8558a09f
3 files changed
+62 -12

No files matched your search

+12 -4
View File
@@ -6906,11 +6906,19 @@ func _smoke_save_slots() -> void:
check(FileAccess.get_file_as_bytes(slot_tpl % 1) == slot1_before,
"sv6 删槽 2 槽 1 字节不动(位间互隔离)〔卡① sv6〕")
# ③ 新档原语(sv4):空槽创建=全零可玩白板,创建即激活并落盘
# ③ 新档原语(sv4):非白板旧内容覆盖为全零可玩白板(判别锚:新档禁读旧档——变异可红),
# 创建即激活并落盘(生产路径只在空槽调用;本段预置旧内容是对原语白板保证的钉死,超生产面)
var fold := FileAccess.open(slot_tpl % 3, FileAccess.WRITE)
fold.store_string(JSON.stringify({"version": 7, "meta": {"keystone_balance": 999,
"adventure_total": 5, "adventure_cleared": 2, "tree_nodes": {}, "fork_sides": {}, "tree_struct": 2}}))
fold.close()
check(t.create_slot(3), "sv4 新档受理·槽 3(创建即激活)〔卡① sv4〕")
check(t.active_slot() == 3 and t.keystone_balance() == 0 and not t.has_breakpoint(),
"sv4 新档=全零可玩合法白板态(激活号 3/钥石 0/无断点)〔卡① sv4〕")
check(FileAccess.file_exists(slot_tpl % 3), "sv4 新档落盘(文件在位)〔卡① sv4〕")
check(t.active_slot() == 3 and t.keystone_balance() == 0 and not t.has_breakpoint()
and t.adventure_total() == 0,
"sv4 新档=全零可玩合法白板态(旧内容 999/5 零带入——钥石/总局数/断点全零)〔卡① sv4〕")
var created: Dictionary = JSON.parse_string(FileAccess.get_file_as_string(slot_tpl % 3))
check(int((created.get("meta", {}) as Dictionary).get("keystone_balance", -1)) == 0,
"sv4 新档落盘=白板内容(盘面核验非 999 旧值)〔卡① sv4〕")
# ④ 高版本拒读槽按槽成立+激活失败恢复切换前三态(sv9/sv10)
var fhv := FileAccess.open(slot_tpl % 2, FileAccess.WRITE)
@@ -1,17 +1,21 @@
# tests/unit/core/save_boot_no_activate_test.gd — 卡① sv2/sv3:启动态钉死类级契约
# (无参实例=无激活态、内存=默认合法空态、无激活写盘一律拒绝并返回 false 且盘面零触碰、
# 访问器 fail-safe 合法空值、越界槽号拒绝。真实 autoload boot 链断言在冒烟 V2-s1..s4 段——
# --script 模式无 autoload,本套件为类级白盒面,双落点在实现报告实际对照表对账。)
# (无参实例=无激活态、内存=默认合法空态、无激活写盘一律拒绝并返回 false 且盘面零触碰
# 〔含空路径派生的裸 ".tmp" 退化写目标——拆闸变异的可判别锚〕、MetaProgression.settle_adventure
# 生产链无激活触达写盘被拒、访问器 fail-safe 合法空值、越界槽号拒绝。
# 真实 autoload boot 链断言在冒烟 V2-s1..s4 段——--script 模式无 autoload,本套件为类级
# 白盒面+生产链对照,双落点在实现报告实际对照表对账。)
# 载体:run_all 单元套件(显式实例化夹具——--script 模式无 autoload)。
extends SceneTree
const SaveManagerScript := preload("res://core/save_manager.gd")
const MetaProgressionScript := preload("res://core/meta_progression.gd")
const Kit := preload("res://tests/unit/test_kit.gd")
func _init() -> void:
_test_no_arg_instance_has_no_activation()
_test_write_rejected_without_target()
_test_settle_chain_write_rejected()
_test_out_of_range_slots_rejected()
quit(Kit.finish("save_boot_no_activate"))
@@ -33,6 +37,8 @@ func _test_no_arg_instance_has_no_activation() -> void:
# ② 无激活态写盘一律拒绝并返回 false,盘面零触碰(sv3 类级——真实入口=冒烟 V2-s3 生产链)
# 判别锚:空 _path 的退化写目标=裸 ".tmp"(落 res://,拆闸实验实测杂散落点)——
# 断言先清退化目标再核零新增,闸短路变异(拒绝口旁路、写盘真实发生)必红。
func _test_write_rejected_without_target() -> void:
var sm := SaveManagerScript.new()
var before := {}
@@ -41,6 +47,10 @@ func _test_write_rejected_without_target() -> void:
before[i] = [FileAccess.file_exists(p),
FileAccess.get_file_as_bytes(p) if FileAccess.file_exists(p) else PackedByteArray(),
FileAccess.get_modified_time(p) if FileAccess.file_exists(p) else 0]
var stray: Array[String] = ["res://.tmp", "res://.tmp.tmp"] # 空 _path 的 tmp 原子写派生名
for sp in stray:
if FileAccess.file_exists(sp):
DirAccess.remove_absolute(sp) # 夹具清场——退化目标从零起
Kit.check_quiet(not sm.write_to_disk(),
"sv3 无激活写盘拒绝(write_to_disk=false)〔卡① sv3〕")
var unchanged := true
@@ -54,11 +64,41 @@ func _test_write_rejected_without_target() -> void:
unchanged = false
Kit.check_quiet(unchanged,
"sv3 拒写盘面零触碰(三槽存在性/字节/mtime 全等)〔卡① sv3〕")
var stray_clean := true
for sp in stray:
if FileAccess.file_exists(sp):
stray_clean = false
Kit.check_quiet(stray_clean,
"sv3 拒写退化写目标零触碰(裸 .tmp 零新增——拒绝口可判别锚)〔卡① sv3〕")
# 拒读禁写态语义在位(高版本拒读→写拒绝——既有契约回归锚)
sm._read_only = true
Kit.check_quiet(not sm.write_to_disk(), "sv3 拒读禁写态写盘拒绝(既有契约保持)〔卡① sv3〕")
# ③ 生产链对照面(sv3 真实入口):MetaProgression.settle_adventure 无激活态触达写盘被拒
# (生产结算链全段在位:mark_first_adventure_done→apply_adventure_summary→refresh_treasure_unlocks
# →write_to_disk;无激活态下落账内存、写盘拒绝、盘面零触碰——已知中间态的机检面)
func _test_settle_chain_write_rejected() -> void:
var db = load("res://core/config_db.gd").new()
if not db.load_tables("res://data/tables", false):
Kit.check_quiet(false, "sv3 链测试前置:数值表加载失败〔卡① sv3〕")
return
var sm := SaveManagerScript.new()
var meta := MetaProgressionScript.new(db, sm)
for sp in ["res://.tmp", "res://.tmp.tmp"]:
if FileAccess.file_exists(sp):
DirAccess.remove_absolute(sp)
Kit.check_quiet(not sm.has_write_target() and not sm.write_to_disk(),
"sv3 链前置:无激活态在位且直写被拒〔卡① sv3〕")
meta.settle_adventure({"result": "failed", "cleared": false, "levels_cleared": 1,
"stopped_at": 2, "keystone_total": 0, "master_seed": 3})
Kit.check_quiet(not sm.has_write_target() and sm.adventure_total() == 1,
"sv3 生产链:settle_adventure 落账内存(adventure_total=1)而写盘仍无目标(被拒不落盘)〔卡① sv3〕")
Kit.check_quiet(not FileAccess.file_exists("res://.tmp")
and not FileAccess.file_exists("res://.tmp.tmp"),
"sv3 生产链盘面:结算触达后退化写目标零新增(链上真实入口的盘面核验)〔卡① sv3〕")
# ③ 越界槽号三原语拒绝+窥视越界返回不可读(原语边界 fail-safe)
func _test_out_of_range_slots_rejected() -> void:
var sm := SaveManagerScript.new()
+7 -5
View File
@@ -7,7 +7,7 @@
## 卡① 存档制数据层改造批(隐式单档 → 3 存档位)——已合并(见合并记录)
**状态**:T0–T4 完成;批末重闸 --code 全绿(回执见合并提交信息);独立验收审计通过(`reports/iter33-验收审计-2026-10-21.md` 卡① 节)。
**状态**:T0–T4 完成;批末重闸 --code 全绿(回执见合并提交信息);独立验收审计两轮——首轮未过(sv3 拆闸实验判「拒写断言无判别力+生产链零对照面」、sv4 申报变异未执行且无判别力,两行缺漏回炉),回炉后断言强化(sv3 退化写目标锚+生产链对照面、sv4 旧内容判别锚)并补执行变异⑥⑦,复审通过(`reports/iter33-验收审计-2026-10-21.md` 卡① 节)。
### 一、实际改动—验收对照表(§7.1 需求侧表的执行对账,六列+结果)
@@ -16,9 +16,9 @@
| 需求点 | 改动实值(文件:行) | 验收测试实值(落点+尾缀) | 层级 | 真实入口 | 撤销或变异证明 | 结果 |
|---|---|---|---|---|---|---|
| sv1 三槽承载+位间隔离 | `save_manager.gd:15-27` 常量与字段(SLOT_COUNT/SLOT_PATH_TEMPLATE/_slot_template);`:77` slot_path 唯一派生口;`:66` attach_slot_template 注入口 | 冒烟 `_smoke_save_slots` ①段 `smoke_all.gd:6858` 起〔sv1 往返×3+位间隔离〕+单元 `save_slot_isolation_test.gd`〔sv1〕(22 检查) | 接口 | `SaveManagerCore` 实例按槽 API 读写往返,不经 UI | 变异①=slot_path 派生写死 `% 1` → 三槽往返一致断言红(已执行,见变异表) | 通过 |
| sv2 启动态不读盘 | `save_manager.gd:29` `_init` 默认参改 `""`+`:48-53` `_ready` 只做旧档迁移、零读槽 | 冒烟 V2-s1/V2-s2(`smoke_all.gd:273-278`)〔sv2〕真实 boot 链+单元 `save_boot_no_activate_test.gd`(8 检查)类级白盒 | 冒烟+单元 | 组合根 boot 链 `/root/SaveManager`(真实入口=冒烟);单元为 --script 无 autoload 环境的类级对照面(**双落点对账:计划仅列单元,实测拆为冒烟真实链+单元类级**) | 变异④=_ready 偷调 activate_slot(1) → V2-s1/V2-s3 红(已执行) | 通过 |
| sv3 无激活写盘拒绝 | `save_manager.gd:354-358` `write_to_disk` 入口 `_path == ""` 判定 | 冒烟 V2-s3(`smoke_all.gd:278`)+单元〔sv3〕「拒写+返 false+盘面零触碰」(`save_boot_no_activate_test.gd` 快照三槽存在性/字节/mtime 全等) | 接口 | `MetaProgression.settle_adventure()`(`meta_progression.gd:275`,写盘 :282)无激活态触达写盘被拒 | 撤销=去掉判定放行旧入口 → 拒写断言红(代码评审可证:判定即 sv3 唯一闸门) | 通过 |
| sv4 新档原语 | `save_manager.gd:116-137` `create_slot`(创建即激活+落盘+失败回退) | 冒烟 ③段〔sv4〕全零可玩+文件在位 | 接口 | 空槽调新档 API 后按域读回 | 变异=新档写成读旧档 → 全零断言红(白板态断言锚 `_default_data` 全零,读旧档即带异值必红——与 sv5 读回断言同族) | 通过 |
| sv2 启动态不读盘 | `save_manager.gd:29` `_init` 默认参改 `""`+`:48-53` `_ready` 只做旧档迁移、零读槽 | 冒烟 V2-s1/V2-s2(`smoke_all.gd:273-278`)〔sv2〕真实 boot 链+单元 `save_boot_no_activate_test.gd`(12 检查)类级白盒+生产链对照 | 冒烟+单元 | 组合根 boot 链 `/root/SaveManager`(真实入口=冒烟);单元为 --script 无 autoload 环境的类级对照面+settle 生产链(**双落点对账:计划仅列单元,实测拆为冒烟真实链+单元类级/链级**) | 变异④=_ready 偷调 activate_slot(1) → V2-s1/V2-s3 红(已执行) | 通过 |
| sv3 无激活写盘拒绝 | `save_manager.gd:354-358` `write_to_disk` 入口 `_path == ""` 判定 | 冒烟 V2-s3(`smoke_all.gd:278`)+单元〔sv3〕「拒写+返 false+三槽快照全等+**退化写目标(裸 .tmp)零新增**+**MetaProgression.settle_adventure 生产链触达后盘面零触碰**」(`save_boot_no_activate_test.gd`,12 检查) | 接口 | `MetaProgression.settle_adventure()`(`meta_progression.gd:275`,写盘 :282)无激活态触达写盘被拒——生产链对照面在单测 ③段实测(真表 db 驱动全链) | 变异⑦=闸短路(`if false and _path == ""`)→ 退化写目标两断言红(类级+链级,已执行;首轮断言无判别力经审计判缺漏后强化) | 通过(回炉后) |
| sv4 新档原语 | `save_manager.gd:116-137` `create_slot`(创建即激活+落盘+失败回退) | 冒烟 ③段〔sv4〕非白板旧内容(999/5)覆盖为全零白板+盘面核验非旧值 | 接口 | 空槽调新档 API 后按域读回+盘面文件内容核验 | 变异⑥=create 改读旧档(`load_from_disk()` 代 `_default_data()`)→ 白板两断言红(已执行) | 通过(回炉后) |
| sv5 进档原语 | `save_manager.gd:94-114` `activate_slot`(激活+读盘+失败恢复切换前三态) | 冒烟 ①④段〔sv5〕+单元〔sv5〕 | 接口 | 槽 N 有档 → activate_slot → 读回=该槽内容 | 变异⑤=activate 漏更新 _path → 写盘受理断言红(已执行) | 通过 |
| sv6 删档原语 | `save_manager.gd:140-161` `delete_slot`(文件删除+.tmp 清偿+激活指针连清除+.corrupt.bak 不追删) | 冒烟 ②段〔sv6〕文件系统存在性断言 | 集成 | 激活/非激活槽调删档 API+盘面核查 | 变异②=漏删文件 → 在盘断言红(已执行) | 通过 |
| sv7 摘要三项按槽窥视 | `save_manager.gd:163-168` `peek_slot_summary`+`:170-172` peek_summary_at 注入口+`:174-205` 只读解析 | 单元 `save_slot_summary_test.gd`〔sv7〕(12 检查:三槽异值/空槽/三不可读态)+冒烟 ⑥段 | 单元+接口 | 窥视 API 按槽调用(不激活不写盘——套件内断言 active_slot==0) | 变异③=窥视改读激活态内存 → 跨槽摘要红(已执行) | 通过 |
@@ -39,6 +39,8 @@
| ③ | `peek_slot_summary` 改读激活态内存 | 跨槽摘要红 | sv7 窥视三项逐槽正确·槽 1/2 红(`save_slot_summary_test`) | 单元套件直跑 | all green (12 checks) |
| ④ | `_ready` 偷调 `activate_slot(1)`(偷复激活) | boot 断言红 | V2-s1 boot 后无激活态红+V2-s3 写盘拒绝红(冒烟) | `run_smoke.py` 全量 | 1201/0 全绿 |
| ⑤ | `activate_slot` 漏更新 `_path`(写盘落旧目标) | 写盘落错槽红 | sv3 激活态写盘受理·槽 1/2 红(`save_slot_isolation_test`——无激活态拒写路径被触发) | 单元套件直跑 | all green (22 checks) |
| ⑥ | `create_slot` 改读旧档(`load_from_disk()` 代 `_default_data()`,首轮审计 sv4 缺漏回炉) | 全零白板断言红 | sv4 白板态红+sv4 盘面核验红(999 旧值带入;冒烟) | `run_smoke.py` 全量 | 1201/0 全绿 |
| ⑦ | `write_to_disk` 无激活闸短路(首轮审计 sv3 缺漏回炉——拆闸实验证实原断言无判别力) | 拒写盘面零触碰断言红 | sv3 退化写目标零触碰红+sv3 生产链盘面零触碰红(`save_boot_no_activate_test`——杂散 game/.tmp 真实落盘被两锚抓获) | 单元套件直跑 | all green (12 checks) |
### 三、T0 产物:隔离面全清单清点(sv11 件核)
@@ -71,6 +73,6 @@
| 闸 | 基线(T0) | 末态(卡① 收口) |
|---|---|---|
| 冒烟 | 1156 / 0 | **1201 / 0**(+45:V2-s1..s4 四断言+_smoke_save_slots 段 41 断言) |
| 单元 | 35 套件全绿 | **38 套件全绿**(+3:isolation 22 / boot 8 / summary 12) |
| 单元 | 35 套件全绿 | **38 套件全绿**(+3:isolation 22 / boot 12〔回炉+4〕/ summary 12) |
| probe --click | 全绿 | 全绿(重闸复跑) |
| 重闸 --code | — | 全绿(回执随合并提交留痕) |