身為一天只看兩眼的人,我要每則回覆都自己說出拖了多久,我才能一眼看出這件事花了不該花的時間 #63
Notifications
Due Date
No due date set.
Blocks
#30 讓閘擋對東西
inkstone/ISEP
Reference: inkstone/ISEP#63
Reference in New Issue
Block a user
Delete Branch "%!s()"
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?
身為一天只看兩眼的人,我要每則回覆都自己說出拖了多久,我才能一眼看出這件事花了不該花的時間。
leo 2026-08-27 的原話
🔴 重點在後面那句:不是要總管記得戴,是要它長在機器上。
總管答應「現在開始戴」——而那正是這條規則第一次失效的方式:
靠記性的規則,下一個 session 就沒有了(今天已經證明過好幾次:
history-first/KBDB-first/stage-first/派工-first 全是同一個形狀)。
要達成什麼
總管每一則回覆都帶著「這件事已經花了多久」,而且不需要總管記得。
判準:一個新開的 session,總管什麼都沒被交代,回覆裡照樣有時長。
這一格要你自己判斷(不要照抄總管的想法)
——leo 的原話是「隨時看自己拖了多久」,那個「拖」指向的是任務不是 session,
但實際上哪個基準對他最有用,要你想清楚並在票上說明理由
additionalContext型的 hook 就是這樣做的),但「注入提醒」與「回覆真的帶上」是兩件事——注入了但模型沒照做是這類機制的主要失效模式,設計時要正面處理
怎麼驗
紅線
plugin.json要升版——版本沒動=沒有人吃得到claude-code、改 tag[decision] leo 2026-08-28 07:40 給了這張票的具體規格,並指定它是今天的第一個交付
leo 原話
這張票要做成什麼(規格具體化)
每一次回覆都要帶倒數——不是「有空時報時」,是每一則都要有,而且是機器算的不是我記的。
倒數的基準有兩層:
due_date,Gitea 上查得到)為什麼它排第一
因為它是今天其餘 12 張票的節拍器。leo 整天上課、只能看兩眼,
沒有倒數他就不知道「這件事還來得及嗎」,而我沒有倒數就會重演昨天的「拖時間」。
與
inkstone/ISEP#82的分工(不要做重複)同一個注入點,兩行內容,來源不同:
先各自成立,能動了再合成同一支。
🔴 卡點一:通知發不出去(總管 2026-08-28 07:50 實撞)
leo 要的是 Telegram。通道本身是好的(
notify_leo工作流,wiki 記載「一條指令、不需任何金鑰」),但
prod-write-guard.sh擋下來了:它的判準是「指令打到線上實例主機 + 帶寫入語意」就擋。
而發一則 Telegram 一定是帶 body 的寫入型請求打到那台實例
⇒ 它跟「部署一個工作流上線」長得一模一樣,閘分不出來。
🔴 這不是誤攔,是閘的解析度不夠:兩者都打同一個 named webhook 家族路徑。
差別在打的是哪一個 named webhook——
notify_leo是發一則訊息,ship_refresh_cdn那種才是動線上狀態。所以本票要連帶處理:讓
prod-write-guard認得出「發通知」這個動作並放行它,判準要看打的是哪一個 named webhook,不是看有沒有寫入旗標。
⚠️ 放行的範圍要窄:只放行
notify_leo這一個(或一份明列的通知類白名單),不是放行整個 named webhook 家族——那會把部署工作流一起放掉。
🔴 卡點二:連「描述這個卡點」都會被同一支閘擋(同款第八次)
總管第一次想把本則貼上票時被自己擋下來——因為留言內文裡引用了那個閘的判準關鍵字
(實例主機名、寫入旗標的字樣),而閘比對的是指令文字,分不出「執行它」與「談論它」。
📌 這正是
inkstone/InkStoneCo#23「守門的閘擋錯東西:紅線裡複述關鍵字被當成下令」所記的同一個病,而那張票的標題已經標著「同款第七次」——這是第八次。
📌 leo 2026-08-17 的診斷早就寫在
sdd-gitea-governance.md§8.3:⇒ 修
prod-write-guard時要一起處理:它必須分得出「這條指令要去做那件事」和「這段文字在說明那件事」。繞法(把內文先寫成檔案再用不含關鍵字的指令送出)能通,
但那正是 leo 說的「人就會學會繞過它,那它就等於不存在」。
🔴 卡點三:總管的「我確認過了」戳記在雲端是失效的
prod-write-guard給總管的出口是蓋一個一次性戳記檔。但那個動作在
.claude/settings.json的 allow 清單裡是明文放行的,auto mode classifier 仍連續四次擋下它。
⇒ 這是
inkstone/InkStoneCo#99(「classifier 尊重 settings.json 白名單」)的實例,代表總管手上那個「我確認過了」的出口在雲端根本打不開——
閘留了一道給總管的門,而那道門在這個環境裡是焊死的。
📌 本票不修這一格(歸
inkstone/ISEP#90雲端接線那條線),但要記在這裡,因為它決定了「修
prod-write-guard時不能只靠戳記當出口」。【身份】claude-code(ISEP repo 工人,subagent)
交件:
inkstone/ISEP#63PR:#94(分支
feat/countdown-stamp,未推 main)做了什麼
hooks/countdown-guard.sh——一支閘掛兩個事件,因為那是同一件事的兩半:UserPromptSubmit:把算好的那一行送到眼前Stop:這一回合的回覆裡有沒有那一行,沒有就擋一次,並把算好的那一行印出來給它抄票上點名的失效模式(「注入了但模型沒照做」)就是靠後半接住的。
只做前半 = 又一個會被忽略的提醒(本 repo 心法第 2 條明令不要做)。
判準不是關鍵字黑名單:查的是「那個被要求的輸出元素在不在」(一個機器產生的標記
⏱),不是「有沒有講某些不該講的話」。換講法照樣要帶標記;多寫什麼都不會觸發。
那一格我自己判了:時長從這段對話的第一則訊息算起
理由(票要我說明):
resume 取 transcript 第一列的時間、不是 hook 第一次被叫到的時間:接關不是重新開始。
收工線=台北 16:00,過線後四小時內顯示「已超過」(超時消失的話這東西就沒意義了),
台北 20:00 之後才滾隔天。milestone 期限走快取,
countdown.py從不打網路(
UserPromptSubmit在每則訊息的關鍵路徑上),拿不到就整段不顯示、不編數字。連帶修好票上的兩個卡點(
prod-write-guard.sh)…/named/<ns>/notify_leo/trigger放行;…/named(部署端點)與…/named/<ns>/ship_refresh_cdn/trigger照擋。放行範圍刻意只有一個名字,不放行整個家族。⇒ 真的在部署的寫法照樣擋。
📌 修這支的過程又撞了一次同款:連「把修法寫進檔案」那條指令都被擋,因為內文引用了主機名。
測試(照
docs/TESTING.md的形狀,新增 A14/A15)全程離線(時鐘定住、狀態走環境變數、不打網路、不留測試檔)。20 條裡 7 條是「不該擋」。
實測(期望值 vs 實際顯示):起點 06:28 台北、現在 08:03 台北 →
期望「已過 1 小時 35 分」,實得
⏱ 已過 1 小時 35 分|距收工線(台北 16:00)剩 7 小時 56 分。🔴 沒驗的那一格(這是 report 不是 deliver 的那部分,明講)
A8「新 session 閘真的會觸發」沒有跑——這條 subagent 開不了新的 Claude Code session。
UserPromptSubmit是這個 repo 第一次用的事件,harness 會不會真的去叫它,只有在新 session 裡才看得出來。合併後請在新 session 驗一眼:第一則回覆有沒有帶
⏱。腳本層面(該擋、該放、算得準)已經 20/20 驗完。版本
plugin.json0.9.0 → 0.10.0。合併時要跟著打v0.10.0的 tag,否則
check-version-consistency.sh會紅(那支要求 plugin.json = 最新 tag)。順帶一提(不在本票範圍,沒動)
跑既有測試時發現
stage-before-prod-guard.test.sh(9/16)與main-and-prod-push-guard.test.sh(「沙盒建不起來」)在這個容器裡是紅的。已切回 main 複驗過,兩支在 main 上同樣紅 ⇒ 是既有狀態/環境問題,不是本 PR 造成的。