diff --git a/design/engineering/test-conventions.md b/design/engineering/test-conventions.md index ed7a6974..851e47d9 100644 --- a/design/engineering/test-conventions.md +++ b/design/engineering/test-conventions.md @@ -116,7 +116,7 @@ **判据出处行锚(2026-11-05 立,自 2026-11-05 起对文件名日期不早于该日的需求卡片生效;旧卡不回头改,被编入迭代开工前由写卡段按本粒度补挂)**:对照表「需求点」列每行必须带**判据出处行锚**——该行验收判据所依据的现行文档句子,格式「`<文档相对路径>:<行号>`」。现行文档=`design/` 全域现行文档(含 `ux/` 交互规格与 art-bible 的判据行);已退役的需求卡片不是现行文档,不得充当判据出处。作用=断言预期值从规格句抄出,不从实现反推:实现行为与规格句冲突时断言红;规格缺席的行写不出锚,即停卡退回写卡段(那是需求澄清缺口,不是测试缺口)。机检=`tools/pipeline_gate.py` 判据 C5(锚格式与指向存在性,按卡文件名日期分流)+`tools/capability_audit.py` 链式锚检查(断言→套件→能力行→系统文档,见 §8.9)。 -**测试函数的判据出处注记(2026-11-06 立)**:`game/tests/**` 与 `game/probe/**` 内每个**验证函数**(函数体含 `check(`/`check_quiet(`/`_problems.append(`/`push_error(` 判定调用的函数——定义行与 `_check(` 前缀不作判定计)必须带至少一条**判据出处注记**,格式「`# oracle: :<行号> <判据一句>`」——指针在前、判据摘要句在后;锚形态两档:行号锚(默认)与节锚(`「节名」<行关键词>`)——所指文档整节重排时同批把行号锚重锚为节锚,免行号漂移(2026-11-07 架构收窄批立),断言预期值的出处随断言走:断言红时读注记即达出处文档句,零查表。指针空间=`design/` 全域现行文档(行为测试锚 owner 系统文档「验收标准」句或 `ux/` 规格句;惯例类测试〔封装扫描、判定通道纪律、驱动契约〕锚规约条款行);`game/sim/` 不进扫描面(测量面直构惯例)。与链式锚的分工:链式锚(断言→套件→能力行→系统文档)不变、属义务清单层;本注记属执行证据层、写在断言文件内,非独立账本(§8.9 法则 4 不变)。写新测试函数时当场挂注记;被指规格句改行号时随批维护指针——死指针即红。局限如实声明:注记是被动文本,句内容改而行数不变时机检抓不到(与卡片判据 C5 同限)。机检=`tools/capability_audit.py` 判据出处注记道(覆盖检查+指针存在性;扫描面零文件自检红)。规格缺席写不出锚=发现规格缺口:记发现不造锚、收尾呈报,禁锚到非现行文档凑数。 +**测试函数的判据出处注记(2026-11-06 立)**:`game/tests/**` 与 `game/probe/**` 内每个**验证函数**(函数体含 `check(`/`check_quiet(`/`_problems.append(`/`push_error(` 判定调用的函数——定义行与 `_check(` 前缀不作判定计)必须带至少一条**判据出处注记**,格式「`# 判据出处: :<行号> <判据一句>`」——指针在前、判据摘要句在后;锚形态两档:行号锚(默认)与节锚(`「节名」<行关键词>`)——所指文档整节重排时同批把行号锚重锚为节锚,免行号漂移(2026-11-07 架构收窄批立),断言预期值的出处随断言走:断言红时读注记即达出处文档句,零查表。指针空间=`design/` 全域现行文档(行为测试锚 owner 系统文档「验收标准」句或 `ux/` 规格句;惯例类测试〔封装扫描、判定通道纪律、驱动契约〕锚规约条款行);`game/sim/` 不进扫描面(测量面直构惯例)。与链式锚的分工:链式锚(断言→套件→能力行→系统文档)不变、属义务清单层;本注记属执行证据层、写在断言文件内,非独立账本(§8.9 法则 4 不变)。写新测试函数时当场挂注记;被指规格句改行号时随批维护指针——死指针即红。局限如实声明:注记是被动文本,句内容改而行数不变时机检抓不到(与卡片判据 C5 同限)。机检=`tools/capability_audit.py` 判据出处注记道(覆盖检查+指针存在性;扫描面零文件自检红)。规格缺席写不出锚=发现规格缺口:记发现不造锚、收尾呈报,禁锚到非现行文档凑数。 **验收档申报(2026-11-04 立,自 2026-11-05 起对文件名日期不早于该日的需求卡片生效;旧卡不回头改)**:每张需求卡片在头部信息区(与设计事实源声明同区)申报一个验收档,三档:高/中/低。判据=失败代价单维——这条改动做错了,后果随存档或结算传播的(存档写读与迁移、RNG 流、战斗结算公式与乘区、经济入账、数值表结构校验)=高;后果玩家可见但不损持久状态的(常规玩法逻辑、门控、交互逻辑、呈现数据面)=中;后果即看即知且无状态残留的(文案、纯呈现样式、布局微调)=低。一张卡触多档按最高档申报;申报由写卡段落笔,用户批卡(U0)时确认或改判。档位只调节 §8.7 审计深度——闸机与 CI 的域划分、选闸算法、全量强制档一概不因档位变化,真实入口、判据绑定面、禁削弱等验收闭合判据全部照旧。未申报档位的卡一律按高档全量审计。机检=`tools/pipeline_gate.py` 判据 C4:卡内须含「验收档:高/中/低」申报行。 @@ -152,7 +152,7 @@ 2. 抽查判据绑定面:断言从真实入口进入、钉在被测改动的特有可观测提交面上,且当轮真实跑批执行过; 3. 检查测试削弱:删除断言、放宽阈值、缩小扫描面、换下层直调,逐处要卡片申报或用户批准。 4. 核对内部字段直查的受控例外:直查行是否已在对照表注明理由(该行为无公开可观测面可钉)。 -5. 核对判据出处:抽查断言的预期值能否从其判据出处行锚(§8.3)的规格句独立写出——预期值只在实现里有的(同义反复,oracle 镜像实现),判红。 +5. 核对判据出处:抽查断言的预期值能否从其判据出处行锚(§8.3)的规格句独立写出——预期值只在实现里有的(同义反复,判据镜像实现),判红。 **审计深度分级(2026-11-04 立)**:审计按卡内申报的验收档(§8.3)逐卡定深度;梯度只落在昂贵的判断件上,机械且堵造假向量的两件(削弱检查、例外核对)三档全保留不抽。中/低档省略的测试复跑以远端 CI 读数为执行证据——`tools/ci_check.sh <合并提交>` 的现查输出(commit+run 号+conclusion)是机器产物,run 号在远端永久可复核,审计报告照抄该行即可;照抄前先核对读数必须是「绿」——「未验」(零触发批跑闸步全跳过)与「不可判」不作证据,那种批的回补办法是等一次含代码面的合回或用户自发全量回归(2026-11-04 用户裁:回执等待件退役,证据由落盘文件改为现查读数;「不采信实现者自述已全绿」的口径不变): diff --git a/design/gdd/08-Alpha版本标准.md b/design/gdd/08-Alpha版本标准.md index 144eff1c..3e335e3c 100644 --- a/design/gdd/08-Alpha版本标准.md +++ b/design/gdd/08-Alpha版本标准.md @@ -2,7 +2,7 @@ > **一句话定位**:本文定义这个项目的 **Alpha 版本包含哪些东西**——它是里程碑 M3 的完成标准,也是判断"还差什么"的对照表。 > **本文只列条目,不写内容**:每样东西是什么、规则怎么走,一律归各自的权威文档,本文只给指路链接。想知道某样东西的定义,请点链接,不要在本文里找解释。 -> **状态**:**已定稿(v1.28)**——2026-10-13 用户令定稿,历次升版明细见 git 提交史。Alpha 的内容范围自此冻结:增删条目一律须经用户裁决。 +> **状态**:**已定稿(v1.30)**——2026-10-13 用户令定稿,历次升版明细见 git 提交史。Alpha 的内容范围自此冻结:增删条目一律须经用户裁决。 > **成文**:2026-10-13。 ## 本文怎么用 @@ -152,12 +152,10 @@ Alpha 内以玩法循环本身的内容与表现为主(棋盘、关卡、战 | 主角立绘三态 | [角色设计](../art/character-design.md) | 在役 | | 状态图标 | [美术圣经](../art/art-bible.md) | 在役 | | 战斗演出链(弹道 / 受击 / 血条 / 灰化) | [战斗表现](systems/战斗循环/战斗表现.md) | 在役 | -| 逐行结算排播 | [settlement-summary](../ux/settlement-summary.md) | 在役 | | 减动效开关 | [设置与本地化](systems/表现与支撑/设置与本地化.md) | 在役 | | 全局纹理过滤设为邻近采样 | [待办清单](../../待办清单.md) | 在役(default_texture_filter=0+平滑渐变件三处显式 LINEAR 白名单,翻转面全枚举闭合) | | UI 字体(全局像素字,Fusion Pixel 单套单字重) | [美术圣经](../art/art-bible.md) §7.4 | 在役(现状即终稿——拉丁沿用自带字形不另接专件、不上第二字重;信息层级手段=字号档差+墨色深浅) | | 战斗一屏样张(界面美术的终稿闸) | [美术圣经](../art/art-bible.md) §1.4 | 在役(样张整体过闸——用户实机目检核销,沿革查 git 提交史;目标规格与五项实装定值单点=art-bible 五张规格表。主角+三 Boss 重产依赖照旧;站桩帧动画已改排 Beta,见「六 · Alpha 不含」) | -| UI 氛围层与九宫格切片观感修 | [待办清单](../../待办清单.md) | 部分在役(光柱硬边已修=连续 alpha 渐变;未结半=九宫格切片错位——Alpha 内做最小修复:核对素材尺寸,必要时重出九宫格素材,全套素材重出排 Beta;出口=结算屏与图例屏错位消失,渲染闸+用户目检通过) | | UI 元素细节修(滑轨填充 / 图标垫块 / 留白 / 开发件外泄) | [待办清单](../../待办清单.md) | 在役(四子项中滑轨填充注销,余三件——图标垫块明度差降档/商店+营地布局修/诊断钮迁调试浮窗——全落地) | --- diff --git a/game/probe/board_shot_probe.gd b/game/probe/board_shot_probe.gd index 76dcdade..325c4c19 100644 --- a/game/probe/board_shot_probe.gd +++ b/game/probe/board_shot_probe.gd @@ -26,7 +26,7 @@ var _cur_settlement = null # 当关 settlement(身份回调读取面—— func _ready() -> void: -# oracle: design/engineering/test-conventions.md:84 (棋盘截图取证——渲染闸采集组) +# 判据出处: design/engineering/test-conventions.md:84 (棋盘截图取证——渲染闸采集组) # 运行前提=窗口化真渲染面(shot_probe 同款护栏——headless 下 frame_post_draw 永不触发+视口纹理恒空) if DisplayServer.get_name() == "headless": print("[board_shot] FAIL — 本探针必须窗口化运行(headless 无渲染面,截图必空);现行事实源=tools/render_gate.sh 取证段") @@ -182,7 +182,7 @@ func _ready() -> void: # 判据:环外径像素 ÷ 格边 落 0.82±1px;封印格最外圈 1px 框最暗值与相邻未封印未开格同位框最暗值差 ≤1/255 #(halo 在 0.455×格边归零——格边框不应被压暗;相邻未开格同砖纹理同套瓦片为无封印参照)。 func _seal_evidence(tag: String, view: Node, settlement: Object, off_img: Image, out: String) -> void: -# oracle: design/engineering/test-conventions.md:84 (封印印记像素取证组) +# 判据出处: design/engineering/test-conventions.md:84 (封印印记像素取证组) var ms = settlement.minesweeper var seal_cell := Vector2i(-9, -9) var ref_cell := Vector2i(-9, -9) @@ -290,7 +290,7 @@ func _probe_identity_lookup(c: Vector2i): # 双帧逐像素比对:所有变化像素必须落在生效格的内缘带内 # (de < cell÷8——带外含砖心零侵入=禁整格染色/禁越圈);每个生效格须有实绘像素(不空转)。 func _check_dual_frames(tag: String, view, glow_cells: Dictionary, off_img: Image, on_img: Image) -> void: -# oracle: design/engineering/test-conventions.md:56 (判定上报通道——验证函数组) +# 判据出处: design/engineering/test-conventions.md:56 (判定上报通道——验证函数组) var board = view.board() if board == null: _problems.append("%s 双帧比对取板失败(view.board() 为 null)" % tag) diff --git a/game/probe/fx_probe.gd b/game/probe/fx_probe.gd index 5ea3d1ad..365a8d6b 100644 --- a/game/probe/fx_probe.gd +++ b/game/probe/fx_probe.gd @@ -8,7 +8,7 @@ extends Node func _ready() -> void: -# oracle: design/gdd/systems/战斗循环/战斗表现.md:148 (结算演出——挖掘期零打扰组) +# 判据出处: design/gdd/systems/战斗循环/战斗表现.md:148 (结算演出——挖掘期零打扰组) await get_tree().process_frame var problems: Array = [] diff --git a/game/probe/fx_shot_probe.gd b/game/probe/fx_shot_probe.gd index 71c2daa7..a953779b 100644 --- a/game/probe/fx_shot_probe.gd +++ b/game/probe/fx_shot_probe.gd @@ -21,7 +21,7 @@ var _problems: Array = [] func _ready() -> void: -# oracle: design/engineering/test-conventions.md:84 (特效截图取证——渲染闸采集组) +# 判据出处: design/engineering/test-conventions.md:84 (特效截图取证——渲染闸采集组) var args := OS.get_cmdline_user_args() out_dir = args[0] if args.size() >= 1 and args[0] != "" else "user://qa-fx" DirAccess.make_dir_recursive_absolute(out_dir) @@ -108,7 +108,7 @@ func _ready() -> void: func _snap(tag: String) -> void: -# oracle: design/engineering/test-conventions.md:56 (判定上报通道——验证函数组) +# 判据出处: design/engineering/test-conventions.md:56 (判定上报通道——验证函数组) await RenderingServer.frame_post_draw var img: Image = get_viewport().get_texture().get_image() if img == null or img.is_empty(): @@ -118,7 +118,7 @@ func _snap(tag: String) -> void: func _fail(msg: String) -> void: -# oracle: design/engineering/test-conventions.md:56 (判定上报通道——验证函数组) +# 判据出处: design/engineering/test-conventions.md:56 (判定上报通道——验证函数组) _problems.append(msg) push_error("[fx_shot_probe] FAIL — " + msg) get_tree().quit(1) diff --git a/game/probe/layout_probe.gd b/game/probe/layout_probe.gd index 3b9f88e1..e0e8ddf9 100644 --- a/game/probe/layout_probe.gd +++ b/game/probe/layout_probe.gd @@ -19,7 +19,7 @@ var _est_reads: Dictionary = {} # 逐档 13/14 板推定读数留痕(label func _ready() -> void: -# oracle: design/gdd/systems/表现与支撑/HUD框架.md:264 (战斗屏三区几何与棋盘格边长——分辨率档位组) +# 判据出处: design/gdd/systems/表现与支撑/HUD框架.md:264 (战斗屏三区几何与棋盘格边长——分辨率档位组) await get_tree().process_frame var main: Node = load("res://presentation/main.tscn").instantiate() add_child(main) @@ -59,7 +59,7 @@ func _ready() -> void: # 一份不变量断言,逐档代入——代码量与档数无关 func _check_one(label: String, main: Node) -> void: -# oracle: design/gdd/systems/表现与支撑/HUD框架.md:264 (单档几何断言组) +# 判据出处: design/gdd/systems/表现与支撑/HUD框架.md:264 (单档几何断言组) var vr: Rect2 = get_viewport().get_visible_rect() if vr.size != Vector2(VIEWPORTS[0]["size"]) and vr.size.y < 1.0: _problems.append("[%s] 逻辑视口退化 %s" % [label, vr.size]) diff --git a/game/probe/level_map_shot_probe.gd b/game/probe/level_map_shot_probe.gd index a201979c..f637f333 100644 --- a/game/probe/level_map_shot_probe.gd +++ b/game/probe/level_map_shot_probe.gd @@ -11,7 +11,7 @@ extends Node const SEED_L3 := 910212 # 深图固定种子(与 level_map_viewport_probe 同源——图确定性承载) func _ready() -> void: -# oracle: design/engineering/test-conventions.md:84 (关卡画面截图取证——载入守卫组) +# 判据出处: design/engineering/test-conventions.md:84 (关卡画面截图取证——载入守卫组) var args := OS.get_cmdline_user_args() var out_dir := args[0] if args.size() > 0 else "user://" await get_tree().process_frame @@ -45,7 +45,7 @@ func _settle() -> void: func _make_runner(entry: bool, node_id: int): -# oracle: design/engineering/test-conventions.md:84 (判定上报通道——验证函数组) +# 判据出处: design/engineering/test-conventions.md:84 (判定上报通道——验证函数组) var rng = load("res://core/rng_service.gd").new() rng.new_adventure(SEED_L3) var runner = load("res://core/level_runner.gd").new(get_node("/root/ConfigDB"), rng) @@ -85,7 +85,7 @@ func _deepest_with_outs(screen, runner) -> int: func _shot(out_dir: String, fname: String) -> void: -# oracle: design/engineering/test-conventions.md:84 (判定上报通道——验证函数组) +# 判据出处: design/engineering/test-conventions.md:84 (判定上报通道——验证函数组) DirAccess.make_dir_recursive_absolute(out_dir) # 落盘目录自建(save_png 对缺目录静默失败——刷新链不预建) var img := get_viewport().get_texture().get_image() var err := img.save_png(out_dir.path_join(fname)) diff --git a/game/probe/level_map_viewport_probe.gd b/game/probe/level_map_viewport_probe.gd index a83c93d3..42118dbe 100644 --- a/game/probe/level_map_viewport_probe.gd +++ b/game/probe/level_map_viewport_probe.gd @@ -22,14 +22,14 @@ var _runner # 当前停点的单关 runner(open_choices 驱动随记—— func _check(desc: String, ok: bool) -> void: -# oracle: design/ux/level-map.md:3 (判定上报通道——验证函数组) +# 判据出处: design/ux/level-map.md:3 (判定上报通道——验证函数组) _checks += 1 if not ok: _problems.append(desc) func _ready() -> void: -# oracle: design/ux/level-map.md:3 (关卡画面视口跟随——卷轴视口组) +# 判据出处: design/ux/level-map.md:3 (关卡画面视口跟随——卷轴视口组) await get_tree().process_frame await get_tree().process_frame var host := Control.new() @@ -62,7 +62,7 @@ func _ready() -> void: ## R1 浅图整幅居中无裁切+画布入视口件承载(画布=视口首子件——setup 注入序) func _probe_shallow_no_crop(screen, vp) -> void: -# oracle: design/ux/level-map.md:3 (浅层不裁切组) +# 判据出处: design/ux/level-map.md:3 (浅层不裁切组) _runner = _make_runner_entry(1, SEED_L1) screen.open_choices(_cand_nodes(_runner), _runner) await get_tree().process_frame @@ -81,7 +81,7 @@ func _probe_shallow_no_crop(screen, vp) -> void: ## R5 前置+深图入口停点:锚点=入口组包围盒中心夹紧(spec :101——多入口并列取包围盒居中) func _probe_deep_entry_clamp(screen, vp) -> void: -# oracle: design/ux/level-map.md:3 (深层入口钳制组) +# 判据出处: design/ux/level-map.md:3 (深层入口钳制组) _runner = _make_runner_entry(3, SEED_L3) screen.open_choices(_cand_nodes(_runner), _runner) await get_tree().process_frame @@ -175,7 +175,7 @@ func _probe_clamp_bounds_and_columns(screen, vp) -> void: ## R6 拖拽不触发选路提交;阈值另一侧完整点击仍提交(提交语义零改动) func _probe_drag_no_submit(screen, vp) -> void: -# oracle: design/ux/level-map.md:3 (判定上报通道——验证函数组) +# 判据出处: design/ux/level-map.md:3 (判定上报通道——验证函数组) # 重建到中段可居中停点(候选=停点出边——候选节点居屏中可拖可达) var stops := _centerable_stops(screen, vp) if stops.size() < 3: @@ -214,7 +214,7 @@ func _probe_drag_no_submit(screen, vp) -> void: ## R2 停点切换后当前节点居中(视口中线投影 x=640±2——视口满屏宽即屏中线) func _probe_follow_anchor(screen, vp) -> void: -# oracle: design/ux/level-map.md:3 (判定上报通道——验证函数组) +# 判据出处: design/ux/level-map.md:3 (判定上报通道——验证函数组) var stops := _centerable_stops(screen, vp) if stops.size() < 3: _problems.append("R2 可居中停点不足(=%d)" % stops.size()) @@ -230,7 +230,7 @@ func _probe_follow_anchor(screen, vp) -> void: ## R7 平滑滚动有 tween 中间帧;减动效开=位置即达(画布坐标域判定) func _probe_smooth_scroll_reduced_motion(screen, vp) -> void: -# oracle: design/ux/level-map.md:3 (判定上报通道——验证函数组) +# 判据出处: design/ux/level-map.md:3 (判定上报通道——验证函数组) var saved_scale: float = UiKit.motion_scale UiKit.motion_scale = 1.0 var stops := _centerable_stops(screen, vp) @@ -270,7 +270,7 @@ func _probe_smooth_scroll_reduced_motion(screen, vp) -> void: ## R8 指引件可见性与几何(深图超窗——像素级判据②③) func _probe_guidance_chrome(screen, vp) -> void: -# oracle: design/ux/level-map.md:3 (判定上报通道——验证函数组) +# 判据出处: design/ux/level-map.md:3 (判定上报通道——验证函数组) var band_l: Control = vp.get_node_or_null(NodePath("FadeL")) var band_r: Control = vp.get_node_or_null(NodePath("FadeR")) var chip: Control = vp.get_node_or_null(NodePath("PanHint")) @@ -302,7 +302,7 @@ func _probe_shallow_guidance_hidden(screen, vp) -> void: ## 入口停点 runner(defer_entry——选路态挂起、候选=入口节点) func _make_runner_entry(level_index: int, seed_val: int): -# oracle: design/ux/level-map.md:3 (判定上报通道——验证函数组) +# 判据出处: design/ux/level-map.md:3 (判定上报通道——验证函数组) var rng = load("res://core/rng_service.gd").new() rng.new_adventure(seed_val) var runner = load("res://core/level_runner.gd").new(get_node("/root/ConfigDB"), rng) @@ -313,7 +313,7 @@ func _make_runner_entry(level_index: int, seed_val: int): ## 中段停点 runner(断点续玩重建——图由种子+参数档重生成同图,零 RNG 消耗) func _make_runner_at_stop(level_index: int, seed_val: int, node_id: int): -# oracle: design/ux/level-map.md:3 (判定上报通道——验证函数组) +# 判据出处: design/ux/level-map.md:3 (判定上报通道——验证函数组) var rng = load("res://core/rng_service.gd").new() rng.new_adventure(seed_val) var runner = load("res://core/level_runner.gd").new(get_node("/root/ConfigDB"), rng) @@ -388,7 +388,7 @@ func _extreme_node(pos: Dictionary, nodes: Array, first: bool) -> Dictionary: func _finish() -> void: -# oracle: design/ux/level-map.md:3 (判定上报通道——验证函数组) +# 判据出处: design/ux/level-map.md:3 (判定上报通道——验证函数组) if _checks == 0: _problems.append("零断言执行(断言数下限闸——三硬闸③)") if _problems.is_empty(): diff --git a/game/probe/probe_coverage_recorder.gd b/game/probe/probe_coverage_recorder.gd index c13abde8..b45dcfad 100644 --- a/game/probe/probe_coverage_recorder.gd +++ b/game/probe/probe_coverage_recorder.gd @@ -199,7 +199,7 @@ func _seen_into(node: Node, keys: Array[String]) -> void: # ---- 落盘(JSONP 式 .js——file:// 页面