Commit Graph

2 Commits

Author SHA1 Message Date
claude-code 5342917f2b roster-guard 認不出真實的 subagent_type,整個環境派不出工
Claude Code 給 plugin agent 的 subagent_type 帶前綴(isep:isep-hand),
而 agents/*.md 的 frontmatter name 沒有(isep-hand)。roster.find() 用完全相等比對
⇒ 真實派工一律被擋,而名單上的裸名字工具又不收 ⇒ 兩種寫法都派不出去。

測試沒抓到是因為 24 條全部餵手寫 payload,沒有一條用真實的 subagent_type 形狀。
補第 19 條專測這個:舊 roster.py + 新測試 → 紅;修好 → 25/25。

順手補 gate-ok 漏掉的 roster——v0.15.0 新增那支閘時沒同步逃生口清單,
所以撞上死鎖時連留痕的出口都沒有。
2026-08-28 12:36:13 +00:00
claude-code 3e83a4b4f3 修好「總管可以放行」那道門——它在 Linux(=每個雲端 session)上是焊死的(inkstone/ISEP#90 ④)
三支閘(prod-write-guard/main-and-prod-push-guard/stage-before-prod-guard)
判斷戳記新不新,都寫成這一行:

    MT=$(stat -f %m "$STAMP" 2>/dev/null || stat -c %Y "$STAMP" 2>/dev/null || echo 0)

macOS(BSD stat)上 `-f %m` 就是 mtime,對的。
**GNU coreutils 的 `-f` 是「顯示檔案系統資訊」**,而且它一邊回非零、
一邊往 stdout 吐一整段區塊 ⇒ `||` 接上的秒數被那段文字污染
⇒ 下一行的 `case "$NOW$MT" in *[!0-9]*) return 1` 必然命中
⇒ **在 Linux 上那三支閘的戳記永遠不會被接受。**

後果不是少一個便利功能:那三支閘都是「擋下來、但總管看過就能放行」,
而放行那道門在雲端打不開 ⇒ **它們在雲端等於純擋**,
總管照著閘自己印的指示做,做幾次都打不開,閘也不會告訴他門是壞的
(inkstone/InkStoneCo#99 那次「連續四次蓋不出戳記」就是這個形狀)。

· hooks/lib/mtime.sh:先 `-c %Y`(GNU)再 `-f %m`(BSD),**每一步都驗是不是純數字**
  ——這個 bug 的成因正是「命令失敗了卻還是印了東西」,只看離開碼會再被騙一次。
  四支用到的檔各自帶一份 inline fallback:這道門不能因為少一個檔案就再關上一次。
· scripts/gate-ok:把散在各閘訊息裡的七種逃生口收斂成一個名字、一種形狀
  (`gate-ok <閘名> [參數]`)。原因是逃生口原本是「臨時湊出來的 Bash 指令」,
  而臨時湊的指令沒有穩定形狀可以事先放行——settings.json 的 allow 只能逐條完全比對,
  多一個 `&&`、換一個 session id 就落在規則外。它蓋的戳記與閘原本認的完全同一個檔、
  同一種語意(單次、綁 repo、綁 session、有效期都沒動),換掉的只有「怎麼蓋」。

測試 hooks/tests/gate-ok.test.sh:16/16。既有的三支測試(29/16/10)不受影響。
拿 main 跑同一份:②⑤(門打得開)紅、⑥⑦⑧(門沒變寬)全綠
⇒ 這支補的正是既有測試從來沒驗過的那半邊。
2026-08-28 00:11:42 +00:00