修复: 卡①T3——probe_gate --full 段落码四探针收编(ui_probe/ui_tune_probe/t17_defer_probe/fx_probe——游离闸外只能手敲→入重闸;timeout 120=实测 17.4/49.6/63.0/21.9s 的 2-7×余量;PASS 语义+退出码闸+残留批末闸随骨架)+头注释「shot_probe 禁入本闸……归真人目检」纪律句删除改写(2026-10-07 用户授权=历史偷懒标记;渲染面归 render_gate 正主)+轻闸默认段零删减零改动(--full 只增不改,契约红线②)。ui_layout_probe 零断言诊断件补最小布局断言转断言件(1280/1920 两档:基座 1280x800/顶层三区互斥不越界/board_view 含于 D 区/1920 档钉迭代 9 分辨率案甲契约——stretch=canvas_items 下逻辑视口与四区矩形恒定,分辨率维度不重复建闸;headless resize 实测生效;首跑 PASS 退出码 0;闸归属归卡③裁点②候裁本批不入闸)。probe_gate 两形态实测:默认段全绿+--click --full 全绿四探针全 PASS 残留 0

This commit is contained in:
DKChan committed 2026-10-08 19:20:59 +08:00
1 parent a7861aec5a
commit c0c066da0c
2 files changed
+112 -5

No files matched your search

+60 -1
View File
@@ -1,6 +1,11 @@
# VERTICAL SLICE - NOT FOR PRODUCTION
# Date: 2026-09-13(四区布局诊断探针——"内容未满幅/棋盘底裁切"回归定位:打印窗口/视口/四区实际矩形
# 与最小尺寸、展开旗标,对照 battle.md §Layout 1280×800 基座规格)
# 迭代 19 卡① T5(2026-10-08):零断言诊断件补最小布局断言转断言件——1280/1920 两档:
# ①基座 1280×800(battle.md §Layout)②顶层三区(B=stage/C=info_panel/D=board_zone)互不重叠不越视口
# ③board_view(=board_zone 子节点别名)不越视口且含于 D 区 ④1920 档钉分辨率案甲契约(迭代 9 案甲——
# stretch=canvas_items/aspect=keep 下逻辑视口与四区矩形恒定=构图与基准档一致);退出码/PASS-FAIL 语义
# 具备闸可接形态(闸归属归卡③裁点②候裁,本批不入闸)。原诊断打印面全保留。
# 运行:Godot_console.exe --headless --path . res://smoke/ui_layout_probe.tscn
extends Node
@@ -43,7 +48,61 @@ func _ready() -> void:
root_box.anchor_left, root_box.anchor_top, root_box.anchor_right, root_box.anchor_bottom,
root_box.offset_left, root_box.offset_top, root_box.offset_right, root_box.offset_bottom, root_box.size])
print("board_view cell_size=%s board=%s" % [main.board_view.get("cell_size"), main.board_view.board()])
get_tree().quit(0)
# ── 最小布局断言(迭代 19 卡① T5——1280/1920 两档;语义见头注) ──
var problems: PackedStringArray = []
var vr: Rect2 = get_viewport().get_visible_rect()
if vr.size != Vector2(1280, 800):
problems.append("基座视口 %s ≠ 1280x800(battle.md §Layout)" % vr.size)
var azones := {"stage": main.stage, "info_panel": main.info_panel, "board_zone": main.board_zone}
var arects := {}
for k in azones:
var actl: Control = azones[k]
if actl == null:
problems.append("%s=null" % k)
continue
var ar := Rect2(actl.global_position, actl.size)
arects[k] = ar
if ar.size.x <= 0.0 or ar.size.y <= 0.0:
problems.append("%s 零尺寸 %s" % [k, ar.size])
elif not vr.encloses(ar):
problems.append("%s 越视口 %s ⊄ %s" % [k, ar, vr])
var bvc: Control = main.board_view
if bvc == null:
problems.append("board_view=null")
else:
var br := Rect2(bvc.global_position, bvc.size)
if not vr.encloses(br):
problems.append("board_view 越视口 %s ⊄ %s" % [br, vr])
if arects.has("board_zone") and not arects["board_zone"].encloses(br):
problems.append("board_view 越出 board_zone(%s ⊄ %s)" % [br, arects["board_zone"]])
var akeys := arects.keys()
for i in range(akeys.size()):
for j in range(i + 1, akeys.size()):
if arects[akeys[i]].intersects(arects[akeys[j]]):
problems.append("顶层区重叠 %s×%s(%s ∩ %s)" % [akeys[i], akeys[j], arects[akeys[i]], arects[akeys[j]]])
# 1920 档(Q4 注记对应面:单档 1280 闸+本两档断言钉 1920 构图恒等——分辨率维度不重复建闸)
get_window().size = Vector2i(1920, 1080)
for i in range(4):
await get_tree().process_frame
var vr2: Rect2 = get_viewport().get_visible_rect()
if vr2 != vr:
problems.append("1920 档逻辑视口漂移 %s ≠ %s(案甲:stretch 基座恒定)" % [vr2, vr])
for k in azones:
var actl2: Control = azones[k]
if actl2 == null:
continue
var ar2 := Rect2(actl2.global_position, actl2.size)
if arects.has(k) and ar2 != arects[k]:
problems.append("1920 档 %s 矩形漂移 %s ≠ %s(案甲:构图与基准档一致)" % [k, ar2, arects[k]])
if problems.is_empty():
print("[layout_probe] PASS — 1280/1920 两档全过(基座1280x800/顶层三区互斥不越界/board_view含于D区/案甲构图恒定)")
get_tree().quit(0)
else:
for p in problems:
print("[layout_probe] FAIL — " + p)
print("[layout_probe] FAIL — %d 项断言未过" % problems.size())
get_tree().quit(1)
func _dump_ctrl(c: Control, depth: int) -> void:
+52 -4
View File
@@ -5,17 +5,21 @@
# 段:ui_input_probe=默认必跑;ui_struct_probe=默认必跑(ui-struct-probe mini-loop 2026-10-05 注册——
# 全 UI 屏结构断言:按钮互压/等宽/出屏/零尺寸/标题屏双列);ui_contrast_probe=默认必跑(UI 设计对齐批
# T2 2026-10-06 注册——UI 文字对比度机检 ≥4.5:1 无区域例外,测点表随批维护);--click=加跑 ui_click_probe 行为走查
# (自退出+退出码闸;超时多半=探针未适配新停点层,归 probe适配批);shot_probe 禁入本闸——
# 必须窗口化运行(headless 无渲染面,探针内已有 fail-fast 护栏),归真人目检。
# 用法: tools/probe_gate.sh [game目录] [--click] 缺省 game 目录=脚本所在仓库的 game/(worktree 内自动指向该 worktree)
# (自退出+退出码闸;超时多半=探针未适配新停点层,归 probe适配批)。
# --full 段(迭代 19 卡① T3 收编 2026-10-08——重闸件):ui_probe/ui_tune_probe/t17_defer_probe/fx_probe
# 四件带断言探针收进(此前游离在一切闸外只能手敲);轻闸默认段断言面零删减零改动(--full 只增不改)。
# 渲染面归 render_gate.sh 正主(窗口化:shot_probe 七屏+fx_shot/board_shot 取证+棋盘 golden 逐像素)——
# 旧头注「shot_probe 禁入本闸……归真人目检」纪律句随三闸口径扩容改写退役(2026-10-07 用户授权=历史偷懒标记)。
# 用法: tools/probe_gate.sh [game目录] [--click] [--full] 缺省 game 目录=脚本所在仓库的 game/(worktree 内自动指向该 worktree)
# 依赖: Git Bash(coreutils timeout/taskkill) + PowerShell;Godot 路径可用环境变量 GODOT_BIN 覆盖。
set -u
G="${GODOT_BIN:-/d/code/godot/Godot_v4.7.2-stable_win64_console.exe}"
REPO="$(cd "$(dirname "$0")/.." && pwd)"
GAME=""; WITH_CLICK=0
GAME=""; WITH_CLICK=0; WITH_FULL=0
for a in "$@"; do
case "$a" in
--click) WITH_CLICK=1 ;;
--full) WITH_FULL=1 ;;
*) GAME="$a" ;;
esac
done
@@ -85,6 +89,50 @@ if [ "$WITH_CLICK" -eq 1 ]; then
fi
fi
# ── --full 收编段(迭代 19 卡① T3 2026-10-08——四件带断言探针入闸;实测时长 ui_probe 17.4s/
# ui_tune_probe 49.6s/t17_defer_probe 63.0s/fx_probe 21.9s,timeout 120=2-7×余量) ──
if [ "$WITH_FULL" -eq 1 ]; then
echo "======== ui_probe(--full 收编) ========"
timeout 120 "$G" --headless --path "$GAME_WIN" res://smoke/ui_probe.tscn >"$TMP/flp.log" 2>&1
st=$?; kill_orphans
grep -E "\[ui_probe\]" "$TMP/flp.log" | tail -2
if [ "$st" -eq 124 ] || [ "$st" -eq 137 ]; then
echo "[probe_gate] FAIL — ui_probe 超时挂死(exit=$st),孤儿已清"; _rc=1
elif ! grep -q "PASS" "$TMP/flp.log"; then
echo "[probe_gate] FAIL — ui_probe 未见 PASS(exit=$st)"; _rc=1
fi
echo "======== ui_tune_probe(--full 收编) ========"
timeout 120 "$G" --headless --path "$GAME_WIN" res://smoke/ui_tune_probe.tscn >"$TMP/flt.log" 2>&1
st=$?; kill_orphans
grep -E "\[tune_probe\]" "$TMP/flt.log" | tail -2
if [ "$st" -eq 124 ] || [ "$st" -eq 137 ]; then
echo "[probe_gate] FAIL — ui_tune_probe 超时挂死(exit=$st),孤儿已清"; _rc=1
elif ! grep -q "PASS" "$TMP/flt.log"; then
echo "[probe_gate] FAIL — ui_tune_probe 未见 PASS(exit=$st)"; _rc=1
fi
echo "======== t17_defer_probe(--full 收编) ========"
timeout 120 "$G" --headless --path "$GAME_WIN" res://smoke/t17_defer_probe.tscn >"$TMP/fld.log" 2>&1
st=$?; kill_orphans
grep -E "\[t17_defer\]" "$TMP/fld.log" | tail -2
if [ "$st" -eq 124 ] || [ "$st" -eq 137 ]; then
echo "[probe_gate] FAIL — t17_defer_probe 超时挂死(exit=$st),孤儿已清"; _rc=1
elif ! grep -q "PASS" "$TMP/fld.log"; then
echo "[probe_gate] FAIL — t17_defer_probe 未见 PASS(exit=$st)"; _rc=1
fi
echo "======== fx_probe(--full 收编) ========"
timeout 120 "$G" --headless --path "$GAME_WIN" res://smoke/fx_probe.tscn >"$TMP/flx.log" 2>&1
st=$?; kill_orphans
grep -E "\[fx_probe\]" "$TMP/flx.log" | tail -2
if [ "$st" -eq 124 ] || [ "$st" -eq 137 ]; then
echo "[probe_gate] FAIL — fx_probe 超时挂死(exit=$st),孤儿已清"; _rc=1
elif ! grep -q "PASS" "$TMP/flx.log"; then
echo "[probe_gate] FAIL — fx_probe 未见 PASS(exit=$st)"; _rc=1
fi
fi
echo "======== 残留检查(批末闸) ========"
left="$(orphans | wc -l | tr -d ' ')"
total="$(tasklist 2>/dev/null | grep -ci '^Godot' || true)"