diff --git a/.claude-plugin/plugin.json b/.claude-plugin/plugin.json index 36502c4..05acc48 100644 --- a/.claude-plugin/plugin.json +++ b/.claude-plugin/plugin.json @@ -1,7 +1,7 @@ { "name": "isep", "description": "InkStone Environment Plugin —— leo 的 Claude Code 環境唯一真相源:48 支機械閘(59 條註冊,白話盤點見 docs/hooks-inventory.md)、7 支 slash command、2 支 skill、27 支腳本,外加治理規範與標籤真相源。本機與雲端裝同一份,沒有子集。", - "version": "0.6.0", + "version": "0.6.1", "keywords": [ "inkstone", "guardrails", diff --git a/docs/hooks-inventory.md b/docs/hooks-inventory.md index bb79d79..991e3b0 100644 --- a/docs/hooks-inventory.md +++ b/docs/hooks-inventory.md @@ -14,7 +14,9 @@ > 🔴 **這兩個數字上一版是錯的(2026-08-26 實際數過才發現)**:本頁原本寫「43 個檔、53 條註冊」, > 而當時真實是 **45 個檔、55 條註冊**——中間有兩支閘進來時沒有回頭改這裡。 > 現在的寫法是實際數出來的: -> `ls hooks/*.sh | wc -l` = 48;`grep -c '"command"' hooks/hooks.json` = 59。 +> `ls hooks/*.sh | wc -l` = 48;`grep -c '"command":' hooks/hooks.json` = 59。 +> ⚠️ **冒號不能省**:`grep -c '"command"'`(沒冒號)會連 `"type": "command"` 一起數到,回 **118**。 +> 本頁 2026-08-27 之前寫的是沒冒號那版——**照著它跑會拿到一個跟本頁不符的數字**。 > **一份會偷偷過期的盤點表,跟沒有盤點表差不多**——見本頁最後「怎麼跟實況對帳」那段。 > > 📌 **`0.6.0`(`inkstone/ISEP#59`,2026-08-27)這兩個數字是併完之後當場數出來的**: @@ -23,6 +25,10 @@ > 加上 `ISEP#72` 的 `reply-identity-guard.sh` 已在 main 上。 > 一加一減之後檔數不變、註冊條數落在 59——**這正是「不能靠加減推算、只能實數」的例子**: > 上一版寫 58,就是把兩批改動的加減兜出來、沒有真的數過。 +> +> 🔴 **`0.6.1`(2026-08-27)補回表格漏掉的兩列**:`isep-presence-beacon.sh`(E 組)、 +> `milestone-due-guard.sh`(A 組)。**標頭寫 48 支的同時,下面的表格只列得出 46 支** +> ——數字是對的,人話少了兩行。發現的方法與防它再犯的指令,見下面「落差偵測」第二組 `comm`。 --- @@ -51,6 +57,7 @@ | `leo21c-write-guard.sh` | AI 想寫東西到你私人帳號 `leo21c` 就擋下——這個帳號只准你自己用,AI 的實驗一律走別的測試帳號。 | 🛑 擋 | | `release-tag-guard.sh` | AI 想打版本 tag,但 `plugin.json` 裡寫的版本號跟 tag 對不上就擋下——避免「這裡說 0.2.0、那裡說 0.1.0」各說各話。 | 🛑 擋 | | `ticket-api-bypass-guard.sh` | AI 想繞過 `scripts/ticket` 工具、直接打 API 新增 Gitea 東西(開新票/milestone/label/PR,會漏掉「新增前先搜過」這道檢查)就擋下——不管是隱式 POST(urllib 傳 data= 沒寫 method)還是小寫 `requests.post(...)`。 | 🛑 擋 | +| `milestone-due-guard.sh` | AI 想開一個新的里程碑(milestone)卻沒填期限就擋下,**填 `9999-01-01` 一樣擋**——那是「沒有期限」穿了一件期限的衣服,盤點時每一格看起來都有值,其實一格都沒有。只管「建里程碑」這個動作,查詢/改別的欄位都放行。 | 🛑 擋 | | `reply-identity-guard.sh` | 直接打 Gitea API 貼留言到票上時,內文第一行沒有 `【身份】`(`總管`/`subagent`/`leo`)就擋下——票上多條線並行時,看不出哪一則是誰寫的。純讀取、走 `scripts/ticket` 正門、指令裡加 `reply-identity-ok` 都放行。 | 🛑 擋 | | `comment-carries-task-guard.sh` | AI 要在票裡留一則「等某某上線才驗得了」這種**還沒做完的事**,卻沒有把它開成一張子票時,擋一次。留言沒人會回頭讀,票的 open/closed 撈一次就看得到。 | 🛑 擋(同一輪只擋一次) | @@ -103,6 +110,7 @@ | 閘名 | 對你意味著什麼 | 動作 | |---|---|---| +| `isep-presence-beacon.sh` | 對話一開始印一行 `🟢 ISEP vX.Y.Z 已載入(N 支閘|來源:…)`。**這行不是裝飾,是唯一能證明「這個 session 真的有閘」的東西**——它自己就住在 plugin 裡,看得到它就表示 plugin 載入了;某個 session 從頭到尾沒有這行,那個 session 是零閘狀態,先修 plugin 再做事。同一台機器可能同時有兩份 ISEP(marketplace 裝的、repo 裡 vendor 的),所以那行會講出這次是哪一份在說話。 | 📝 記錄(context 注入) | | `session-start-recall.sh` | 對話一開始就自動把「全局現況」(Gitea 各 repo 的票、KBDB 的藏書地圖)推到 AI 眼前,不必等它自己想到要查。 | 📝 記錄(context 注入) | | `skill-deploy-drift-guard.sh` | 如果「全機真正在用的 skill」跟「repo 裡版控的正本」內容對不上,就在開場講出來——避免用著一份沒人知道已經跟正本分家的舊拷貝。 | 📝 記錄 | @@ -177,7 +185,62 @@ $ comm -13 /tmp/fs_hooks.txt /tmp/registered_hooks.txt (無輸出) ``` -**這次順便抓到的另一個落差**:`.claude-plugin/plugin.json` 的說明文字寫「42 支機械閘(52 條註冊)」, +🔴 **上面那兩行驗不出「表格漏列」**——它們比的是 `hooks.json`,不是這張表。 +「有閘、但這頁沒有它那一行人話」要另外一組指令才看得見,就是下面這組 +(2026-08-27 就是靠它抓到本頁漏了 `isep-presence-beacon.sh`/`milestone-due-guard.sh` 兩列): + +``` +$ ls hooks/*.sh | xargs -n1 basename | sort > /tmp/inv_fs.txt +$ grep -oE '^\| `[a-zA-Z0-9_.-]+\.sh`' docs/hooks-inventory.md \ + | grep -oE '[a-zA-Z0-9_.-]+\.sh' | sort -u > /tmp/inv_table.txt + +# 有這支閘、但這頁沒有它那一列 → 要補人話 +$ comm -23 /tmp/inv_fs.txt /tmp/inv_table.txt +(無輸出) + +# 這頁列了、但檔案已經不在了 → 要刪那一列 +$ comm -13 /tmp/inv_fs.txt /tmp/inv_table.txt +(無輸出) +``` + +🔴 **`^\| \`` 這個錨點不能拿掉**——它的意思是「**這一行的第一欄就是這支閘**」, +也就是「表格真的列了它」。把錨點拿掉、改成抓全頁所有反引號裡的 `*.sh`, +反向那半會吐出 **3 個假警報**(2026-08-27 實跑): + +``` +claim-verify-police.sh ← 出現在「已於 ISEP#60 移除」那段**移除紀錄**裡 +subagent-claim-worksheet.sh ← 同上 +github-arm.sh ← 它在 `scripts/`,不在 `hooks/`;是 github-contact-guard + 那一列裡告訴你「怎麼解鎖」的逃生口 +``` + +**三個都不是幽靈,三個都不該刪**:刪掉前兩個等於刪掉「G 組為什麼是空的」這段歷史, +刪掉第三個等於讓那一列不再告訴你怎麼過閘。 +⇒ **0 次正確攔截、3 次誤攔**——照這個訊號去改,會把好東西改壞。 + +那「頁面上出現了一個根本不存在的檔名」怎麼辦?**那要另外一格量,而且判準不是文字是事實**: + +``` +# C. 頁面提到的每個 *.sh,現在存在,或者 git 歷史裡存在過 +$ for n in $(grep -oE '`[a-zA-Z0-9._-]+\.sh`' docs/hooks-inventory.md | tr -d '`' | sort -u); do + [ -f "hooks/$n" ] || [ -f "scripts/$n" ] && continue + [ -n "$(git log --all --oneline --diff-filter=AD -- "hooks/$n" "scripts/$n")" ] && continue + echo "$n" + done +(無輸出) +``` + +**「現在沒有、但曾經有」=歷史,合法;「從來沒有過」=打錯字或憑空捏造,才是幽靈。** +這一格問的是 git,不是問這頁的用字,所以它不會因為誰換個寫法就失效。 + +📌 **三格都要跑,而且它們量的是不同東西**: +A1 缺人話、A2 表格有幽靈、C 全頁有幽靈。 +**標頭的 48/59 對不代表這頁沒漏**——補進 2 支真的、同時留著 2 支假的,數字照樣湊得到 48。 +**數量相等不等於集合相等**,所以驗的一律是集合(`comm`),不是 `wc -l`。 + +**這次順便抓到的另一個落差**(🕐 **這一段是 2026-08-20 的快照,裡面每個數字都是那天的,不是現況**—— +留著是因為它是「兩份文件的數字不會自己跟上」這個病的第一個案例;現況數字看本頁標頭): +`.claude-plugin/plugin.json` 的說明文字寫「42 支機械閘(52 條註冊)」, `README.md` 也寫「42 支 + `hooks.json`」「共 52 條註冊」——但實測是 **43 支檔案、53 條註冊**。 差 1 支、差 1 條,猜測是今天(2026-08-20)新增的 `leo21c-write-guard.sh`/`release-tag-guard.sh`/ `ticket-api-bypass-guard.sh` 這批(檔頭日期都是今天)加了之後,兩份文件的數字沒有跟著更新。 @@ -232,12 +295,16 @@ $ comm -13 /tmp/fs_hooks.txt /tmp/registered_hooks.txt - **`micromanage-guard.sh`/`irreversible-dispatch-guard.sh`/`no-ticket-no-dispatch.sh` 的雙重矩比對(`Task` + `Agent`)是刻意保險還是舊名稱沒清掉**——見上面「重複掛載」段落,我沒有把握單靠讀檔案判斷,需要看實際觸發紀錄或問總管。 - **`stage-before-prod-guard.sh` 跟 `main-and-prod-push-guard.sh` 的分工邊界**:`main-and-prod-push-guard.sh` 的檔頭明講自己是在「補 `stage-before-prod-guard.sh` 的破口」(那支只認 3 個關鍵字,抓不到 `wrangler deploy`),但兩支都還掛著、都還在管「prod 出貨」這件事。這是「新的補洞、舊的continua」還是「舊的該退休了」,這份盤點表不下判斷,留給你在下一步的分類會議裡定奪。 -除了以上兩點,其餘 41 支的行為都能從檔頭與源碼直接讀出,沒有「猜」的部分。 +除了以上兩點,其餘各支的行為都能從檔頭與源碼直接讀出,沒有「猜」的部分。 + +> 📌 這句話原本寫「其餘 **41** 支」——那是 43 支閘那一版(`v0.2.1`)數的,之後沒有人重跑過。 +> 2026-08-27 把數字拿掉而不是改成 46:**改成 46 等於宣稱我逐支重讀過源碼,而我沒有。** +> 要恢復一個數字,就重跑一次上面「抽驗」那件事,然後把當天的日期寫上去。 --- ## 這份表怎麼跟實況對帳(半年後怎麼發現漂移) -1. **有沒有新閘沒被收進這張表**:跑本文「落差偵測」段落的兩行 `comm` 指令,比對 `hooks/*.sh` 的檔名清單跟這張表列出的閘名清單(不是跟 `hooks.json`,那個只驗證有沒有註冊,驗不了有沒有寫進這張人話表)。 +1. **有沒有新閘沒被收進這張表**:跑本文「落差偵測」段落**第二組**(`inv_fs` vs `inv_table` 的兩行 `comm`)**加第三格 C**,比對 `hooks/*.sh` 的檔名清單跟這張表列出的閘名清單。**不是第一組**——第一組比的是 `hooks.json`,只驗證有沒有註冊,驗不了有沒有寫進這張人話表。2026-08-27 漏掉的那兩列,第一組是綠的、第二組才紅。**抓表格列的那組 `grep` 一定要帶 `^\| \`` 錨點**,理由與拿掉之後會冒出的 3 個假警報,就寫在那一段裡。 2. **有沒有閘的行為跟這裡寫的不一樣了**:抽幾支重新讀一次源碼,跟這裡的「一句話」對一遍——就是本文「抽驗 5 支」做的事,可以照同樣方法定期重做。 3. **`.claude-plugin/plugin.json` 與 `README.md` 的數字**:這兩處各自寫了一次「幾支、幾條註冊」,前面已經抓到一次對不上(42/52 vs 實際 43/53)。這兩個數字沒有機制保證跟著 `hooks/` 目錄自動更新,是本表發現的第一個具體漂移案例。