From 9586e63005bd6944278f87b9052983b3c5f1c6a2 Mon Sep 17 00:00:00 2001 From: Jeffery Date: Thu, 27 Aug 2026 18:49:58 +0800 Subject: [PATCH] =?UTF-8?q?test(restart-gate):=20=E5=86=92=E7=85=99?= =?UTF-8?q?=E6=B8=AC=E8=A9=A6=E5=8A=A0=E9=A9=97=E4=B8=80=E6=94=AF=20CLI=20?= =?UTF-8?q?=E4=B8=80=E4=BB=BD=E7=9A=84=E7=AF=84=E5=9C=8D?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit What:`tools/wire-cli.sh` 的 `smoke` 重啟閘門段從 9 條情境擴為 16 條,新增 `smoke_rs_file()` 比對狀態檔在不在。新增的情境是:只有別支 CLI 有狀態檔時放行、`require` 寫出的是當前 CLI 那一份、新工作階段開始後只清掉自己那一份、清除不動別支那一份、清除後放行、舊格式單一狀態檔存在時擋下、`clear` 一併刪掉舊檔、舊檔清除後放行。原有的豁免技能、逃生門與取不到技能名三類情境照舊,情境名稱從「狀態檔存在」改寫為「當前 CLI 那份存在」。檔頭的判定路徑清單同步改寫。 Why:只比對結束碼看不出「一支 CLI 一份」有沒有真的成立——別支那一份要留著、自己那一份要刪掉,兩件事都反映在檔案在不在,不反映在結束碼。舊版的冒煙只驗得到「狀態檔不存在」與「狀態檔存在」兩條,正好漏掉這次修掉的兩個缺陷所在的範圍:並行部署的覆寫與清除的全域解除,兩者在單一檔案的年代都跑得出 exit 0 與 exit 2 的正確值。 How:情境沿用暫時的 `$JSC_HOME`,不動使用者真正的狀態目錄——冒煙測試不該把別人的閘門拆掉。別支 CLI 的代號取 `smoke-other` 這個不在五支之列的固定值,才不會跟這一輪的 `$cli` 撞在一起。`smoke_rs_file()` 只比 `exist` 與 `absent` 兩種預期,失敗訊息直接講明「一支 CLI 一份的範圍壞了」,看訊息就知道是範圍出錯,不是腳本跑不動。舊檔那兩條情境走 `session-timer.sh restart` 觸發清除,跟真實路徑一致。 Who:`jsc-hooks` 接線工具的冒煙測試,覆蓋部署後重啟閘門的判定與清除範圍。 --- tools/wire-cli.sh | 70 ++++++++++++++++++++++++++++++----------------- 1 file changed, 45 insertions(+), 25 deletions(-) diff --git a/tools/wire-cli.sh b/tools/wire-cli.sh index 3439565..8f8138a 100755 --- a/tools/wire-cli.sh +++ b/tools/wire-cli.sh @@ -14,8 +14,9 @@ # 跑起來不出錯(缺 node、路徑錯、權限不足都只在真的執行時才現形)。 # 有分支的判定另外驗結果,不只驗跑得完:sdlc-gate.sh 的工作包歸屬比對會自備一份暫時的 # $JSC_HOME 狀態檔,把「查無歸屬」「自己的工作包」「別的工作包」與逃生門各跑一次,比對結束碼。 -# restart-gate.sh 的部署後重啟閘門同法:狀態檔不存在、狀態檔存在、豁免技能、逃生門、 -# 取不到技能名五條路徑各跑一次,再驗一次清除機制真的清得掉。 +# restart-gate.sh 的部署後重啟閘門同法:當前 CLI 沒有狀態檔、只有別支 CLI 有狀態檔、當前 +# CLI 那份存在、豁免技能、逃生門、取不到技能名各跑一次,再驗狀態檔本身在不在——清除只刪自己 +# 那一份、別支那一份留著、舊格式的單一狀態檔照樣擋得下來且清得掉。 # # 接線行為(依 CLI 而定,皆為冪等:重跑只取代既有的 jsc-hooks 標記段落,不會重複疊加): # claude — 什麼都不用寫,hooks.json 已自動接線八支 hook @@ -709,9 +710,10 @@ if [ "$action" = smoke ]; then fi # 部署後重啟閘門(restart-gate.sh):上面那支只走得到「狀態檔不存在」與「取不到技能名」, - # 擋人那一條完全沒跑到。這裡同樣自備一份暫時的 $JSC_HOME,把五條判定路徑各跑一次並比對 - # 結束碼,最後再驗清除機制真的把狀態檔清掉。用暫時目錄是為了不動到使用者真正的 - # $JSC_HOME/restart-required——冒煙測試不該把別人的閘門拆掉。 + # 擋人那一條完全沒跑到。這裡同樣自備一份暫時的 $JSC_HOME,把每條判定路徑各跑一次並比對 + # 結束碼,另外驗三件狀態檔設計本身的事:別支 CLI 那一份不影響這一支、清除只刪自己那一份、 + # 舊格式的單一狀態檔照樣擋得下來。用暫時目錄是為了不動到使用者真正的 + # $JSC_HOME/restart-required.d/——冒煙測試不該把別人的閘門拆掉。 # 一律 > "$smoke_out" fi } + # 狀態檔在不在也要比:一支 CLI 一份的重點就在「該留的留、該刪的刪」,只看結束碼看不出來。 + smoke_rs_file() { # $1=情境 $2=狀態檔 $3=exist 或 absent + if { [ "$3" = exist ] && [ -f "$2" ]; } || { [ "$3" = absent ] && [ ! -f "$2" ]; }; then + printf '[jsc] restart-gate.sh(%s):狀態檔 %s,與預期相同。\n' "$1" "$3" >> "$smoke_out" + else + smoke_fails=$((smoke_fails + 1)) + printf '[jsc] restart-gate.sh(%s):狀態檔預期 %s,實際不是,一支 CLI 一份的範圍壞了:%s\n' \ + "$1" "$3" "$2" >> "$smoke_out" + fi + } if rs_home=$(mktemp -d 2>/dev/null); then - smoke_rs_case "狀態檔不存在" jsc-sdlc:implement 0 - JSC_HOME="$rs_home" sh "$HOOKS/restart-gate.sh" require update hooks cli /dev/null - smoke_rs_case "狀態檔存在,技能 jsc-sdlc:implement" jsc-sdlc:implement 2 - smoke_rs_case "狀態檔存在,豁免技能 jsc-cli:deploy" jsc-cli:deploy 0 - smoke_rs_case "狀態檔存在,豁免技能 jsc-gitea:wiki" jsc-gitea:wiki 0 - smoke_rs_case "狀態檔存在,豁免技能 jsc-log:worklog" jsc-log:worklog 0 - smoke_rs_case "狀態檔存在,豁免技能 jsc-meta:skill-check" jsc-meta:skill-check 0 + rs_dir="$rs_home/restart-required.d" + # 別支 CLI 的代號。取一個不在五支之列的固定值,才不會跟這一輪的 $cli 撞在一起。 + rs_other=smoke-other + smoke_rs_case "當前 CLI 沒有狀態檔" jsc-sdlc:implement 0 + JSC_HOME="$rs_home" JSC_CLI="$rs_other" \ + sh "$HOOKS/restart-gate.sh" require update hooks /dev/null + smoke_rs_case "只有別支 CLI 有狀態檔" jsc-sdlc:implement 0 + JSC_HOME="$rs_home" JSC_CLI="$cli" \ + sh "$HOOKS/restart-gate.sh" require update hooks cli /dev/null + smoke_rs_file "require 寫出當前 CLI 那一份" "$rs_dir/$cli" exist + smoke_rs_case "當前 CLI 那份存在,技能 jsc-sdlc:implement" jsc-sdlc:implement 2 + smoke_rs_case "當前 CLI 那份存在,豁免技能 jsc-cli:deploy" jsc-cli:deploy 0 + smoke_rs_case "當前 CLI 那份存在,豁免技能 jsc-gitea:wiki" jsc-gitea:wiki 0 + smoke_rs_case "當前 CLI 那份存在,豁免技能 jsc-log:worklog" jsc-log:worklog 0 + smoke_rs_case "當前 CLI 那份存在,豁免技能 jsc-meta:skill-check" jsc-meta:skill-check 0 smoke_rs_case "逃生門 JSC_RESTART_GATE=off" jsc-sdlc:implement 0 off smoke_rs_case "取不到技能名" "" 0 # 清除機制:session-timer.sh 判定為新工作階段時會呼叫 restart-gate.sh clear。 # 這裡走的就是那條路徑(暫時 $JSC_HOME 底下沒有起始檔,等同行程新起的第一次)。 - if [ -f "$rs_home/restart-required" ]; then - JSC_HOME="$rs_home" JSC_SESSION_ID=smoke-restart \ - sh "$HOOKS/session-timer.sh" start /dev/null - if [ -f "$rs_home/restart-required" ]; then - smoke_fails=$((smoke_fails + 1)) - printf '[jsc] restart-gate.sh(清除機制):新工作階段開始後狀態檔還在,閘門會一直擋。\n' >> "$smoke_out" - else - printf '[jsc] restart-gate.sh(清除機制):新工作階段開始後狀態檔已清除,與預期相同。\n' >> "$smoke_out" - fi - else - smoke_fails=$((smoke_fails + 1)) - printf '[jsc] restart-gate.sh(清除機制):require 沒有寫出狀態檔,清除機制沒驗到。\n' >> "$smoke_out" - fi + JSC_HOME="$rs_home" JSC_CLI="$cli" JSC_SESSION_ID=smoke-restart \ + sh "$HOOKS/session-timer.sh" start /dev/null + smoke_rs_file "新工作階段開始後清掉自己那一份" "$rs_dir/$cli" absent + smoke_rs_file "清除不動別支 CLI 那一份" "$rs_dir/$rs_other" exist + smoke_rs_case "清除後放行" jsc-sdlc:implement 0 + # 舊格式的單一狀態檔(過渡相容):沒有 per-CLI 資訊,所以一律擋,clear 一併刪掉。 + printf 'at=%s\nmode=update\ndomains=hooks\ncli=%s\n' "$(now_iso)" "$rs_other" \ + > "$rs_home/restart-required" 2>/dev/null + smoke_rs_case "舊格式單一狀態檔存在" jsc-sdlc:implement 2 + JSC_HOME="$rs_home" JSC_CLI="$cli" JSC_SESSION_ID=smoke-restart-legacy \ + sh "$HOOKS/session-timer.sh" restart /dev/null + smoke_rs_file "清除一併刪掉舊格式狀態檔" "$rs_home/restart-required" absent + smoke_rs_case "舊格式狀態檔清除後放行" jsc-sdlc:implement 0 rm -rf "$rs_home" else smoke_fails=$((smoke_fails + 1))