From 21cd0f2e050753d8992dac58c6d431a095ef0aa1 Mon Sep 17 00:00:00 2001 From: DKChan <524912269@qq.com> Date: Wed, 28 Oct 2026 04:14:35 +0800 Subject: [PATCH] =?UTF-8?q?=E5=B7=A5=E7=A8=8B(=E6=8C=82=E6=AD=BB=E9=98=B2?= =?UTF-8?q?=E6=8A=A4=C2=B7probe=5Fgate=E4=BB=B6):=20=E5=8D=81=E5=A4=84?= =?UTF-8?q?=E5=A5=97=E4=BB=B6=E6=8D=A2=20run=5Fsuite=20=E6=95=B4=E6=A0=91?= =?UTF-8?q?=E5=9B=9E=E6=94=B6=E2=80=94=E2=80=94=E5=90=AF=E5=8A=A8=E8=AE=B0?= =?UTF-8?q?=20WINPID,=E8=B6=85=E6=97=B6=E5=85=88=20taskkill=20/T=20?= =?UTF-8?q?=E6=9D=80=E5=85=A8=E6=A0=91=E5=86=8D=20kill=20-9=20=E6=94=B6=20?= =?UTF-8?q?MSYS=20=E4=BE=A7(=E9=A1=BA=E5=BA=8F=E9=A2=A0=E5=80=92=E4=BC=9A?= =?UTF-8?q?=E8=AE=A9=20/T=20=E8=B5=B0=E4=B8=8D=E5=88=B0=E5=B7=B2=E6=AD=BB?= =?UTF-8?q?=E7=88=B6=E8=BF=9B=E7=A8=8B,=E5=8D=B3=E5=8E=9F=E5=AD=A4?= =?UTF-8?q?=E5=84=BF=E6=B3=84=E6=BC=8F=E6=A0=B9=E6=BA=90),=E6=A0=87?= =?UTF-8?q?=E5=BF=97=E6=96=87=E4=BB=B6=E5=88=A4=E8=B6=85=E6=97=B6(taskkill?= =?UTF-8?q?=20=E5=BC=BA=E6=9D=80=E5=90=8E=20MSYS=20wait=20=E6=8A=A5=200)?= =?UTF-8?q?=E2=80=94=E2=80=94=E9=BB=98=E8=AE=A4=E4=BA=94=E6=AE=B5=E5=AE=9E?= =?UTF-8?q?=E8=B7=91=E5=85=A8=E7=BB=BF=E6=AE=8B=E7=95=990,=E8=B6=85?= =?UTF-8?q?=E6=97=B6/=E6=AD=A3=E5=B8=B8=E5=8F=8C=E8=B7=AF=E5=BE=84?= =?UTF-8?q?=E6=9C=BA=E5=88=B6=E9=AA=8C=E8=AF=81=E9=80=9A=E8=BF=87;run=5Fal?= =?UTF-8?q?l.gd=20=E9=98=BB=E5=A1=9E=E9=9D=A2=E8=B6=85=E6=97=B6=E5=AE=88?= =?UTF-8?q?=E6=8A=A4=E5=B1=9E=E4=BB=A3=E7=A0=81=E9=9D=A2=E7=95=99=E5=BE=85?= =?UTF-8?q?=20worktree=20=E6=89=B9,=E6=9D=A1=E7=9B=AE=E4=BF=9D=E6=8C=81?= =?UTF-8?q?=E5=BE=85=E6=89=A7=E8=A1=8C?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- tools/probe_gate.sh | 72 ++++++++++++++++++++++++++++++++------------- 待办清单.md | 2 +- 2 files changed, 52 insertions(+), 22 deletions(-) diff --git a/tools/probe_gate.sh b/tools/probe_gate.sh index 1098059d..839caa7d 100644 --- a/tools/probe_gate.sh +++ b/tools/probe_gate.sh @@ -1,6 +1,7 @@ #!/usr/bin/env bash # 探针闸正主——headless 安全段固化,禁再手拼同款 Godot 命令。 -# 三闸:①每段 timeout 守卫(挂死=FAIL 不静默)②段前预清+段后清本 game 目录孤儿 Godot +# 三闸:①每段 timeout 守卫+超时整树回收(挂死=FAIL 不静默;taskkill /T 连引擎子进程一起杀, +# 不再只杀 wrapper 留孤儿)②段前预清+段后清本 game 目录孤儿 Godot # (按命令行精确匹配本 game 路径,不误杀其他 worktree 会话的合法进程)③末尾残留清点=批末闸(必须 0)。 # 段:ui_input_probe=默认必跑;ui_struct_probe=默认必跑( # 全 UI 屏结构断言:按钮互压/等宽/出屏/零尺寸/标题屏双列);ui_contrast_probe=默认必跑( @@ -75,6 +76,35 @@ kill_orphans() { local p; for p in $(orphans); do taskkill //F //PID "$p" >/dev/null 2>&1; done } +# 每段跑批统一走本函数:后台启动记 MSYS PID→WINPID,守卫进程到点先 taskkill /T 整树回收 +# (顺序要紧:先杀 wrapper 再清树会让 /T 走不到已死的父进程,引擎子进程照样泄漏—— +# 2026-10-25 在册挂死根源),后 kill -9 收 MSYS 侧。正常退出不动进程树;段后 kill_orphans 照跑兜底。 +run_suite() { # run_suite <日志> <场景 res:// 路径> + local t="$1" log="$2" scene="$3" + local kf="$TMP/killed.$RANDOM" + rm -f "$kf" + "$G" --headless --path "$GAME_WIN" "$scene" >"$log" 2>&1 & + local pid=$! + local wpid="" + wpid="$(ps -W 2>/dev/null | awk -v p="$pid" '$1==p{print $4; exit}')" + ( sleep "$t" 2>/dev/null + touch "$kf" + [ -n "$wpid" ] && taskkill //F //T //PID "$wpid" >/dev/null 2>&1 + kill -9 "$pid" 2>/dev/null + true ) & + local guard=$! + wait "$pid"; local st=$? + kill "$guard" 2>/dev/null; wait "$guard" 2>/dev/null + # taskkill 强杀后 MSYS wait 可能报 0——超时判定以守卫落下的标志文件为准(与 124 同判)。 + if [ "$st" -ge 128 ] || [ -f "$kf" ]; then + st=124 + echo "[probe_gate] 套件超时(${t}s),已整树回收(PID=$pid/WINPID=${wpid:-未取到——靠孤儿清杀兜底})" + fi + rm -f "$kf" + kill_orphans + return "$st" +} + # 冷检出刷导入(.godot 不入 git,fresh worktree 首跑一次性付) if [ ! -f "$GAME/.godot/uid_cache.bin" ]; then echo "[probe_gate] 冷检出:editor --quit 刷导入(一次性,可到 1-2 分钟)" @@ -86,39 +116,39 @@ pre="$(orphans | wc -l | tr -d ' ')" if [ "$pre" -gt 0 ]; then echo "[probe_gate] 预清本闸残留 Godot×$pre"; kill_orphans; fi echo "======== ui_input_probe ========" -timeout 120 "$G" --headless --path "$GAME_WIN" res://probe/ui_input_probe.tscn >"$TMP/uip.log" 2>&1 -st=$?; kill_orphans +run_suite 120 "$TMP/uip.log" res://probe/ui_input_probe.tscn +st=$? grep -E "PASS|FAIL|问题" "$TMP/uip.log" | head -12 verdict "ui_input_probe" "$TMP/uip.log" "$st" || _rc=1 echo "======== ui_struct_probe ========" -timeout 120 "$G" --headless --path "$GAME_WIN" res://probe/ui_struct_probe.tscn >"$TMP/stp.log" 2>&1 -st=$?; kill_orphans +run_suite 120 "$TMP/stp.log" res://probe/ui_struct_probe.tscn +st=$? grep -E "PASS|FAIL" "$TMP/stp.log" | head -12 verdict "ui_struct_probe" "$TMP/stp.log" "$st" || _rc=1 echo "======== layout_probe(分辨率几何·两档) ========" -timeout 120 "$G" --headless --path "$GAME_WIN" res://probe/layout_probe.tscn >"$TMP/lay.log" 2>&1 -st=$?; kill_orphans +run_suite 120 "$TMP/lay.log" res://probe/layout_probe.tscn +st=$? grep -E "PASS|FAIL" "$TMP/lay.log" | head -12 verdict "layout_probe" "$TMP/lay.log" "$st" || _rc=1 echo "======== ui_contrast_probe ========" -timeout 120 "$G" --headless --path "$GAME_WIN" res://probe/ui_contrast_probe.tscn >"$TMP/ctp.log" 2>&1 -st=$?; kill_orphans +run_suite 120 "$TMP/ctp.log" res://probe/ui_contrast_probe.tscn +st=$? grep -E "PASS|FAIL" "$TMP/ctp.log" | head -12 verdict "ui_contrast_probe" "$TMP/ctp.log" "$st" || _rc=1 echo "======== screen_flow_probe(L3 屏壳切换·迭代 29 T4) ========" -timeout 120 "$G" --headless --path "$GAME_WIN" res://probe/screen_flow_probe.tscn >"$TMP/sfp.log" 2>&1 -st=$?; kill_orphans +run_suite 120 "$TMP/sfp.log" res://probe/screen_flow_probe.tscn +st=$? grep -E "screen_flow_probe" "$TMP/sfp.log" | tail -3 verdict "screen_flow_probe" "$TMP/sfp.log" "$st" "screen_flow_probe" || _rc=1 if [ "$WITH_CLICK" -eq 1 ]; then echo "======== ui_click_probe 行为走查 ========" - timeout 240 "$G" --headless --path "$GAME_WIN" res://probe/ui_click_probe.tscn >"$TMP/clk.log" 2>&1 - st=$?; kill_orphans + run_suite 240 "$TMP/clk.log" res://probe/ui_click_probe.tscn + st=$? grep -E "click_probe" "$TMP/clk.log" | tail -4 verdict "ui_click_probe" "$TMP/clk.log" "$st" "click_probe" || _rc=1 fi @@ -127,26 +157,26 @@ fi # 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://probe/ui_probe.tscn >"$TMP/flp.log" 2>&1 - st=$?; kill_orphans + run_suite 120 "$TMP/flp.log" res://probe/ui_probe.tscn + st=$? grep -E "\[ui_probe\]" "$TMP/flp.log" | tail -2 verdict "ui_probe" "$TMP/flp.log" "$st" || _rc=1 echo "======== ui_tune_probe(--full 收编) ========" - timeout 120 "$G" --headless --path "$GAME_WIN" res://probe/ui_tune_probe.tscn >"$TMP/flt.log" 2>&1 - st=$?; kill_orphans + run_suite 120 "$TMP/flt.log" res://probe/ui_tune_probe.tscn + st=$? grep -E "\[tune_probe\]" "$TMP/flt.log" | tail -2 verdict "ui_tune_probe" "$TMP/flt.log" "$st" || _rc=1 echo "======== t17_defer_probe(--full 收编) ========" - timeout 120 "$G" --headless --path "$GAME_WIN" res://probe/t17_defer_probe.tscn >"$TMP/fld.log" 2>&1 - st=$?; kill_orphans + run_suite 120 "$TMP/fld.log" res://probe/t17_defer_probe.tscn + st=$? grep -E "\[t17_defer\]" "$TMP/fld.log" | tail -2 verdict "t17_defer_probe" "$TMP/fld.log" "$st" || _rc=1 echo "======== fx_probe(--full 收编) ========" - timeout 120 "$G" --headless --path "$GAME_WIN" res://probe/fx_probe.tscn >"$TMP/flx.log" 2>&1 - st=$?; kill_orphans + run_suite 120 "$TMP/flx.log" res://probe/fx_probe.tscn + st=$? grep -E "\[fx_probe\]" "$TMP/flx.log" | tail -2 verdict "fx_probe" "$TMP/flx.log" "$st" || _rc=1 fi diff --git a/待办清单.md b/待办清单.md index fc8c0dd8..3b212f24 100644 --- a/待办清单.md +++ b/待办清单.md @@ -538,7 +538,7 @@ #### 闸与探针批上下文挂死防护——probe_gate 进程树回收与 run_all 阻塞面超时(2026-10-25 登记,来源=批次移交) **实况**:证据=迭代 36 批末闸机观测(非本批引入)。原登记两件存量噪声,件①(battle_log_view.gd:17 类型声明错致运行期 TypedArray 错误、日志失真)已随迭代 38 卡⑥ 收口出账(git 提交 ce49a8ee),本条只剩件②:`level_shop_economy_test` 在闸批量上下文存在挂死形态(直跑恒绿),`tools/probe_gate.sh` 的 per-suite timeout 只杀 wrapper 不杀引擎子进程,孤儿泄漏会殃及后续全部 Godot 启动(批末四次闸跑批中断的根源,处置=清杀泄漏进程+删重建 `game/.godot`)。挂死防护=闸壳/测试基建,按改动四类属**工程改动走直改通道**。 -- 直改落点:tools/probe_gate.sh(per-suite 进程树回收)+game/tests/run_all.gd(OS.execute 阻塞面超时守护)——测试基建直改 +- 直改落点:tools/probe_gate.sh(per-suite 进程树回收)+game/tests/run_all.gd(OS.execute 阻塞面超时守护)——测试基建直改。**2026-10-28 用户裁四批全做,probe_gate 件已落**(run_suite 整树回收:启动记 WINPID → 超时先 `taskkill /T` 杀全树再 `kill -9` 收 MSYS 侧〔顺序颠倒会让 /T 走不到已死父进程〕→ 标志文件判超时〔taskkill 强杀后 MSYS wait 可能报 0〕;默认五段实跑全绿+超时/正常双路径机制验证通过)。run_all.gd 件属代码面(game/tests),按车道铁律留待触及测试基建的 worktree 批顺带,本条目保持待执行。 **改动面**:工具代码