閘門改問行程還在不在,不問代號見過沒有 #95

Open
jiantw83 wants to merge 1 commits from fix/restart-gate-asks-the-process into develop
Member

怎麼發現的

驗上一輪部署的重啟狀態時發現 claude 那道閘門在 13:48 就消失了,而人是 14:10 左右才重啟的。那段時間有三個全新的 claude 工作階段冒出來:13:48:41、13:48:47、13:48:59。

直接測過,不是推論:

JSC_CLI=claude restart-gate.sh require update assist   → 閘門立起來
{新的 session_id} + JSC_CLI 未設 + CLAUDECODE=1
  → session-timer.sh start                             → 閘門不見了

為什麼

判準原本是 session-timer.sh 的一句話:起始檔不存在=這個代號第一次開始=行程是新起的。 那個等式不成立。

  • 還沒重啟的工作階段自己生出來的子行程(claude -p、外掛子命令、子代理)拿到的也是沒見過的代號,一觸發就把閘門清掉。人一次都沒重啟,收尾那句「請重新啟動」於是只剩人自己記得。
  • 反方向也會答錯:續接原代號的 resume,行程確實換過了、新程式碼確實載入了,舊寫法卻連問都不會問。

排程那條路碰巧沒踩到,因為 cron 條目帶著 JSC_CLI=cron,清的是 restart-required.d/cron。那是巧合擋下來的,不是判準擋下來的。

改法

該問的是「載入舊程式碼那個行程還在不在」,就直接問它。

require 落地時一併記下兩個欄位:

欄位 內容
session= 掛上閘門那一刻的工作階段代號
pid= 那一支 CLI 自己的行程代號(往上追祖先,比對命令名等於 CLI 代號);追不到時為空

清除的判準:

  • 記到行程代號就只認它。 還活著不清(不管代號換沒換),走了就清(續接原代號的 resume 也算)。
  • 追不到行程代號時退回結束記號。 要求代號換了、而且舊的那個工作階段寫出過 .end。少了前一個,同一階段每次觸發都會清掉自己;少了後一個,子行程照樣清得掉。
  • 舊版寫的閘門沒有這兩個欄位就一律清,維持改版前的行為:認不出來就不要把人鎖在門外。
  • 核對命令名,不只看行程還在。 行程代號會被回收,回收後那個號碼照樣「活著」。

判定整段搬到 restart-gate.sh,session-timer.sh 只負責在工作階段開始時問一次,並把手上那個代號帶進去。start 分支不再由「起始檔在不在」決定要不要問——那個條件兩頭都會答錯。

report 的輸出格式沒動:那一行的 domains 擺在最後而且可能含空白,後面再接欄位會讓現有的讀法把新欄位讀成 domain 名。

冒煙那一組原本把舊語意寫成斷言

改完之後 wire-cli.sh smoke 有兩條當場變紅:清除後放行、舊格式狀態檔清除後放行。那不是改壞,是那兩條斷言記的是舊語意。

重寫成逐條驗三條清除路徑,SMOKE_EXPECT_RS 16 → 21:

斷言 預期
還沒重啟,子行程清不掉自己那一份 狀態檔留著
子行程清不掉,照樣擋下 擋下
記到的行程走了就清掉自己那一份 狀態檔消失
清除不動別支 CLI 那一份 別支留著
追不到行程代號又沒有結束記號 留著
追不到行程代號但有結束記號 清掉

另外加一條驗 require 真的把 session= 寫下來。少了那個欄位會無聲退回相容路徑,也就是改版前那個會被子行程清掉的行為,而每一條行為斷言照樣全綠——只驗行為驗不出這一種。

「行程走了」那一條不寫死一個「應該不存在」的號碼:拿一個剛結束並回收過的行程代號來寫,那種寫死的號碼哪天被別的行程佔走,斷言就會反過來變成偽陽性。

驗過的

項目 結果
五支 CLI 的 smoke 全部 status=ok,lines 145
重啟閘門那一組 21 條全數與預期相同
report 輸出格式 與改版前逐字相同
六條清除路徑手動實測 子行程留、同階段留、行程走了清、代號回收清、無結束記號留、有結束記號清
## 怎麼發現的 驗上一輪部署的重啟狀態時發現 claude 那道閘門在 `13:48` 就消失了,而人是 `14:10` 左右才重啟的。那段時間有三個全新的 claude 工作階段冒出來:`13:48:41`、`13:48:47`、`13:48:59`。 直接測過,不是推論: ``` JSC_CLI=claude restart-gate.sh require update assist → 閘門立起來 {新的 session_id} + JSC_CLI 未設 + CLAUDECODE=1 → session-timer.sh start → 閘門不見了 ``` ## 為什麼 判準原本是 `session-timer.sh` 的一句話:**起始檔不存在=這個代號第一次開始=行程是新起的。** 那個等式不成立。 - **還沒重啟的工作階段自己生出來的子行程**(`claude -p`、外掛子命令、子代理)拿到的也是沒見過的代號,一觸發就把閘門清掉。人一次都沒重啟,收尾那句「請重新啟動」於是只剩人自己記得。 - **反方向也會答錯**:續接原代號的 resume,行程確實換過了、新程式碼確實載入了,舊寫法卻連問都不會問。 排程那條路碰巧沒踩到,因為 cron 條目帶著 `JSC_CLI=cron`,清的是 `restart-required.d/cron`。**那是巧合擋下來的,不是判準擋下來的。** ## 改法 該問的是「載入舊程式碼那個行程還在不在」,就直接問它。 `require` 落地時一併記下兩個欄位: | 欄位 | 內容 | | --- | --- | | `session=` | 掛上閘門那一刻的工作階段代號 | | `pid=` | 那一支 CLI 自己的行程代號(往上追祖先,比對命令名等於 CLI 代號);追不到時為空 | 清除的判準: - **記到行程代號就只認它。** 還活著不清(不管代號換沒換),走了就清(續接原代號的 resume 也算)。 - **追不到行程代號時退回結束記號。** 要求代號換了、而且舊的那個工作階段寫出過 `.end`。少了前一個,同一階段每次觸發都會清掉自己;少了後一個,子行程照樣清得掉。 - **舊版寫的閘門沒有這兩個欄位就一律清**,維持改版前的行為:認不出來就不要把人鎖在門外。 - **核對命令名,不只看行程還在。** 行程代號會被回收,回收後那個號碼照樣「活著」。 判定整段搬到 `restart-gate.sh`,`session-timer.sh` 只負責在工作階段開始時問一次,並把手上那個代號帶進去。`start` 分支不再由「起始檔在不在」決定要不要問——那個條件兩頭都會答錯。 `report` 的輸出格式沒動:那一行的 `domains` 擺在最後而且可能含空白,後面再接欄位會讓現有的讀法把新欄位讀成 domain 名。 ## 冒煙那一組原本把舊語意寫成斷言 改完之後 `wire-cli.sh smoke` 有兩條當場變紅:`清除後放行`、`舊格式狀態檔清除後放行`。**那不是改壞,是那兩條斷言記的是舊語意。** 重寫成逐條驗三條清除路徑,`SMOKE_EXPECT_RS` 16 → 21: | 斷言 | 預期 | | --- | --- | | 還沒重啟,子行程清不掉自己那一份 | 狀態檔留著 | | 子行程清不掉,照樣擋下 | 擋下 | | 記到的行程走了就清掉自己那一份 | 狀態檔消失 | | 清除不動別支 CLI 那一份 | 別支留著 | | 追不到行程代號又沒有結束記號 | 留著 | | 追不到行程代號但有結束記號 | 清掉 | 另外加一條驗 `require` 真的把 `session=` 寫下來。**少了那個欄位會無聲退回相容路徑,也就是改版前那個會被子行程清掉的行為,而每一條行為斷言照樣全綠**——只驗行為驗不出這一種。 「行程走了」那一條不寫死一個「應該不存在」的號碼:拿一個剛結束並回收過的行程代號來寫,那種寫死的號碼哪天被別的行程佔走,斷言就會反過來變成偽陽性。 ## 驗過的 | 項目 | 結果 | | --- | --- | | 五支 CLI 的 smoke | 全部 `status=ok`,`lines 145` | | 重啟閘門那一組 | 21 條全數與預期相同 | | `report` 輸出格式 | 與改版前逐字相同 | | 六條清除路徑手動實測 | 子行程留、同階段留、行程走了清、代號回收清、無結束記號留、有結束記號清 |
jiantw83 added 1 commit 2026-09-07 06:25:48 +00:00
判準原本是「這個工作階段代號我沒見過=行程是新起的」。那個等式不
成立:還沒重啟的工作階段自己生出來的子行程,拿到的也是沒見過的代
號,於是替人把閘門放下了,而人一次都沒重啟。

這台機器上真的發生過。部署掛上的閘門兩分鐘後就不見了,那段時間有
三個子工作階段冒出來,收尾那句「請重新啟動」於是只剩人自己記得。
排程那條路碰巧沒踩到,因為 cron 條目帶著 JSC_CLI=cron,清的是別
一份——巧合擋下來的,不是判準擋下來的。

反方向也會答錯:續接原代號的 resume,行程確實換過了,舊寫法卻連
問都不會問。

所以 require 一併記下掛上閘門時的工作階段代號與那一支 CLI 的行程
代號,清除只認行程存活:還活著就不清,走了就清。追不到行程代號時
退回結束記號,要求代號換了而且舊階段寫出過 .end。核對命令名不只
看行程還在,因為行程代號會被回收。

判定整段搬到 restart-gate.sh,session-timer.sh 只負責問。冒煙那
一組原本把舊語意寫成斷言,改成逐條驗三條清除路徑,並加一條驗
require 真的把欄位寫下來——少了那個欄位會無聲退回相容路徑,而每
一條行為斷言照樣全綠。
This pull request has changes conflicting with the target branch.
  • plugin.json
View command line instructions

Checkout

From your project repository, check out a new branch and test the changes.
git fetch -u origin fix/restart-gate-asks-the-process:fix/restart-gate-asks-the-process
git checkout fix/restart-gate-asks-the-process
Sign in to join this conversation.
No Reviewers
No labels
1 Participants
Notifications
Due Date
No due date set.
Dependencies

No dependencies set.

Reference: plugins/hooks#95