feat/assistant-gate-and-heartbeat/heartbeat
feat/assistant-gate-and-heartbeat/main
hooks/heartbeat.sh
write
check
report
clear
hooks/assistant-gate.sh
README.md
這台機器的穩定路徑指向開發存放庫,寫進接線檔就立刻對五支 CLI 生效。而現在還沒有心跳,接線的那一秒整組技能會全部鎖死,連修的路徑都走不到。接線的前提是助理已經在跑、心跳穩定,那是另一輪的事。
deny.sh
sh -n 兩支都通過;lint-scripts.sh exit 0(19 支);ste100-lint.sh exit 0;檔案無 BOM。
sh -n
lint-scripts.sh
ste100-lint.sh
心跳(暫存 JSC_HOME,沒碰真實環境):檔案不存在、寫入後、時間戳改成 400 秒前、門檻覆寫成 600、時間戳空值與非數字、clear 後再 clear、不認得的子命令與無參數——每一種的結束碼都與檔頭宣告一致。另外驗了寫不進去的兩種版面(位置被一般檔案佔住、被非空目錄佔住),都正確回報失敗。
JSC_HOME
閘門:心跳新鮮放行、不存在擋、過期擋且訊息報出差幾秒、時間戳壞掉擋且講第三種話、逃生門放行、解不出技能名放行、非 jsc 技能放行、11 支豁免技能逐一放行、非豁免技能(工作日誌那一支)確實被擋。
五支 CLI 的擋人形態逐一驗過,這一項最要緊,錯了那兩支就是無聲失效:
接線檔確認未動:git status 只有新增的腳本與 README;hooks.json、codex-hooks.json、wire-cli.sh 三份檔案裡閘門名稱的出現次數都是 0。
git status
hooks.json
codex-hooks.json
wire-cli.sh
What: - 新增 hooks/heartbeat.sh,四個子命令:write 寫心跳、check 判定新鮮、report 印現況、clear 清除。 - README 的 hooks 表補一列,事件欄註明不接線;環境變數表補上心跳門檻那一個。 Why: - 助理是背景行程,別人要知道它還在不在跑,唯一的依據就是它留下的心跳。閘門要判、status 技能要印、巡檢要記,三邊都需要同一份判定。 - 判定散在三個地方一定會漂移,狀態跟訊息就會對不上。所以判定只寫一份,check 與 report 共用同一個探測函式。 How: - 新鮮的判準是「檔案存在,而且時間戳距現在小於門檻」。門檻預設 300 秒,是心跳週期的五倍,一次網路或磁碟卡頓不會誤判;環境變數可以覆寫,壞值退回預設而不報錯——變數打錯字不該讓判定整個歪掉。 - 絕不看 pid 存活。五支 CLI 與容器裡的行程互相看不到彼此的 pid,看了也證明不了什麼,pid 只當擋人訊息的線索。 - check 用結束碼分四種狀態:新鮮、過期、不存在、時間戳壞掉。前三種的處置各不相同,擋人訊息要說的話也不一樣;第四種既不是「跑過停了」也不是「沒啟動過」,併進任何一邊都會讓訊息說錯話,而且絕不能退回判成新鮮。 - 寫入走暫存檔再更名。直接覆寫的話,剛好讀到寫一半的檔案會少掉時間戳,助理活著卻被判成壞了。 - 這一支不接線,只是被助理與閘門呼叫的工具。接線是後續獨立的一步,先接會在心跳還沒跑起來時就擋死整組技能。 Who: 助理落地的第一塊:先有心跳,閘門才判得動,主體才有東西可寫。
What: - 三份 manifest 的版本一起提升。 - heartbeat.sh 檔頭引用的技能名由 status 改成 assistant。 Why: - 上一筆加了 heartbeat.sh 卻沒有動版本號。版本不動,別的 domain 就沒有辦法用相依宣告要求「要有這支腳本的那一版」——宣告寫得出來,卻保證不了內容。助理宣告的下限本來會落在一個不含這支腳本的版本上。 - 檔頭寫的技能名是助理落地初期那一支獨立技能。助理主體把三個操作收攏成一支之後,那個名字就不存在了,照著找會找不到東西。 How: - 版本由 sync-skill-manifest.sh 同步,三份一致。 - 這一支仍然不接線,只是被助理與閘門呼叫的工具。 Who: 助理主體實作時,從相依宣告那一側回頭抓到的兩個缺口。
What: - 新增 hooks/assistant-gate.sh:心跳新鮮就放行,心跳不存在、過期或時間戳壞掉就擋下該次技能呼叫。 - 豁免清單十一支、逃生門一個。README 的 hooks 表與環境變數表跟著補。 - 這一版刻意不接線,接線檔一個字都沒動。 Why: - 助理沒在跑的時候,技能會以為背景有人收尾,實際上沒有。這道閘門把那個落差擋在門外。 - 不接線是因為這台機器的穩定路徑指向開發存放庫,寫進接線檔就立刻對五支 CLI 生效。而現在還沒有心跳,接線的那一秒整組技能會全部鎖死,連修的路徑都走不到。接線的前提是助理已經在跑、心跳穩定。 How: - 這是整組 hook 裡唯一一道 fail-closed 的閘門。其餘的原則都是資料不足就放行,這一道相反。代價是狀態檔寫不進去時全組停擺,所以逃生門與豁免清單不是選配,是能上線的前提。 - 豁免清單只收解鎖路徑,不收收尾規則。這一點與重啟閘門的方向相反:重啟閘門解鎖靠閘門外的動作,收尾規則要寫得完;這一道解鎖靠跑一支技能,清單收寬了閘門就等於沒有。 - 清單認技能名不認呼叫鏈,所以豁免技能轉呼叫的下一層也要收進來。最要緊的是 wiki 那一支:巡檢要先把結果寫上監控頁才寫心跳,只豁免助理自己會做出「沒心跳就擋 wiki、擋了巡檢跑不完、跑不完就還是沒心跳」的自咬環。 - 心跳判定回「檔案系統問不出來」時放行,不擋。那是判不出事實,不在這道閘門的職權裡;而且那一刻正是磁碟或權限壞掉的訊號,擋下去連豁免那幾支也修不動——它們同樣要寫狀態檔。磁碟壞掉要人去清磁碟,不是把技能組鎖起來。時間戳壞掉則照擋,那是確定沒有可信心跳的證據,而且修法就在豁免清單裡。 - 逃生門的判斷擺在載入共用函式庫之前。函式庫讀不到時 sh 會就地結束並回擋人的那個碼,逃生門也會跟著跑不到,人就繞不過去。 - 擋人一律經 deny.sh 輸出。三支走標準錯誤加結束碼,另外兩支靠標準輸出的內容擋,結束碼固定是零;自己印訊息會在那兩支上無聲失效。 - 心跳不存在、過期、時間戳壞掉三種情況講三種話。使用者要做的事不一樣:一個是從沒啟動過,一個是跑過停了,一個是檔案壞了要重建。 Who: 助理落地的最後一塊。接線與準則那一節另外處理。
No dependencies set.
The note is not visible to the blocked user.
摘要
變更內容
hooks/heartbeat.shwrite寫心跳、check判定新鮮、report印現況、clear清除hooks/assistant-gate.shREADME.md設計重點
為什麼不接線
這台機器的穩定路徑指向開發存放庫,寫進接線檔就立刻對五支 CLI 生效。而現在還沒有心跳,接線的那一秒整組技能會全部鎖死,連修的路徑都走不到。接線的前提是助理已經在跑、心跳穩定,那是另一輪的事。
心跳
check用結束碼分四種狀態:新鮮、過期、不存在、時間戳壞掉。前三種處置不同,第四種既不是「跑過停了」也不是「沒啟動過」,併進任何一邊都會讓訊息說錯話,而且絕不能退回判成新鮮。check與report共用同一個探測函式。兩邊各判一次一定會漂移,狀態與訊息就會對不上。閘門
deny.sh。 三支走標準錯誤加結束碼,另外兩支靠標準輸出的內容擋、結束碼固定是零。自己印訊息會在那兩支上無聲失效。測試結果
sh -n兩支都通過;lint-scripts.shexit 0(19 支);ste100-lint.shexit 0;檔案無 BOM。心跳(暫存
JSC_HOME,沒碰真實環境):檔案不存在、寫入後、時間戳改成 400 秒前、門檻覆寫成 600、時間戳空值與非數字、clear後再clear、不認得的子命令與無參數——每一種的結束碼都與檔頭宣告一致。另外驗了寫不進去的兩種版面(位置被一般檔案佔住、被非空目錄佔住),都正確回報失敗。閘門:心跳新鮮放行、不存在擋、過期擋且訊息報出差幾秒、時間戳壞掉擋且講第三種話、逃生門放行、解不出技能名放行、非 jsc 技能放行、11 支豁免技能逐一放行、非豁免技能(工作日誌那一支)確實被擋。
五支 CLI 的擋人形態逐一驗過,這一項最要緊,錯了那兩支就是無聲失效:
接線檔確認未動:
git status只有新增的腳本與 README;hooks.json、codex-hooks.json、wire-cli.sh三份檔案裡閘門名稱的出現次數都是 0。前置 Push Request