merge(迭代34 卡④ 信息迷雾可见性批): 层距 N 类型可见性+Boss/候选豁免+单圈回雾(N 读表)+呈现决策面与绘制记录观测面+画布大图断言与探针常数同源+两轮独立验收审计通过(首轮不通过 D1/D2→甲案回炉 T2→复审闭合;回执 commit=1b4a4acf,--code 全绿)

域判定依据:本批 diff 触及 game/(代码域触发面)与 reports/ 产出物,按迭代批既定口径与卡③先例(43c0f3c1)以 --code 全绿回执合回,design/ 与根规则文件零改动。
This commit is contained in:
DKChan committed 2026-10-22 16:13:49 +08:00
commit 16a7ec8012
16 files changed
+1030 -23

No files matched your search

+15
View File
@@ -16,3 +16,18 @@
## 白名单外未代拍事项
无。实现期未遇到需要超出 §10 清单自决的设计分歧。
## 卡④ 信息迷雾可见性批
> 白名单依据=`reports/需求卡片-信息迷雾可见性批-2026-10-21.md` §9(六条)。
| # | 白名单条目 | 实际做法 | 约束核验 |
|---|---|---|---|
| 1 | provisional N=2(§9-1) | `level.tres` 挂 `info_visible_layers = 2`;`validate` 只校验 int ≥ 1 | 定值仍在数据表,代码零硬编码;N=1/3 改表实测可见窗随动 |
| 2 | API/探针命名(§9-2) | `info_visible_layers`/`type_visible_ids`/`node_display`/`display_probe` | 均无 `fog_` 前缀,与战斗「视野迷雾」零撞词 |
| 3 | 雾下节点呈现落点(§9-3) | 图标/类型文字改读 `node_display` 输出;节点方块、编号、连线结构通道零改动 | 编号保留、类型文字不绘制;结构通道冒烟与渲染闸全绿 |
| 4 | 大图夹具规模(§9-4) | 12 个 BFS 层构造(跨层跳边压层后布局实得 11 层×6 槽)、含双 Boss、跨层跳边 | 满足 ≥10 层 × ≥5 槽;断言按布局实测 `maxl/maxslot` 推导 |
| 5 | 常数锚同源化方式(§9-5) | 探针直接引 `LevelMapScreen.LAYER_BASE_X/LAYER_STEP_X/NODE_HALF` 导出常量 | 与 `_fit_canvas` 公式逐项同源,无手抄数字副本 |
| 6 | 提交切分与分支命名(§9-6) | 分支 `iter34-fog`;三笔:实现与断言(`ed8e0f9f`)、⑱ 判据改绑(`4ef154b9`)、类型闸归零+探针补尾缀(`6f04f29b`) | 三笔均在 `game/` 内;报告随批落 `reports/` |
| 7 | 白名单外——审计缺漏 D1 的接线层验收手段(卡片 §9 未列,已呈报三案) | 呈报甲(补绘制输出观测面)/乙(改 §7.1 口径)/丙(单次快照降级)并推荐甲;用户回「继续未完成的任务」后按甲落地:`_draw_graph` 绘制点记录本帧绘制事实,`display_probe()` 改读该记录 | 改动集中在提交 `1970e0ef`,一笔可回退;未触碰冻结视觉件(零新画法/色值/线宽/缩放滚动),新增面为只读成员与记录赋值 |
@@ -0,0 +1,164 @@
# 迭代 34 卡④(信息迷雾可见性批)独立验收审计报告(2026-10-22)
> 审计员:未参与本卡实现的独立子代理。审计期只读源码/测试/产出物,自跑命令取证;除本报告外未写任何文件。
> 审计对象:`D:\code\g-plan2-iter34-fog`(分支 `iter34-fog`,任务指定被审 HEAD `477fd0f5`,审计起点 `43c0f3c1`)。
> 审计期分支前进说明:审计过程中分支新增 `6757c21e`(docs-only,仅 `reports/iter34-反哺点-2026-10-22.md` 追加 ⑮ 体验验证清单登记,6 行)。本报告结论按任务指定 HEAD `477fd0f5` 的代码面给出;`6757c21e` 不触及代码与测试,不影响任何判定,仅在反哺点相符性一节并入核对。
## 1. 审计范围与基线
| 项 | 内容 |
|---|---|
| 被审 diff | `git diff 43c0f3c1..HEAD`:14 个文件(`game/` 11 件:核心 1/schema 1/数据 1/呈现 1/冒烟 2/单测 4(含 2 个 .uid)/manifest 1;`reports/` 3 件)。审计期 HEAD 前进后为 15 件(多 1 件 docs-only) |
| 工作树状态 | 审计开工与收尾 `git status --short` 均为空;4 次变异注入后均 `git checkout --` 还原并复核为空 |
| 环境 | Godot 4.7.2 console;python 前置 `PYTHONIOENCODING=utf-8`;长测前清理了残留 `ui_click_probe` Godot 进程(2 个),全程串行单实例 |
| 不采信项 | 实现报告 §5.7 的「已全绿」自述仅作对照,判定一律用下面自跑读数 |
### 1.1 自跑命令与读数(原文)
| # | 命令(工作目录) | 读数原文 | 退出码 |
|---|---|---|---|
| C1 | `Godot…console.exe --headless --path . --script res://tests/unit/core/level_map_type_vis_test.gd`(`game/`) | `[level_map_type_vis_test] all green (26 checks)` | 0 |
| C2 | 同上换 `res://tests/unit/presentation/level_map_info_fog_test.gd` | `[level_map_info_fog_test] all green (19 checks)` | 0 |
| C3 | 同上 `res://tests/run_all.gd` | `[run_all] all green (40 suites)` | 0 |
| C4 | `Godot…console.exe --headless --path . res://smoke/ui_input_probe.tscn`(`game/`) | `[ui_input_probe] PASS — …十八断言全绿`(见 §4 观察项 3) | 0 |
| C5 | `python tools/run_smoke.py`(工作树根) | `[run_smoke] 摘要: 冒烟完成:1211 项检查,0 项失败`+`[run_smoke] PASS(退出码 / 摘要失败数 / 脚本错误扫描 三闸全过)`;新增 5 条「可见性冒烟」断言逐条 `[PASS]`(含〔fv4〕〔fv3〕〔fv6〕〔fv1〕) | 0 |
| C6 | `bash game/tests/static_scan.sh` | `[audit_type_hints] PASS——产品码类型闸归零(R1/R2/R3)`;`[static_scan] S9 ok` … `结构审计 PASS` | 0 |
| C7 | `python tools/audit_type_hints.py` | `[audit_type_hints] PASS——产品码类型闸归零(R1/R2/R3)` | 0 |
| C8 | 读 `game/tests/.gates/receipt.json` | `commit: 4ef154b9…`;`09 静态扫描 exit: "1"`;`all_green: false`;`changed_vs_baseline: ["09 静态扫描:红项清单变化…"]` | — |
要点:C1–C7 证明**当前代码面**的冒烟、单元、探针、静态扫描在我手上全绿;C8 证明**闸回执证据**停留在 `4ef154b9`,且该次 09 红、`all_green=false`,此后还有 2 个代码相关提交(`6f04f29b` 改 3 个 `game/` 文件、`477fd0f5`/`6757c21e` 仅文档)。这一差异见 §5.2 与 §6 缺漏 D2。
## 2. §7.1 对照表逐行结论(fv1–fv9)
判定口径:①断言真实存在且尾缀可 grep;②真实入口符合卡片该行声明;③断言强度足以在改动撤销/单点变异时变红。行内「通过」均附自跑依据。
| fv | 断言存在(文件:行,实测 grep) | 真实入口核对 | 断言强度核对 | 结论 |
|---|---|---|---|---|
| **fv1 邻近 N 层见类型** | `level_map_type_vis_test.gd:121/122/123`(层距 2 可见、3/4 不可见)、`:142/143`(入口锚层 0)、`:166/167/168`(单链退化);`smoke_all.gd:4942-4943`(真图节点 7/8 入雾)。尾缀〔fv1〕共 8 处断言+3 处注释 | 核心 `type_visible_ids()` 直调(卡片该行声明即此)+冒烟真图 L2 入口停点 | 边界两侧都断言(N 内真、N+1 假),非恒真;M1 实测 4 条红(§3) | **通过** |
| **fv2 范围外只见结构** | `level_map_info_fog_test.gd:51/54/56`(显隐与无描边)、`:96/98/100`(label 三态);`ui_input_probe.gd:59-62`(⑱ 雾下节点双通道,尾缀在 :60)。尾缀〔fv2〕共 8 处 | 单元=`ScreenScript.node_display` 纯函数(卡片允许);探针=`ro.display_probe()`。**但 `display_probe()` 内部是逐节点重调 `node_display`(`level_map_screen.gd:536-547`),不是读取实际绘制输出**——卡片该行要求「真机 `display_probe()` 读绘制面(接线层验收——防『断言在、接线坏、不红』)」不成立 | 单元决策面断言有效(M2 红);⑱ 的「图标不出示」判据自指(fog_id 正是按 `draw_icon==false` 选出,再断言其 false,恒真;「文字不出示」判据有效)。**接线层(`_draw_graph` 是否消费决策面)零断言:我注入「两处 `if bool(disp[...])` 直接改 `if true`」=模拟接线坏,C2 仍 `19 checks` 全绿、C4 仍 PASS**(§3 W1) | **缺漏**(详见 §6 D1) |
| **fv3 Boss/终点不入雾+多终点标记** | `level_map_type_vis_test.gd:144/145`(远距 Boss 在集、同层距非 Boss 不在集);`level_map_info_fog_test.gd:65/67/70/73`(双 Boss 描边、Boss 三通道在、远 Boss 不入雾、豁免不扩散);`ui_input_probe.gd:63-64`;`smoke_all.gd:4939`(真图 L2 Boss=9 在集)。尾缀〔fv3〕共 9 处断言 | 核心可见集直调+`node_display` 直调+真机 `display_probe`(卡片该行声明即此)+冒烟真图 | 单 Boss 核心豁免与双 Boss 决策面均有断言;M3/M4 报告已证(我未复跑,M2 连带 `Boss 豁免不扩散〔fv3〕` 实测红,说明该条有敏感度)。观察项:双 Boss 夹具把 7/9 直接写进 `type_vis=[1,7,9]`,未从 `type_visible_ids()` 推导「均在集」,多终点核心成员性只有单 Boss 用例覆盖同一代码分支(非阻塞,见 §4 观察项 4) | **通过**(含 1 条观察项) |
| **fv4 下一跳恒可见** | `level_map_type_vis_test.gd:132/133`(跨层跳边候选层距 N+1 仍在集、同锚非候选不在集);`smoke_all.gd:4938`(真图候选 ⊆ 可见集);`ui_input_probe.gd:66-67`(真机候选 draw_icon)。尾缀〔fv4〕共 3 处 | 核心直调+冒烟真图+探针 | 跨层跳边是反例夹具,删候选豁免会红(报告 M5;未复跑);M2 不连带此条,逻辑独立 | **通过** |
| **fv5 节点内详情不显示** | `level_map_info_fog_test.gd:87/88`(携带 `enemy_id/reward_id` 与不带者逐键相等;label 不含内容值,实际打印「战斗 · 可选」)。尾缀〔fv5〕共 3 处 | `node_display` 纯函数(卡片该行声明即此) | 逐键相等+字符串不含,两条互补;M6 报告已证(未复跑)。`node_display` 正文只读 `type`,代码审读一致 | **通过** |
| **fv6 N 进数据表** | `level_map_type_vis_test.gd:96`(真表读数 2)、`:100/102/104`(N=1 合法、0/-1 判 domain 错)、`:178/180/186`(改表 N=1/3/10 可见窗随动);`smoke_all.gd:4940-4941`(真图读表=2)。尾缀〔fv6〕共 7 处断言 | `LevelTable.validate()`+`db.level.info_visible_layers` 读值(核心直调,卡片声明即此) | 不是「读一次字段」——改表值三档窗随动+越域双值判错,强度够;M7a/M7b 报告已证(未复跑) | **通过** |
| **fv7 单圈语义** | `level_map_type_vis_test.gd:155/156/157`(visited 不豁免:远/中距回雾、近端仍显)、`:207`(`start_level_external` resume_state 重建与直入逐位一致)。尾缀〔fv7〕共 6 处 | 核心直调+真实 resume 入口 | visited 显式注入后仍不可见=单圈成立;resume 断言两侧同函数、若两者同空会平凡相等,但同套件其余组已证函数非空输出,风险可接受 | **通过** |
| **fv8 画布自适应** | `level_map_info_fog_test.gd:169`(规模实测 maxl=10/maxslot=6)、`:175`(min.x 1334.5 ≥ 1334.5)、`:177`(min.y 449.0 ≥ 449.0)、`:185`(全节点方块在画布内)、`:192/195`(双 Boss 描边、远处战斗 32 入雾);`ui_input_probe.gd:146-149`(常数锚引屏内常量)+⑬ | `canvas_probe()`/`layout_probe()`+真机探针 ⑬。⑬ 的 BFS 独立推导、常数同源 | 公式两侧独立推导(布局实测反解 maxl/maxslot,非用 `_fit_canvas` 自己的层表);M9 实测 2 条红(§3)。观察项:`layout_probe` 的 `maxl` 由 `_content_size` 居中后的坐标反解,若宽度公式少项,反解仍正确——正是 M9 能红的原因,无缺陷 | **通过** |
| **fv9 显隐接线(雾不扩可点域)** | `ui_input_probe.gd:76-91`(真机 `push_input` 点击雾下非候选节点,`route_chosen` 零发射,尾缀 :89) | 真机 push_input+真实 `_candidate_at` 命中面;判据绑 `route_chosen` 信号面(可观测提交面),未绑兜底终态 | M10 实测红,原文 `提交=[3] visible=true 选路态=true`(§3);这是本卡最强的一条 | **通过** |
**§7.1 汇总**:fv1、fv3、fv4、fv5、fv6、fv7、fv8、fv9 通过(fv3 含 1 条观察项);**fv2 判缺漏**——不是「断言不存在」,而是卡片该行声明的「读绘制面/接线层验收」用当前 `display_probe()` 实现不成立,且实测接线坏不红。
## 3. 变异复现记录(自跑)
四张 T 卡各复现一条(T1→M1、T2→M2、T3→M9、T4→M10),全部「注入→最窄闸见红→`git checkout --` 还原→复跑绿」,另加一条审计自设的接线坏注入 W1。**无复现不一致**:四条红的位置与报告 §5.4 所写逐字一致。
| # | T 卡 | 注入内容(精确位置) | 红断言原文(自跑) | 还原后读数 |
|---|---|---|---|---|
| **M1** | T1 | `game/core/level_runner.gd:433`:`absi(...) <= n` → `< n` | `[FAIL] 层距 N 内可见:锚层 1 取节点 4(层距 2)〔fv1〕`;`[FAIL] 单圈只按锚层取窗:已过近端节点 4(层距 2)仍可见〔fv7〕`;`[FAIL] 单链退化形态:入口锚层 0,下标 2 可见〔fv1〕`;`[FAIL] N 读表:N=3 时节点 5(层距 3)入窗〔fv6〕`;`4/26 项失败`,退出码 1 | `git status --short` 空;C1 复跑 `all green (26 checks)` 退出码 0 |
| **M2** | T2 | `game/presentation/views/level_map_screen.gd` `node_display`:`"draw_icon": type_shown` → `true` | `[FAIL] 雾下节点:图标与类型文字均不绘制(显隐语义,非灰化)〔fv2〕`;`[FAIL] Boss 豁免不扩散:雾下非 Boss 仍隐类型〔fv3〕`;`[FAIL] 大图呈现:入口停点远处战斗节点(编号 32,层 6)类型入雾〔fv8〕`;`3/19 项失败`,退出码 1 | `git status --short` 空;C2 复跑 `all green (19 checks)` 退出码 0 |
| **M9** | T3 | `level_map_screen.gd:_fit_canvas` 宽公式去 `+ NODE_HALF.x`(`LAYER_BASE_X + maxl*LAYER_STEP_X + 8.0`) | `[FAIL] 大图拟合:画布 min.x 覆盖最深节点(1298.0 ≥ 1334.5)〔fv8〕`;`[FAIL] 大图布局:全节点方块落在拟合画布内(origin=(0.0,0.0) size=(1298.0,449.0))〔fv8〕`;`2/19 项失败`,退出码 1 | `git status --short` 空;C2 复跑 `all green (19 checks)` 退出码 0 |
| **M10** | T4 | `level_map_screen.gd:_candidate_at`:`for nid in _cand_ids` 改为遍历全节点 id(先构 `_all_ids`) | `[ui_input_probe] FAIL — case⑱ 雾下节点点击产生提交(提交=[3] visible=true 选路态=true——雾不扩大可点域)〔fv9〕`,退出码 1 | `git status --short` 空;C4 复跑 `PASS` 退出码 0 |
| **W1**(审计自设,报告未列) | T2 接线层 | `_draw_graph` 两处条件 `if bool(disp["draw_icon"]):`/`if bool(disp["draw_label"]):` 均改 `if true:`(模拟「决策面正确、接线坏」) | **不红**:C2 `all green (19 checks)` 退出码 0;C4 `PASS` 退出码 0 | `git status --short` 空;C2 复跑 `all green (19 checks)` 退出码 0 |
W1 的结论:本卡唯一「防止接线坏」的声明(§7.1 fv2 真实入口格)在端到端两层闸上都不成立——这正是卡片要求「真机 `display_probe()` 读绘制面」的动机,而 `display_probe()` 只是决策面的第二次求值。
## 4. 测试削弱检查结论
| 检查面 | 结论 |
|---|---|
| 删除既有断言 | **无**。`git diff 43c0f3c1..HEAD -- game/smoke game/tests` 的全部删除行只有 3 行,均为 `ui_input_probe.gd` 的画布常数锚注释+`need_x2` 手抄公式行,属卡片 §7.1「旧断言预声明」第①类允许项(改为引 `LevelMapScreen.LAYER_BASE_X/LAYER_STEP_X/NODE_HALF`,判据与断言语义未变)。其余冒烟/探针文件只增不删 |
| 放宽阈值 | **无**。冒烟新增 5 条全为新判据;⑬ 容差 `-0.5` 未动;⑱ 无「非空即过」类宽松判据 |
| 缩小扫描范围 | **无**。新两套件扫描全节点;大图夹具 63 节点全量比对 |
| 真实入口换下层直调 | **fv2 一项成立**(§2、§6 D1):`display_probe` 是决策面重算,不是绘制面读取。其余各行入口与卡片声明一致 |
| 注释掉断言 | **无** |
| 越出卡片声明的削弱 | **无**(除 fv2 的入口口径问题外) |
观察项(非削弱,但影响判据强度,建议回炉 T2 时一并处理):
1. ⑱ 的「雾下图标不出示」判据自指:fog_id 按 `not disp[vnid]["draw_icon"]` 选出,再断言 `not draw_icon`,该半句恒真;有效的是「文字通道不出示」半句与「雾面节点存在」的存在性(M2 时因选不到 fog 节点而走 `case⑱ 雾面节点选取失败` 分支变红)。建议改为选区与断言解耦(如按层距/候选集独立选雾节点)。
2. fv3 双 Boss 夹具的 `type_vis` 是手写 `[1,7,9]`,只证「决策面对两个 Boss 都亮」,未从 `type_visible_ids()` 推导「两端点均在集」;核心多 Boss 成员性由单 Boss 用例覆盖同一分支,风险低。
3. C4 的 PASS 文案仍列到 ⑰ 为止(「十八断言」按 18 个 case 数),未点名 ⑱;报告 §5.2 称「探针⑱ 5 项断言」,实现实为 4 个 `_pre_fail` 判据+1 个选区前置。均为措辞/计数瑕疵,不影响判据有效性。
## 5. 报告 / 代拍板 / 反哺点相符性
### 5.1 实现报告 §5.3 六条偏差逐条核对
| 偏差 | 核对结果 |
|---|---|
| 1 大图夹具 12 BFS 层→布局 11 层(实测 maxl=10/maxslot=6) | **如实**(C2 打印「实测最大层 10/最大槽 6」;夹具源码 `tiers := 12`+跨层跳边) |
| 2 ⑱ 零提交判据改绑 `route_chosen` | **如实**(M10 红在信号面;旧终态判据被屏态/运行器兜底吸收的解释与 M10 输出 `visible=true 选路态=true` 一致)。属卡片 §8 L1 写法自救,已申报 |
| 3 类型闸 4 处 R1(`6f04f29b` 归零) | **如实**(旧 `static_scan.log` 逐行列 4 处 R1;C6/C7 现为 PASS) |
| 4 常数锚行号 `:98-99` → `:142-145` | **如实**(现文件 `:146-149` 为注释+公式;卡片原行号已 T0 订正) |
| 5 画布下限 620×256 vs 冻结文档 620×240 | **如实**(`level_map_screen.gd:303`=`Vector2(620, 256)`;`design/gdd/ux/level-map.md:68` 写 620×240;反哺点 ⑧ 已登记) |
| 6 命中面 `_candidate_at` 零改动 | **如实**(diff 该函数零 hunk;M10 是我注入才改) |
**未申报的偏差 1 条**:§5.2 fv2 行写「真机 `display_probe()` 读绘制面」,实际 `display_probe()` 只是 `node_display` 快照重算,`_draw_graph` 接线零断言(W1 证明)。报告 §5.3 未列此偏差。
**报告 §5.7 与回执不符 1 条**:报告表 09 行写「1 → 0」,读作最终已绿;但 `receipt.json` 的 `commit=4ef154b9`、`09 exit=1`、`all_green=false`,且该回执早于 `6f04f29b`(修 09 的提交)与分支尖。报告末句「最终合并回执见本批合并提交信息(起跑 commit=分支尖)」是未来义务,不是已落证据;而 §5.1 已把 T4 标「完成」。**「批末代码域闸全绿」目前只有窄验证(audit_type_hints PASS+两套件+探针),没有分支尖的 `run_all_gates.sh --code` 回执。**
(补充事实:C8 的 `changed_vs_baseline` 是「09 红项清单变化」。存量基线 `baseline.json` 里 09 本就是 exit=1 的存量红;本批先新增 4 处 R1 被判「清单变化」,修复后应转绿。所以问题不在代码现状,而在回执证据未随修复重生成。)
### 5.2 代拍板六条(卡④)白名单核对
| # | 白名单条目 | 核对结果 |
|---|---|---|
| 1 | provisional N=2 | **合规**:`level.tres` 挂 2;`validate` 只校验 int≥1;代码零硬编码 N(`level_runner.gd:429` 读 `db.level.info_visible_layers`);C1 证明改表值窗随动 |
| 2 | API/探针命名 | **合规**:`info_visible_layers`/`type_visible_ids`/`node_display`/`display_probe` 均无 `fog_` 前缀。`level_map_info_fog_test.gd` 及 `_test_fog_hides_type` 属卡片 T2 指定的测试文件名/测试内私有函数,不是跨层 API |
| 3 | 雾下呈现落点 | **合规**:编号、方块、连线绘制零改动(生产 diff 删除行只有图标/文字块重排与条件切换,色值/线宽/形制零变);C5 冒烟 1211 项、C6 渲染相关静态面全绿 |
| 4 | 大图夹具规模 | **合规**:12 BFS 层压成 11 层×6 槽、含双 Boss、含跨层跳边(1→3 层目标),满足 ≥10×≥5 |
| 5 | 常数锚同源化 | **合规**:探针直接引 `LevelMapScreen` 导出常量,无手抄副本 |
| 6 | 提交切分/分支名 | **合规**:`iter34-fog`,三笔均在 `game/`;报告/产出物在 `reports/` |
白名单外自决:**未发现**(W1 揭示的是验收口径缺失,不是实现自决)。
### 5.3 反哺点 ⑥–⑮ 对卡片 §5 的覆盖
| 卡片 §5 同步面/呈报项 | 反哺点 | 结论 |
|---|---|---|
| 关卡节点地图(N 状态行+可见性语义) | ⑥+⑩ | 覆盖 |
| 关卡节点图生成(屏预算行+下一跳兑现标注) | ⑦ | 覆盖 |
| level-map(画布公式漂移+Information Hierarchy+**雾的正式视觉规格呈报项**) | ⑧(含呈报项,明确「禁本批落文」) | 覆盖 |
| 术语表(信息迷雾 vs 视野迷雾) | ⑨ | 覆盖 |
| 待办清单 | ④+⑪ | 覆盖 |
| roadmap | ⑤+⑫ | 覆盖 |
| **超预算图升级路径(呈报项)** | ⑬ | 覆盖 |
| 实机目检三项登记 | ⑮(审计期新增提交 `6757c21e`) | 覆盖 |
| 方法论反哺 | ⑭ | 额外,合理 |
### 5.4 契约与代码纪律
| 检查 | 结论 |
|---|---|
| 契约 1/2(三层语义、Boss/终点/候选豁免) | 未破:结构通道全绘;类型由 `type_vis` 决定;Boss 在核心与决策面双豁免;候选追加进核心集 |
| 契约 3(N 只进数据表) | 未破:唯一字面量 2 是 `level_table.gd:8` 的 schema 默认值(卡片 T1 明确要求),运行期经 `db.level` 读 |
| 契约 4(显隐、零新画法) | 未破:无灰化/雾纹理/新色值/线宽变化 |
| 契约 5(单圈零记忆) | 未破:实现不读 `visited`;C1 单圈组绿 |
| 契约 6(不动冻结件/禁缩放滚动) | 未破:`_fit_canvas` 公式零改动;下限 620×256 是改前既有值(卡片 §5.3-5) |
| 契约 7(呈现只读) | 未破:呈现层不重算层距,只消费 `type_visible_ids()`;`node_display` 的 Boss 判定属卡片 T2 指定的决策面语义 |
| 契约 8 / §8 L3 | 未破:无生成器/行进/敌人表/校验放宽改动;`type_visible_ids` 无状态;候选未被雾遮 |
| core 零 UI 依赖 | 通过:`level_runner.gd` 仅注释提及 `LevelMapScreen`,无 UI 类型引用 |
| 数值零字面量 / RNG | 通过:N 读表;新代码无 `randomize()`、无自建 RNG |
| 行尾/类型闸 | 通过:核心 `.gd` 无 CRLF;`audit_type_hints` PASS(C7) |
| 头注/变更记录禁令 | 通过:新增文件头只述职责;无版本历史节;`git diff --check` 仅 3 个报告文件「EOF 空行」提示,非代码问题 |
## 6. 总判定:**不通过**
代码现状的自跑读数全部为绿(C1–C7),未发现测试削弱、契约破坏、越权自决或数值/RNG 违规。但按卡片 §7.1 与 T4/T5 的验收口径,有 **2 条缺漏**必须回炉后重审:
### D1(回炉 T2)fv2「接线层验收」未成立,且卡片 T2 与 §7.1 口径冲突
- **缺什么**:证明 `_draw_graph` 真的消费 `node_display` 输出的断言。当前 `display_probe()`(`level_map_screen.gd:536-547`)逐节点重新调用 `node_display`,与绘制路径是两次独立求值;测试与探针都只读这个快照。
- **在哪**:`level_map_info_fog_test.gd:187-195`(大图 `display_probe`)、`ui_input_probe.gd:46-68`(⑱ 前四段);证据=W1 注入(`_draw_graph` 两处条件改 `if true`)后 C2 `19 checks` 全绿、C4 PASS。
- **口径冲突**:卡片 T2 把 `display_probe()` 定义为「id → `node_display` 快照」,而 §7.1 fv2 要求它「读绘制面(接线层验收)」。实现按 T2 落地,§7.1 判据不可能由该接口兑现。这属 spec-AC 不一致,需用户裁:要么 T2 改接口/补一层「绘制输出可观测」的探针(例如自绘记录器:给 canvas 包一层记录 draw_rect/draw_texture_rect/draw_string 的测试桩,或离屏渲染取雾节点区域像素),要么由用户修改 §7.1 fv2 的验收口径(实现批不得自决)。无论走哪条,当前状态下 fv2 的撤销证明只覆盖决策函数,不覆盖接线。
- **附带**:⑱ 的雾下图标判据自指(§4 观察项 1),回炉时一并解除自指。
### D2(回炉 T4/T5)批末代码域闸无分支尖绿回执
- **缺什么**:与分支尖同 commit 的 `tools/run_all_gates.sh --code` 全绿回执。
- **在哪**:`game/tests/.gates/receipt.json`——`commit=4ef154b9`、`09 静态扫描 exit="1"`、`all_green=false`;`6f04f29b`(修 09)与 `477fd0f5` 之后未重跑。实现报告 §5.1 却把 T4 标「完成」、§5.7 表写「09 1 → 0」。报告 §5.6 自己也写明「合并前回执须与分支尖同 commit」。
- **处置**:在分支尖重跑 `tools/run_all_gates.sh --code` 落新回执(`commit` 字段=分支尖、`all_green: true`),再交复审;不得用窄验证替代。我的 C1–C7 已证明重跑应能绿,但回执是合并闸的强制证据,不能由审计代跑(会覆写既有闸产物)。
### 非阻塞观察项(不单独构成缺漏,建议随 D1/D2 一并处理)
1. ⑱ 雾下图标判据自指(§4-1)。
2. fv3 双 Boss 夹具手写 `type_vis`,多终点核心成员性无独立推导(§4-2)。
3. 探针 PASS 文案未列 ⑱,报告「5 项断言」与 4 个判据不符(§4-3)。
**合并前置**:D1、D2 关闭并复审通过前,本卡不得合并(卡片 T5、§7.1 末段)。
@@ -0,0 +1,75 @@
# 迭代 34 卡④(信息迷雾可见性批)独立验收审计·第二轮复审报告(2026-10-22)
> 审计员:第二轮独立复审子代理,未参与实现、未参与第一轮审计。职责=复核甲案是否真关掉 D1、且无新问题。
> 全程只读源码/测试/产出物+自跑最窄命令取证;除本报告外未写任何文件(注入变异均在跑完后 `git checkout --` 还原)。
> 被审对象:`D:\code\g-plan2-iter34-fog`,分支 `iter34-fog`,被审 HEAD `de9cc102`(工作树开工/收尾 `git status --short` 均空)。
> 被审改动:甲案两笔——`1970e0ef`(代码:`level_map_screen.gd`+`ui_input_probe.gd` 两文件)、`de9cc102`(账面:仅 `reports/` 三件)。审计起点=第一轮报告 `reports/iter34-卡④-验收审计-2026-10-22.md`(D1/D2 两条缺漏)。
> 口径:不采信实现报告 §5/§六 的「已全绿/已闭合」自述,凡结论必附自跑读数或文件:行。
## 1. 自跑命令与读数原文
| # | 命令(工作目录=该工作树 `game/`) | 读数原文 | 退出码 |
|---|---|---|---|
| R1 | `…console.exe --headless --path . --script res://tests/unit/core/level_map_type_vis_test.gd` | `[level_map_type_vis_test] all green (26 checks)` | 0 |
| R2 | `…--script res://tests/unit/presentation/level_map_info_fog_test.gd` | `[level_map_info_fog_test] all green (19 checks)` | 0 |
| R3 | `…console.exe --headless --path . res://smoke/ui_input_probe.tscn` | `[ui_input_probe] PASS — …⑰未开格类型微光…⑱信息迷雾绘制接线(display_probe 读实际绘制记录)增)` | 0 |
| R4 | `…--script res://tests/run_all.gd` | `[run_all] unit/contract suite entry — 40 suites`;`[run_all] all green (40 suites)` | 0 |
| R5 | `PYTHONIOENCODING=utf-8 python tools/run_smoke.py` | `[run_smoke] 摘要: 冒烟完成:1211 项检查,0 项失败`;`[run_smoke] PASS(退出码 / 摘要失败数 / 脚本错误扫描 三闸全过)`;可见性断言逐条 `[PASS]`(含〔fv6〕N 读表=2、〔fv1〕层距 3/4 节点 7/8 入雾) | 0 |
> 说明:R4/R5 只读验证单元/冒烟计数(run_all.gd 只写 `.gates/run_all_NN.log`,run_smoke.py 不写 `.gates`),**均未触碰 `receipt.json`**;未跑 `run_all_gates.sh`。R3 的 PASS 文案已点名 ⑱(第一轮观察项 3 已修)。
## 2. 四项逐条结论
### 项 1:D1 是否真关——**通过**
- `display_probe()`(`level_map_screen.gd:546-547`)现只 `return _drawn_disp`,**不再自行调用 `node_display`**(全仓 `_drawn_disp` 仅 4 处:声明 :51、逐帧 clear :444、绘制点赋值 :517、返回 :547——无第二求值面)。
- `_draw_graph` 在**实际绘制点**写记录:`boss_border`(:488,在描边画完之后)、`draw_icon`(:495,在 `if bool(disp["draw_icon"]):` 块内)、`draw_label`+`label_text`(:512-513,在 `if bool(disp["draw_label"]):` 块内),末 `_drawn_disp[nid] = rec`(:517)。记录随每帧 clear 重建(:444),只反映实际发生的绘制。
**W1 复现(第一轮判「不红」的那一发)**——把 :494/:511 两处 `if bool(disp["draw_icon"]|["draw_label"]):` 均改 `if true:`(`git diff` 净 2 行、无其它改动):
- 呈现单元套件红:`ERROR: [FAIL] 大图呈现:入口停点远处战斗节点(编号 32,层 6)类型入雾〔fv8〕`(`level_map_info_fog_test.gd:195`)+`[level_map_info_fog_test] 1/19 项失败`,退出码 **1**。
- 输入探针红:`[ui_input_probe] FAIL — case⑱ 雾下节点类型仍出示(图标=true 文字=true——范围外只见结构)〔fv2〕`,退出码 **1**。
- `git checkout -- game/presentation/views/level_map_screen.gd` → `git status --short` 空 → 复跑 R2 `all green (19 checks)` 退出码 0。
**第一轮 W1=两入口全绿;本次两入口全红**——D1 关掉。**且两红原文与实现报告 §5.4 M11 行逐字一致**(§5.2 fv2 行「M11 绘制处绕开决策面 → 单元与探针双红(实测)」相符)。
**第二发新变异(验记录面不是摆设)**——绘制处条件保持原样(雾下节点实际不画图标),仅在 `_drawn_disp[nid] = rec` 前插一行无条件 `rec["draw_icon"] = true`(记录谎称画了图标、实际没画):
- 呈现单元红:同〔fv8〕:195 一条,退出码 1;探针红:`case⑱ 雾下节点类型仍出示(图标=true 文字=false——范围外只见结构)〔fv2〕`(文字通道未被污染故=false,证断言确实逐值读记录),退出码 1。
- 还原后 R2 `all green (19 checks)`。→ 记录的值是承重的(非仅存在性检查),断言确实消费绘制记录内容。
### 项 2:⑱ 自指是否解除——**通过**
`ui_input_probe.gd` case⑱(:44-73)现况:
- 选区=`fog_id`:`vnid != cur_id and not cands.has(vnid) and not vis.has(vnid)`(:56)——只读核心面 `vis = runner.type_visible_ids()`(:47)、`cur_id`(:48)、`cands`(:43),**不读 `disp`**(源码注释 :57 亦写明「选区只按核心可见集判,不读绘制记录」)。
- 断言=`if bool(disp[fog_id]["draw_icon"]) or bool(disp[fog_id]["draw_label"])`(:64)——读呈现绘制记录。
- Boss 选区按 `type=="boss"` 读节点数据(:54)、候选选区按 `cands[0]`(核心),断言分别读 `disp[boss_id]["boss_border"]`(:68)与 `disp[cands[0]]["draw_icon"]`(:71)。
选区全部来自核心/节点数据面,断言全部来自呈现绘制记录面——**两个不同面**,非第一轮「按 `not disp[...]["draw_icon"]` 选、再断言其 `not draw_icon`」的恒真自指。W1 变异能红即实证该断言不再恒真。→ 自指解除。
### 项 3:有无新削弱或新越权——**通过**
- **删断言/放宽阈值/缩小扫描面/真实入口降级**:`git diff 43c0f3c1..HEAD -- game/` 的删除非注释行仅两类——① `level_map_screen.gd` 原「无条件绘制图标/字形/类型文字」块(改为经 `node_display` 决策面消费+写记录,属卡片 T2 本体,非删断言);② `ui_input_probe.gd` 旧手抄公式 `need_x2 = 70.0 + maxl2*122.0 + 26.0 + 8.0` 与旧 PASS 文案行。**无一条断言被删**。旧 `26.0`→新 `LevelMapScreen.NODE_HALF.x`(36.5,:153-154),阈值抬高 10.5px=**变严**(第一轮 F11 记探针低报仍绿,本次同源化后更紧),容差 `-0.5` 未动(:156)。真实入口 fv2 由「决策面快照」升为「绘制记录」=变强不变弱。
- **`_drawn_disp` 是否只读观测面**:全仓仅 `level_map_screen.gd` 内 4 处引用(见项 1),**无新 `draw_rect/draw_texture_rect/draw_string`**、无色值/线宽/缩放滚动改动、不写存档、不引入持久状态语义;`clear`+记录赋值=纯只读观测面(仿 `canvas_probe`/`layout_probe` 先例)。甲案两文件之外零触达 core/data/smoke_all。
- **早期返回空记录会否致平凡通过**:`_draw_graph` 早返回(`_runner == null or not visible`,:442)时记录不清空不重建。已核**无平凡通过面**——① 呈现单元 :192 先断言 `disp.has(boss_ids[0]) and disp.has(boss_ids[1])`,空记录即判红(且 :195 对缺失键 `disp[32]` 取 null 会报错、同样不放过),当前 19 项全绿反证记录已填充;② 探针 :59 前置判据 `not disp.has(fog_id) or not disp.has(boss_id) or not disp.has(int(cands[0]))` → `_pre_fail`(甲案新增),空记录走「记录缺位」红分支。两入口都对空记录设了拦截。
- **代拍板第 7 行相符性**:卡片 §9 六条白名单(:216-221)无一条覆盖「把 `display_probe` 从 `node_display` 快照改为绘制记录观测面」这一接线层验收手段,属白名单外;代拍板第 7 行(`iter34-代拍板-2026-10-22.md:32`)如实备案「呈报甲/乙/丙三案并推荐甲,按甲落地:`_draw_graph` 绘制点记录本帧事实、`display_probe()` 改读该记录」,约束核验「改动集中 `1970e0ef` 一笔可回退、未触冻结视觉件、新增面为只读成员与记录赋值」——与代码实际做法、与本复审实测逐项一致。非静默越权。
### 项 4:D2 与账面相符——**通过**
- `receipt.json`:`commit = de9cc102`=HEAD(分支尖)✓;`all_green = true` ✓;`changed_vs_baseline = []` ✓;闸项 01/02/03/04/05/09/10 全 `exit 0 / green`(09 静态扫描由「基线红→现绿·改善」,见 `inherited_red`);11 对拍按档位规则 NEED-APPROVAL(数值零变更,不发起,合规)。
- 计数由自跑独立佐证:02 单元 **40 套件**(R4 `all green (40 suites)`)、01 冒烟 **1211 项 0 失败**(R5 摘要原文)——与回执 01/02 的 `exit 0` 相互印证。
- 实现报告:§5.1 提交列表含 `1970e0ef`(:159「审计 D1 回炉 T2」)✓;§5.2 fv2 行与 §5.4 M11 行的红断言原文与项 1 实测逐字对得上 ✓;反哺点 ⑯(:100-104)写清「卡片 T2 :139 接口描述=`id → node_display 快照`滞后,与 §7.1 fv2『读绘制面』矛盾,须由**写卡段订正**、实现期不改卡片」✓。
## 3. 第一轮两条缺漏的闭合判定
- **D1(fv2 接线层验收未成立/⑱ 自指)=已闭合**。`display_probe()` 改读 `_draw_graph` 实际绘制记录、不再二次求值;第一轮判「不红」的 W1 注入(两处绘制条件 `→ if true`)本次在**呈现单元〔fv8〕与输入探针〔fv2〕两入口同时判红**,红原文与 M11 记录一致;⑱ 选区改按核心可见集/候选集/当前位独立选点、断言读绘制记录,自指解除;新变异(污染记录值)两入口亦红,证明记录值承重。
- **D2(缺分支尖代码域全绿回执)=已闭合**。回执 `commit=de9cc102`=HEAD、`all_green=true`、`changed_vs_baseline=[]`,01/02/09 全绿,计数经自跑(1211 项 / 40 套件)独立印证。
## 4. 总判定:**通过(可合并)**
甲案真关掉了 D1(W1 变异从「不红」变「双入口红」,实证接线层断言生效、记录非摆设、自指解除),D2 有分支尖全绿回执且与自跑读数相符。改动为只读观测面、零新画法/色值/线宽/缩放滚动/存档、无测试削弱、无静默越权(白名单外手段已备案并可整笔回退)。第一轮三条非阻塞观察项中,⑱ 自指(观察项 1)与 PASS 文案/计数(观察项 3)已随甲案修除;观察项 2(fv3 双 Boss 夹具手写 `type_vis`)按卡片 T2 指定写法保留、核心多 Boss 成员性由 `level_map_type_vis_test`〔fv3〕覆盖,维持非阻塞。
**唯一遗留(账面措辞,非阻塞、不构成缺漏)**:实现报告 §六 D2 行与 §5.7 行文字仍引用旧复跑 commit `8b9c6989`(甲案代码前的那次分支尖),而当前权威回执为 `de9cc102`;权威闸证据(`receipt.json`)本身正确、与 HEAD 一致、`all_green=true`,仅账面引用未随甲案后重跑刷新。合并前若再跑一次回执则会自然对齐;不影响 D2 闭合判定。
结论:卡④ D1/D2 两条缺漏均已闭合,无新削弱、无新越权,**通过,可合回 master**。
+67
View File
@@ -35,3 +35,70 @@
- 文件与位置:`roadmap.md` 迭代 34 行(两卡并列,本卡为卡③)与顶部「当前位」节
- 改成:卡③状态记为已实现;卡④(信息迷雾可见性)仍在同一迭代内推进;「当前位」按实际进度改写。
- 依据:迭代实现批的收尾义务(`iter` 技能第 5 步账面随批);实现批不写该文件,换代归批后收尾或用户发令。
## ⑥ 关卡节点地图.md:调参表 N 状态行与可见性语义注记
- 文件与位置:`design/gdd/systems/冒险循环/关卡节点地图.md` :172(调参表「信息迷雾可见层数」行)、:100(可见范围「邻近 N 层」节)
- 改成:调参表状态由「定值批落数据表」改为「已落数据表 provisional 2(`level.tres` `info_visible_layers`)」;:100 节补实现语义三句——层距=入口 BFS 层差、Boss/终点与当前候选双豁免、单圈零记忆(已过节点回雾)。
- 依据:卡④ T1 已实现并在 `level_runner.type_visible_ids()` 钉死;`level_map_type_vis_test` 五组断言〔fv1〕〔fv3〕〔fv4〕〔fv7〕覆盖。
## ⑦ 关卡节点图生成.md:屏预算约束行与「下一跳必在可见范围」兑现标注
- 文件与位置:`design/gdd/systems/冒险循环/关卡节点图生成.md` :105–114(调参表)、:83(「下一跳必在可见范围」)
- 改成:调参表补一行「图包络 ≤ 屏预算(1280×800 下约 10 层×8 槽;超预算只许限参数档,禁改画布冻结公式)」;:83 该句标注「实现侧已兑现:候选集强制豁免类型可见性」。
- 依据:卡④契约 6 与 G6 定值(参数限图);`type_visible_ids()` 候选豁免断言〔fv4〕。
## ⑧ level-map.md:画布公式漂移订正+类型可见性层级行
- 文件与位置:`design/gdd/ux/level-map.md` :68(节点图区「冻结公式」句)
- 改成:宽 70+层深×122+34 → 70+层深×122+44.5(`NODE_HALF.x`36.5+8);高 52+槽位×58+26+8 → 52+槽位×58+25+24(`NODE_HALF.y`25+标签行 24);下限 620×240 → 620×256(抬高容纳标签行)。Information Hierarchy 节补「类型可见性(邻近 N 层显隐)」层级行。
- 依据:`level_map_screen.gd:289–304` 现行 `_fit_canvas` 公式与大图拟合断言〔fv8〕;下限定值 256 是当前代码与渲染闸全绿的实际约束。**注意**:本条只订正文档记数,不动冻结件本身(画布公式语义与像素档位不变),是否接受改写由用户裁。
- **呈报项(禁本批落文)**:「雾的正式视觉规格」(雾纹理/灰化遮罩/明度层)属冻结件域,本卡只做显隐语义最小呈现,视觉规格待用户裁后另立。
## ⑨ 术语表.md:登记「信息迷雾」并区别于「视野迷雾」
- 文件与位置:`design/gdd/术语表.md`
- 改成:新增词条「信息迷雾」=关卡节点图上按邻近层数隐藏节点类型的信息可见性;与「视野迷雾」(战斗棋盘按英雄曼哈顿半径遮挡)并列,注明两系统同词根易混、代码标识符禁 `fog_` 前缀。
- 依据:卡④契约与风险 3;实现侧 API 全用 `info_visible_layers`/`type_visible_ids`/`node_display`/`display_probe`。
## ⑩ 关卡节点地图.md:Boss 描边口径冲突择一
- 文件与位置:`design/gdd/systems/冒险循环/关卡节点地图.md` :67
- 改成:Boss 描边口径「封印黑 #000000」与 `level-map.md`/现役代码「紫赤+深墨环」不一致,请文档批核对后择一(现役实现与视觉终稿样张 v1 为紫赤+深墨环)。
- 依据:卡④ G8 定值(实现随现役代码+level-map.md);本批未动描边视觉。
## ⑪ 待办清单.md:卡④条目状态按停卡实况回写
- 文件与位置:`待办清单.md` 中卡④登记条目
- 改成:**不得记为「已实现」**——实现与代码域全量闸已完成(回执 `commit=6f547c35`、`all_green=true`),但独立验收审计判不通过、缺漏 D1(fv2 接线层验收与卡片 T2 对 `display_probe` 的定义互相矛盾)待用户裁决,卡④ 停在审计门。状态写「实现完成·审计不通过待裁(迭代 34)」,缺口记:「`display_probe` 只做决策面二次求值,`_draw_graph` 接线零断言;审计注入接线坏不红」;并写明实现报告路径。裁决后按用户选择推进(改验收接口 → 回炉 T2;改卡片 §7.1 口径 → 改卡后重交审计)。
- 依据:`reports/iter34-卡④-验收审计-2026-10-22.md` §6 D1;五段流水线状态机(`doc-conventions` §12);实现批不写该文件,回写归批后收尾或用户发令。
## ⑫ roadmap.md:迭代 34 行状态刷新(卡③已完成、卡④停审计门)
- 文件与位置:`roadmap.md` 迭代 34 行与顶部「当前位」节
- 改成:卡③(敌人表深度带换代批)记为已实现并已合回;卡④(信息迷雾可见性批)记为「实现完成·独立验收审计不通过待裁」,迭代 34 不得标记完成;「当前位」按此实况改写。
- 依据:迭代实现批收尾义务;实现批不写该文件,换代归批后收尾或用户发令。
## ⑬ 呈报项:超预算图策略升级路径
- 位置:无文档落点(用户在会话中裁)
- 内容:若后续定值批需要大于「约 10 层×8 槽」的完整可见图,两条路都动冻结件——等比缩放(动「20px 烘焙 1:1」「2/3/4px 折线」)或滚动视口(新交互范式)。本卡按 G6 走参数限图,两案均需用户裁。
- 依据:卡④风险 2 与 G6 淘汰案。
## ⑭ test-conventions.md:验收断言应绑可观测提交面(方法论反哺)
- 文件与位置:`design/engineering/test-conventions.md` §9.4(撤销/变异证明)
- 改成:补一句判据——端到端断言的判据应绑「被测改动特有的可观测提交面」(信号发射、事件、入参),不绑多层防御下的终态;否则单点变异可能被下游兜底吸收、终态不变而假绿。示例:探针「雾不扩可点域」首版只看屏/选路态终态,命中面放宽的变异仍绿;改绑 `route_chosen` 发射面后变异即红。
- 依据:卡④ T4 实测(`提交=[3] visible=true 选路态=true`;终态与未点击一致)。
## ⑮ 体验验证清单.md:登记卡④三条实机目检项
- 文件与位置:`体验验证清单.md`
- 改成:登记三条待真人目检项(只登记、不阻塞)——①雾下可读性观感(未知类型节点是否一眼可辨为「未知」而非空节点);②多终点图 Boss 标记观感(双 Boss 是否都带描边且可辨);③大图完整可见观感(11 层×6 槽图是否完整落在屏内、编号不重叠)。判据与观测点见 `reports/iter34-实现报告-2026-10-22.md` §5.5。
- 依据:卡④ T5「实机目检总清单三条」+iter 技能第 5 步账面随批;实现批禁写该清单,登记归文档批或用户发令。
## ⑯ 需求卡片:T2 的 `display_probe` 接口描述与 §7.1 fv2 口径一致化
- 文件与位置:`reports/需求卡片-信息迷雾可见性批-2026-10-21.md` :139(T2 第三条)
- 改成:「新增 `func display_probe() -> Dictionary`(id → `node_display` 快照,只读断言面,仿 `canvas_probe` 先例)」→「(id → 本帧实际绘制事实:图标/文字/描边/文案,由 `_draw_graph` 在实际绘制点写入,只读断言面)」,与 §7.1 fv2 真实入口格「真机 `display_probe()` 读绘制面(接线层验收)」对齐。
- 依据:迭代 34 卡④ 独立验收审计 D1(`reports/iter34-卡④-验收审计-2026-10-22.md` §6);实现按 §7.1 验收面(甲案)落地,卡片 T2 的接口描述是滞后一侧,须由写卡段订正——实现期不改卡片。
+122 -1
View File
@@ -154,4 +154,125 @@
## 五、卡④ 信息迷雾可见性批
另行施工,完成后在本文追加对应章节。
### 5.1 工作树与任务卡状态
工作树 `D:\code\g-plan2-iter34-fog`,分支 `iter34-fog`,起自卡③合并后的 master `43c0f3c1`。提交:`ed8e0f9f`(T1–T3 实现与单测/冒烟/探针)、`4ef154b9`(⑱ 零提交判据改绑信号面)、`6f04f29b`(类型闸归零+探针补雾下文字通道断言)、`1970e0ef`(审计 D1 回炉 T2:绘制记录观测面+⑱ 选区解耦)。
| T 卡 | 内容 | 状态 |
|---|---|---|
| T0 | 事实坐实与基线读数 | 完成(改前基线:冒烟 1206 项 0 失败/单元套件全绿/探针全绿) |
| T1 | N 落表+越域校验+`type_visible_ids()`+核心套件 | 完成(提交 `ed8e0f9f`) |
| T2 | `node_display` 决策面+`display_probe`+`_draw_graph` 接线+呈现套件 | 完成(提交 `ed8e0f9f`,类型闸修补 `6f04f29b`) |
| T3 | 探针常数锚同源化+大图夹具(11 层×6 槽) | 完成(提交 `ed8e0f9f`) |
| T4 | 冒烟断言+探针⑱+变异汇总+代码域全量闸 | 完成(见 §5.4、§5.7) |
| T5 | 三份产出物+独立验收审计+合并 | 审计两轮完成(首轮不通过→甲案回炉→复审通过),合并进行中 |
### 5.2 实际改动—验收对照表
生产侧落点:`game/core/level_runner.gd`(`type_visible_ids()` :422–440、`_bfs_layers()` :443–462);`game/presentation/views/level_map_screen.gd`(`node_display()` :420–437、`_draw_graph` 消费 :478、`display_probe()` :536–547);`game/data/schemas/level_table.gd:8`(字段)、:23–24(越域校验);`game/data/tables/level.tres:7`(`info_visible_layers = 2`);`game/smoke/ui_input_probe.gd:142–145`(常数锚同源化)、:44–90(case⑱);`game/smoke/smoke_all.gd:4938–4943`(真图可见性断言组)。
| fv | 需求点(简) | 验收断言(文件:行) | 层级 | 真实入口 | 撤销/变异结果 |
|---|---|---|---|---|---|
| fv1 | 邻近 N 层见类型 | `level_map_type_vis_test.gd:121`、:122、:123(层距边界);:142、:143(入口锚层 0);:166、:167、:168(单链退化);`smoke_all.gd:4942`(真图) | 单元+集成 | `LevelRunner.type_visible_ids()` 直调;冒烟真图读面 | M1 `<=N`→`<N` → 边界断言红(实测) |
| fv2 | 范围外只见结构 | `level_map_info_fog_test.gd:51`、:54、:56(决策面显隐);:96、:98、:100(label 三态);`ui_input_probe.gd:65`(真机绘制记录双通道);`level_map_info_fog_test.gd:195`(大图绘制记录) | 单元+探针 | `node_display` 纯函数(决策面)+真机 `display_probe()` 读 `_draw_graph` 实际绘制记录(接线面) | M2 决策面 `draw_icon` 强制 true → 红(实测);M11 绘制处绕开决策面 → 单元与探针双红(实测) |
| fv3 | Boss 不入雾+多终点标记 | `level_map_type_vis_test.gd:144`、:145;`level_map_info_fog_test.gd:65`、:67、:70、:73;`ui_input_probe.gd:69`;`smoke_all.gd:4939` | 单元+探针+集成 | `type_visible_ids()`/`node_display`;真机 `display_probe()` | M3 删核心 Boss 豁免 → 红;M4 删决策面 Boss 豁免 → 红(实测) |
| fv4 | 下一跳恒可见 | `level_map_type_vis_test.gd:132`、:133(跨层跳边);`smoke_all.gd:4938`;`ui_input_probe.gd:72` | 单元+集成+探针 | 同上;真图候选读面 | M5 删候选豁免 → 红(实测) |
| fv5 | 节点内详情不显示 | `level_map_info_fog_test.gd:87`、:88(携带 `enemy_id/reward_id` 夹具) | 单元 | `node_display` 纯函数 | M6 label 拼 `enemy_id` → 红(实测) |
| fv6 | N 进数据表 | `level_map_type_vis_test.gd:96`(表读数 2)、:100、:102、:104(越域 validate)、:178、:180、:186(改表随动);`smoke_all.gd:4940–4941` | 单元+集成 | `LevelTable.validate()`/`db.level.info_visible_layers`;冒烟读表 | M7a 删越域校验 → 红;M7b N 硬编码 2 → 红(实测) |
| fv7 | 单圈语义 | `level_map_type_vis_test.gd:155`、:156、:157(visited 不豁免);:207(续玩重建同值) | 单元 | `type_visible_ids()`+`start_level_external` resume 路径 | M8 visited 累积可见 → 红(实测) |
| fv8 | 画布自适应 | `level_map_info_fog_test.gd:169`(夹具规模)、:175(宽)、:177(高)、:185(全节点在画布内)、:192、:195;`ui_input_probe.gd:151–154`(常数锚同源)+⑬ | 单元+探针 | `canvas_probe()`/`layout_probe()`;真机 push_input | M9 去 `NODE_HALF.x` 项 → 红(实测) |
| fv9 | 显隐接线(雾不扩可点域) | `ui_input_probe.gd:94`(点击雾下非候选节点 `route_chosen` 零发射) | 探针 | 真机 `push_input`+`display_probe()` | M10 命中面放宽到全节点 → ⑱ 红(实测,提交=[3]) |
覆盖说明:`game/` 内新增断言按上表逐条挂〔fv#〕尾缀,fv1–fv9 全覆盖,无未证条目;`level_map_type_vis_test` 26 项、`level_map_info_fog_test` 19 项、冒烟新增 5 项(1206→1211)、探针⑱ 4 项判据+1 项选区存在性前置。
### 5.3 卡片与实际改动面的偏差(逐条说明)
1. **大图夹具层数换算**:卡片写「11 层×6 槽」,夹具按 12 个 BFS 层构造——跨层跳边(层 1→层 3)会把目标节点压到 BFS 层 2、其后续链整体上移一层,布局实得 11 层(实测 `maxl=10`、`maxslot=6`)。断言按布局实测推导(`maxl >= 10`),规模不变、语义不变。
2. **⑱ 零提交判据改绑信号面**:按卡片原写法(命中面放宽到全节点 → ⑱ 红)首轮实测仍绿——点击确实穿透并提交,但雾下非战斗节点让本屏保持激活、运行器候选校验又把非法编号拒掉,终态与未点击时相同。改绑 `route_chosen` 发射面后单点变异即红(`提交=[3]`)。属卡片 §8 L1「断言写法」自救范围;同时给⑱ 各断言补 fv2/fv3/fv4/fv9 尾缀。
3. **类型闸新增红**:T4 首轮全量闸暴露新增 4 处 R1(`Dictionary` 未参数化 1 处、`Array` 未参数化 3 处),已参数化归零(`6f04f29b`);修复后 09 转绿(相对基线为改善)。
4. **常数锚行号**:卡片写 `ui_input_probe.gd:98-99`,工作树实落点 :142–145(T0 复核行号),同源化方式=直接引 `LevelMapScreen` 导出常量,未新增副本。
5. **画布下限漂移**:`_fit_canvas` 现行为 `max(Vector2(620, 256))`,`level-map.md:68` 冻结公式写「下限 620×240」——本卡不动冻结件,登记反哺点。
6. **命中面零改动**:`_candidate_at`(:373–386)卡内要求零改动,实现保持候选集循环,fv9 的变异证明正落在此函数。
### 5.4 变异验证记录表(注入 → 最窄闸见红 → 还原)
| # | 注入内容 | 最窄闸 | 红断言(原文摘要) | 还原确认 |
|---|---|---|---|---|
| M1 | `type_visible_ids` 层距判定 `<= n` 改 `< n` | `level_map_type_vis_test` | 层距 N 内可见:锚层 1 取节点 4(层距 2)〔fv1〕;单链退化形态:入口锚层 0,下标 2 可见〔fv1〕(连带 fv6/fv7 各 1 条) | `git checkout` 还原,26 项全绿 |
| M2 | `node_display` 的 `draw_icon` 强制 true | `level_map_info_fog_test` | 雾下节点:图标与类型文字均不绘制〔fv2〕;Boss 豁免不扩散〔fv3〕;大图远处节点入雾〔fv8〕 | 还原,19 项全绿 |
| M3 | 删 `type_visible_ids` 的 Boss 豁免分支 | `level_map_type_vis_test` | Boss 恒显:层距 6 的末位 Boss 仍在可见集〔fv3〕;单链编号空间=数组下标〔fv1〕 | 还原,26 项全绿 |
| M4 | 删 `node_display` 的 Boss 豁免(`type_shown` 只看可见集) | `level_map_info_fog_test` | Boss 豁免独立于可见集:不在 type_vis 的 Boss 仍出示类型〔fv3〕 | 还原,19 项全绿 |
| M5 | 删 `type_visible_ids` 候选豁免追加段 | `level_map_type_vis_test` | 候选恒显:跨层跳边候选(层距 N+1)仍在可见集〔fv4〕 | 还原,26 项全绿 |
| M6 | `label_text` 拼接 `node.get("enemy_id")` | `level_map_info_fog_test` | 决策面不消费内容键〔fv5〕;label_text 不含内容值(实际「战斗goblin_secret · 可选」)〔fv5〕 | 还原,19 项全绿 |
| M7a | 删 `LevelTable.validate` 越域判据(`if false`) | `level_map_type_vis_test` | N 越域 0/-1:validate 判 domain 错〔fv6〕 | 还原,26 项全绿 |
| M7b | `type_visible_ids` 的 N 硬编码 2(不读表) | `level_map_type_vis_test` | N 读表:N=1 时节点 4 出窗〔fv6〕;N=3 时节点 5 入窗〔fv6〕;N≥层高全可见〔fv6〕 | 还原,26 项全绿 |
| M8 | 可见集加 `visited_ids().has(nid)`(累积可见) | `level_map_type_vis_test` | 单圈回雾:已过远端节点 0(层距 5)不因 visited 豁免〔fv7〕;中距节点 2 不可见〔fv7〕 | 还原,26 项全绿 |
| M9 | `_fit_canvas` 宽公式去 `NODE_HALF.x` 项 | `level_map_info_fog_test` | 大图拟合:画布 min.x 覆盖最深节点(1298.0 ≥ 1334.5)〔fv8〕;全节点落在画布内〔fv8〕 | 还原,19 项全绿 |
| M10 | `_candidate_at` 命中面放宽到全节点 | `ui_input_probe`(⑱) | 雾下节点点击产生提交(提交=[3] visible=true 选路态=true)〔fv9〕 | `git checkout` 还原,探针 PASS |
| M11 | `_draw_graph` 图标/文字两处条件改 `if true`(绕开决策面=接线坏) | `level_map_info_fog_test`+`ui_input_probe`(⑱) | 大图呈现:入口停点远处战斗节点(编号 32,层 6)类型入雾〔fv8〕;case⑱ 雾下节点类型仍出示(图标=true 文字=true——范围外只见结构)〔fv2〕 | `git checkout` 还原,19 项全绿+探针 PASS |
### 5.5 实机目检总清单(只登记,不阻塞合并)
| # | 项目 | 观测点 | 状态 |
|---|---|---|---|
| 1 | 雾下可读性观感 | 未知类型房间是否一眼可辨为「未知」而非「漏画」;编号仍在、类型图标与文字不出现 | 待用户试玩 |
| 2 | 多终点 Boss 标记观感 | 双 Boss 图上两个终点的紫赤描边是否都清楚可辨 | 待用户试玩 |
| 3 | 大图完整可见观感 | 大图(11 层×6 槽)整幅在画布内、无节点被裁切或挤在一角 | 待用户试玩 |
### 5.6 遗留读数义务
- 数值零变更(`info_visible_layers` 是呈现参数,不进战斗结算),本卡不发起模拟跑批(MC 档位规则)。
- 合并后主区需 `--editor --quit` 重刷类名缓存,再跑一次代码域全量闸复跑,读数写入合并提交信息。
- 合并前回执须与分支尖同 commit(回执 `commit` 字段)。
### 5.7 全量代码闸读数
T4 里程碑跑批 `tools/run_all_gates.sh --code`,起跑 commit `4ef154b9`:
| 闸 | 退出码 | 对基线 |
|---|---|---|
| 01 冒烟全量 | 0 | 一致(1211 项检查 0 失败) |
| 02 单元套件 | 0 | 一致(40 套件,含本卡新增 2 套件) |
| 03 探针 --click | 0 | 一致 |
| 04 探针 --full | 0 | 一致 |
| 05 渲染闸 | 0 | 一致 |
| 09 静态扫描 | 1 → 0 | 新增 4 处 R1(容器未参数化)→ `6f04f29b` 修复后归零,由红转绿(改善) |
| 10 熵增闸 | 0 | 一致 |
| 11 回放确定性对拍 | NEED-APPROVAL | 本卡数值零变更,按档位规则不发起(需用户批准) |
`6f04f29b` 修复后窄验证:`audit_type_hints` PASS;两套件 26+19 项全绿;`ui_input_probe` PASS。
D1 回炉后在分支尖复跑(`de9cc102`,含代码笔 `1970e0ef`):`all_green: true`、`changed_vs_baseline: []`、01 冒烟 1211 项 0 失败、02 单元 40 套件全绿、03/04 探针绿、05 渲染闸绿、09 静态扫描 0(对基线「改善」)、10 熵增闸 0、11 对拍按档位规则 NEED-APPROVAL。此前那一次复跑(`8b9c6989`,甲案代码之前)已被本次取代。
## 六、卡④ 独立验收审计
审计报告:`reports/iter34-卡④-验收审计-2026-10-22.md`(未参与实现的子代理执行;被审 HEAD `6757c21e`;自跑 40 套件、探针、冒烟 1211 项,另自设变异注入)。
**第一轮结论:不通过**——2 条缺漏,无测试削弱、无契约破坏、无越权自决、无数值/RNG 违规。M1/M2/M9/M10 四条变异由审计自跑,「红的位置与报告 §5.4 逐字一致,无复现不一致」。
| 缺漏 | 内容 | 本批处置 |
|---|---|---|
| D2 回炉 T4/T5 | 缺与分支尖同 commit 的 `--code` 全绿回执(旧回执停在 `4ef154b9`、09 红、`all_green=false`) | **已闭合**:在分支尖重跑全量代码域闸,回执 `commit=de9cc102`(甲案代码回炉之后重跑)、`all_green=true`、`changed_vs_baseline=[]`(见 §5.7) |
| D1 回炉 T2 | fv2「接线层验收」未成立:`display_probe()` 是逐节点重调 `node_display` 的快照,与 `_draw_graph` 的实际绘制是两次独立求值;审计注入「`_draw_graph` 两处条件改 `if true`」模拟接线坏,单元 19 项与探针仍全绿。审计判为**卡片 T2 对 `display_probe` 的定义与 §7.1 fv2「读绘制面」要求互相矛盾(spec-AC 不一致)** | **甲案回炉(提交 `1970e0ef`)**:呈报后用户指令「继续未完成的任务」,按呈报推荐案甲落地——`_draw_graph` 在描边/图标/文字三处实际绘制点写入本帧绘制事实(新只读成员 `_drawn_disp`),`display_probe()` 改读该记录、不再二次求值;探针⑱ 选区改按核心 `type_visible_ids()` 独立选雾节点,解除「按记录选、再断言记录」自指;单元大图组两处呈现断言随动读绘制记录。新增撤销证明 M11(绕开决策面直接画 → 单元〔fv8〕与探针〔fv2〕双红)。该项在 §9 白名单外,已在代拍板追认单第 7 行备案,可整笔回退。 |
审计附三条非阻塞观察项,处置:第 1、3 条已随甲案修除,第 2 条按卡片 T2 指定写法保留(核心多 Boss 成员性由 `level_map_type_vis_test` 的〔fv3〕用例覆盖同一分支)——
1. 探针 ⑱ 的「雾下图标不出示」判据自指——`fog_id` 正是按 `not draw_icon` 选出再断言其 `not draw_icon`,该半句恒真;有效的是文字通道半句与存在性判定(M2 时因选不到雾节点走「选取失败」分支变红)。建议选区与断言解耦(按层距/候选集独立选雾节点)。
2. fv3 双 Boss 夹具手写 `type_vis=[1,7,9]`,未从 `type_visible_ids()` 推导两端点均在集;核心多 Boss 成员性由单 Boss 用例覆盖同一分支,风险低。
3. 探针 PASS 文案只列到 ⑰、未点名 ⑱,§5.2 原称「探针⑱ 5 项断言」实为 4 个 `_pre_fail` 判据+1 个选区前置。两处均已订正:⑱ 已列入 PASS 文案,计数改写为「4 判据+1 前置」。
### 6.1 第二轮复审结论(`reports/iter34-卡④-验收审计-复审-2026-10-22.md`)
被审 HEAD `de9cc102`(=分支尖=回执 commit)。执行者仍是未参与实现的子代理,自跑呈现单元、核心单元、输入探针与冒烟读数,并自己复现第一轮判「不红」的那发注入。
| 项 | 结论 | 复审自跑证据 |
|---|---|---|
| 项 1 D1 是否真关 | **通过** | 注入 `_draw_graph` 图标/文字两处条件改 `if true` → 呈现单元〔fv8〕与探针〔fv2〕双红,探针红原文 `case⑱ 雾下节点类型仍出示(图标=true 文字=true——范围外只见结构)〔fv2〕`;另发「只污染记录值」的新变异同样双红,证记录承重 |
| 项 2 ⑱ 自指解除 | **通过** | 选区改按核心 `type_visible_ids()`/候选集/当前位独立选点,断言读绘制记录,两侧不同面 |
| 项 3 新削弱/新越权 | **通过** | 无删断言、无放宽阈值(探针常数锚 26→36.5 属变严,容差 -0.5 未动);新增面为只读观测,零新画法/色值/线宽/缩放滚动/存档;白名单外手段已在代拍板第 7 行备案、可一笔回退 |
| 项 4 D2 与账面相符 | **通过** | `receipt.json` `commit=de9cc102`、`all_green=true`、`changed_vs_baseline=[]`;自跑冒烟 1211 项 0 失败、单元 40 套件绿 |
**闭合判定:D1 已闭合、D2 已闭合,总判定通过(可合并)。** 观察项 1 与 3 已随甲案修除;观察项 2 按卡片 T2 指定写法保留,核心多 Boss 成员性由 `level_map_type_vis_test`〔fv3〕覆盖,维持非阻塞。复审指出的一处账面措辞(§5.7 与 §六 仍引旧复跑 commit `8b9c6989`)已在本节随文订正。
**合并状态:两轮审计均通过,合回 master。** 卡③ 已在 `43c0f3c1` 合回。