身為總管,我要這道閘擋的是「宣告」而不是「提到宣告」,我才不會一舉報 bug 就被它擋下 #54
Reference in New Issue
Block a user
Delete Branch "fix/factory-idle-guard-blocks-actions-not-mentions"
Deleting a branch is permanent. Although the deleted branch may continue to exist for a short time before it actually gets removed, it CANNOT be undone in most cases. Continue?
【工單】inkstone/ISEP#30 —— 讓閘擋對東西
(雲端驗收 2026-08-23 實撞,脈絡在 inkstone/InkStoneCo#57 comment 3970 之後那輪)
病灶:這道閘在懲罰誠實與謹慎
雲端驗收連續三次被
factory-idle-guard.sh擋下,三次都不是宣告意圖:而閘的訊息教人走「選項③:改寫那句話,說明它在等什麼」,
程式碼裡沒有任何一條分支對應它——放行只有「有 Agent/Task」與「附近有 #票號」兩條。
⇒ 唯一走得通的路是「不寫那三個字」,而那正是同一則訊息 🔴 明文禁止的動作。
六個真兇,沒有一個是「例外沒列夠」
(a) DECL 會匹配裸的「下一步」三個字。
下一步(我|就是|是)?[::]?\s*(?!不是宣告)每一節都可選 ⇒ 整條退化成「文中出現『下一步』」⇒ 只要提到這道閘在講什麼,就被這道閘咬。
→ 收緊:每一條 alternative 都必須接到一個動作動詞才算命中。方向與「加例外清單」相反。
(b) 「引用」被當成「主張」。 只剝
>與長「」,不認 code fence 與行內 code。→ 引用性標記蓋成哨兵(不是刪掉):內層宣告消失、外層句構留著。
刪掉正是 2026-08-17 漏掉「回『規劃』我就派人」的原因 ⇒ 誤攔與漏攔一起修好。
(c) 看錯回合收尾。 取
blocks_text[-1],但那則文字後面可能還有 tool_use ⇒ 宣告其實已兌現。→ 只看最後一個動作之後的文字;收尾在動作上就不觸發。
(d) 訊息承諾的出路,程式碼裡沒有。
→ 出路③ 給一個真的存在的機械形式
⏸ 等:<在等什麼>。白名單標記(要刻意寫、不會誤觸)而且留痕 ⇒ 滿足「不准把那句話刪掉再送一次」。
🔴 以下兩個,是被交付警察擋回來、改用真 transcript 重驗才找到的
第一顆 commit 只驗了我自己造的假 transcript。
改用本機一條 2068 行的真 session(切出 26 個真實回合終止點)重跑,當場多抓到兩個:
(e) 主詞是「你」的下一步,被當成我的宣告。(我原本一向都沒列到的第四類誤攔)
舊閘在 26 個真實回合裡擋了 2 次,兩次咬的都是我在交代 leo 該做什麼:
→ 主詞檢查(誰要動手),只掛在「下一步」那條 alternative 上。
用
finditer逐個檢查前 8 字有沒有第二人稱,蓋得到「你的下一步」這種單字 lookbehind 蓋不到的變體。「你點頭我就做」主詞本來就是我,不受影響。
(f) 票號放寬把閘變鈍了。
我把
#票號從「宣告句附近 ±N 字」放寬成「整段收尾文字」(因為票號常寫在行內 code 裡,剝掉就找不到)。真數據打臉:26 個真實回合裡 20 個是靠「文中某處剛好有票號」放行的
——而報告幾乎一定會提到票號 ⇒ 這道閘在實務上等於不會響。
→ 改成等長替換(蓋成同樣長度的哨兵而非刪除)⇒ 位移可以原封不動對回原文
⇒ locality 與「行內 code 裡的票號也算數」兩件同時成立(
assert len(text)==len(raw))。放行理由分佈(同一批 26 個真實回合):
守封路哲學
leo 2026-08-17:「紅線寫得越細,命中關鍵字的機率越高 ⇒ 那些閘在懲罰謹慎。」
本 PR 沒有加任何關鍵字例外清單——六個修法全是「收緊命中條件」「改變量測對象」
或「主詞/位移這類結構性判斷」。例外清單會越加越長、越長越誤攔,那是同一個病的下一輪。
逐向實測輸出(33 向,先紅後綠)
真實資料上的實測(不是我造的樣本)
本機一條 2068 行真 session,切出 26 個真實回合終止點,兩支閘各跑一次:
真實 schema 也對過了(
assistant.message.content[]、user帶tool_result、還有
attachment/system/bridge-session等 411+300 列雜訊)——造的假 transcript 與真檔同構,27→33 向不是假綠。
從遠端 clone 出來複驗(不是從我的工作目錄)
兄弟閘沒有退步
順手一起處理的
.claude-plugin/plugin.json0.3.6 → 0.3.8(兩顆 commit 各跟一版).claude/hooks/factory-idle-guard.log(InkStoneCo#48:只記「擋下」的話分母未知)。
上面 (f) 那份判定分佈就是靠這個 log 量出來的——留痕不是裝飾,它是這次的量測工具。
docs/hooks-inventory.md那一列補上「過閘的四條路」刻意的取捨(寫進檔頭了,下一輪不要當成 bug 又改回去)
下一步,我去補 X會漏)。吃了逗號,「不是我的下一步,我剛剛已經做完了」就會被咬(過去式當未來式)。
票名是被命名的物件,不是我對下一步的主張。
stop_hook_active逃生門(與 empty-handed-stop-guard 不同)。leo 2026-08-16:「提醒可以忽略,deny 不能。」
之所以敢這樣,是因為出路③現在真的存在 ⇒ 不可能把人鎖死在無解迴圈裡。
🔴 交回總管時要知道的一件事(我沒動它)
InkStoneCo/.claude/hooks/factory-idle-guard.sh與本 PR 的舊版逐位元組相同(
diff -q實測)。這個 PR 併了,本機那份還是舊的、還是會誤攔。InkStoneCo#72(「身為總管,我要本機的閘跟 plugin 同一份,我才不會被舊版誤攔」)
講的就是這件事——但同步屬於 InkStoneCo 那個 repo、要推它的 main,
依兩層手動確認閘不是 subagent 能做的。
📌 另外:KBDB 對這支閘的開發史 0 命中(語義搜尋最高分 0.48,全是 pms/undici 噪音)。
這筆「查了沒有」本身就是餵食清單——ISEP 的閘開發史還沒進 KBDB。
🤖 Generated with Claude Code
2026-08-23 雲端驗收連續三次被這道閘誤攔,三次都不是宣告意圖: ① 否認自己有下一步 ②引用閘自己的訊息 ③貼閘自己的正則原始碼舉報 bug。 而訊息教人走的「選項③:說明它在等什麼」,程式碼裡根本沒有那條分支 ——唯一走得通的路是不寫那三個字,正是同一則訊息明文禁止的動作。 四個真兇,沒有一個是「例外沒列夠」: (a) DECL 會匹配裸的「下一步」三個字(每一節都可選 ⇒ 退化成關鍵字) ⇒ 收緊:每一條 alternative 都必須接到動作動詞才算命中 (b) 只剝 > 引言與長「」,不認 code fence 與行內 code ⇒ 引用被當成主張 ⇒ 引用性標記整段換成哨兵(不是刪掉):內層宣告消失、外層句構留著 ——刪掉正是 08-17 漏掉「回『規劃』我就派人」的原因,兩個方向一起修 (c) 取 blocks_text[-1],但那則文字後面可能還有 tool_use ⇒ 宣告其實兌現了 ⇒ 只看「最後一個動作之後」的文字;收尾在動作上就不觸發 (d) 訊息承諾的出路只有兩條真的存在 ⇒ 出路③ 給一個機械形式 ⏸ 等:<在等什麼>(白名單標記,要刻意寫,留痕) 方向刻意與「再加幾個關鍵字例外」相反——例外清單會越加越長、越長越誤攔。 守 leo 的封路哲學:紅線寫得越細,命中關鍵字的機率越高 ⇒ 那些閘在懲罰謹慎。 順手:擋下與放行都留痕(InkStoneCo#48:只記擋下的話分母未知); log 目錄不在時安靜跳過,不再噴 redirect 錯誤到 stderr。 測試 hooks/tests/factory-idle-guard.test.sh 27 向,誤攔與漏攔兩個方向都測: 舊版 18/27(9 敗)→ 新版 27/27。 Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>交付警察擋回來是對的:前一顆只驗了「我自己造的假 transcript」。 改用本機一條 2068 行的真 session(26 個真實回合終止點)重驗,當場多找到兩個問題: ① 主詞是「你」的下一步,被當成我的宣告。 舊閘在 26 個真實回合裡擋了 2 次,兩次咬的都是我在交代 leo 該做什麼: 「下一步還是那一個動作:你把 feat/... 併進 main」 「## 你下一步(兩招,先便宜的)」 ⇒ 這是全新的第四類誤攔,我原本一向都沒列到。 修法是主詞檢查(誰要動手),只掛在「下一步」這條 alternative 上; 用 finditer 逐個檢查前 8 字有沒有第二人稱,蓋得到「你的下一步」這種 單字 lookbehind 蓋不到的變體。「你點頭我就做」主詞本來就是我,不受影響。 ② 票號從「宣告句附近」放寬成「整段」,把閘變鈍了。 真數據:26 個真實回合有 20 個是靠「文中某處剛好有票號」放行的—— 而報告幾乎一定會提到票號 ⇒ 這道閘在實務上等於不會響。 當初放寬是因為票號常寫在行內 code 裡,剝掉就找不到。 ⇒ 改成**等長**替換(蓋成同樣長度的哨兵而非刪除),位移就能對回原文, locality 與「行內 code 裡的票號也算數」兩件同時成立。 收緊後的判定分佈:21 no-declaration / 3 dispatched / 2 ticket-referenced (原本是 20 ticket-referenced / 3 no-declaration / 3 dispatched)。 真 transcript 實測:舊閘擋 2 次(兩次都是誤攔)→ 新閘擋 0 次。 測試 33 向(+6):舊版 21/33 → 新版 33/33。 版號 0.3.7 → 0.3.8。 Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>