Compare commits

...

3 Commits

Author SHA1 Message Date
Leo fa2f76177e docs(inventory): 反向那半補上真正驗得到幽靈的那一格(總管複驗退回)
總管複驗指出反向 comm 有 3 個輸出。實跑重現了,但逐個查過之後:
**三個都不是幽靈,三個都不該刪。**

  claim-verify-police.sh / subagent-claim-worksheet.sh
    → 全部 5 處都在內文,講的是「已於 ISEP#60 移除」。表格列(第一欄)
      命中數 = 0。刪掉它們等於刪掉「G 組為什麼是空的」這段歷史。
  github-arm.sh
    → 它存在,在 scripts/ 不在 hooks/;出現在 github-contact-guard 那一列的
      描述裡,是告訴人「怎麼解鎖」的逃生口。刪掉那一列就不再說得出怎麼過閘。

成因是那組 grep 拿掉了 `^\| \`` 錨點。有錨點=「這一行的第一欄就是這支閘」=
表格真的列了它;沒錨點=全頁所有反引號。**0 次正確攔截、3 次誤攔。**

但「頁面上出現根本不存在的檔名」確實該被抓到,只是不能靠文字判斷。
本次補上第三格 C:頁面提到的每個 *.sh,要嘛現在存在,要嘛 git 歷史裡存在過。
**「現在沒有但曾經有」=歷史;「從來沒有過」=幽靈。** 它問的是 git 不是用字。

順帶:標頭區那個 43 是 2026-08-20 快照段落裡的歷史數字,不是現況宣稱,
但原文用現在式讀起來像現況 ⇒ 加上「這一段每個數字都是那天的」標記。

實測(含兩個反向對照,證明新那格不是橡皮圖章):
  現況              A1[] A2[] C[]                48 檔 / 48 列
  表格種一支假閘    A2 與 C 都叫
  散文種一支假閘    A1/A2 抓不到、C 抓到          ← 只有 C 守得住這種
18 個測試檔 0 失敗;claude plugin validate 通過。

inkstone/ISEP#75(總管複驗 comment 4822)
2026-08-27 18:35:49 +08:00
Leo a671948fa5 docs(inventory): 補回表格漏掉的兩列人話,並補上驗得出這種漏的那組指令
標頭寫 48 支,下面的表格只列得出 46 支——缺的是
`isep-presence-beacon.sh`(E 組 SessionStart)與
`milestone-due-guard.sh`(A 組 PreToolUse/Bash)這兩列。
不是本次合併造成的,`origin/main` 上數同一個指令也是這兩支。

為什麼這個漏會活這麼久:本頁「落差偵測」只有一組 comm,比的是
`hooks.json`(驗有沒有註冊),驗不了「有沒有寫進這張人話表」。
所以本次同時補上第二組 comm(fs 檔名 vs 表格列出的閘名),
並把「怎麼跟實況對帳」第 1 條指到那一組。

順手修掉同一頁另外兩處自己會騙人的地方:
- 標頭的複驗指令 `grep -c '"command"'` 會連 `"type": "command"` 一起數,
  實跑回 118 不是 59;正確寫法要帶冒號。
- 「其餘 41 支」是 43 支閘那一版數的。改成拿掉數字而不是改成 46——
  改成 46 等於宣稱逐支重讀過源碼,而這次沒有。

版本 0.6.0 → 0.6.1(v0.6.0 已出 release,不升版沒有人吃得到這頁)。

實測:48 檔 vs 48 列,兩個方向的 comm 都空;
18 個測試檔全綠(0 失敗);claude plugin validate 通過。

inkstone/ISEP#59(comment 4779 第二件)
2026-08-27 18:24:20 +08:00
claude-code 7795cd705a Merge pull request '第二波:棒子三格+移除自造待驗單,版本收斂 0.6.0(inkstone/ISEP#58 #62)' (#74) from integrate/isep59-wave2 into main 2026-08-27 10:13:17 +00:00
2 changed files with 72 additions and 5 deletions
+1 -1
View File
@@ -1,7 +1,7 @@
{ {
"name": "isep", "name": "isep",
"description": "InkStone Environment Plugin —— leo 的 Claude Code 環境唯一真相源:48 支機械閘(59 條註冊,白話盤點見 docs/hooks-inventory.md)、7 支 slash command、2 支 skill、27 支腳本,外加治理規範與標籤真相源。本機與雲端裝同一份,沒有子集。", "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": [ "keywords": [
"inkstone", "inkstone",
"guardrails", "guardrails",
+71 -4
View File
@@ -14,7 +14,9 @@
> 🔴 **這兩個數字上一版是錯的(2026-08-26 實際數過才發現)**:本頁原本寫「43 個檔、53 條註冊」, > 🔴 **這兩個數字上一版是錯的(2026-08-26 實際數過才發現)**:本頁原本寫「43 個檔、53 條註冊」,
> 而當時真實是 **45 個檔、55 條註冊**——中間有兩支閘進來時沒有回頭改這裡。 > 而當時真實是 **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)這兩個數字是併完之後當場數出來的**: > 📌 **`0.6.0``inkstone/ISEP#59`2026-08-27)這兩個數字是併完之後當場數出來的**:
@@ -23,6 +25,10 @@
> 加上 `ISEP#72` 的 `reply-identity-guard.sh` 已在 main 上。 > 加上 `ISEP#72` 的 `reply-identity-guard.sh` 已在 main 上。
> 一加一減之後檔數不變、註冊條數落在 59——**這正是「不能靠加減推算、只能實數」的例子**: > 一加一減之後檔數不變、註冊條數落在 59——**這正是「不能靠加減推算、只能實數」的例子**:
> 上一版寫 58,就是把兩批改動的加減兜出來、沒有真的數過。 > 上一版寫 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 的實驗一律走別的測試帳號。 | 🛑 擋 | | `leo21c-write-guard.sh` | AI 想寫東西到你私人帳號 `leo21c` 就擋下——這個帳號只准你自己用,AI 的實驗一律走別的測試帳號。 | 🛑 擋 |
| `release-tag-guard.sh` | AI 想打版本 tag,但 `plugin.json` 裡寫的版本號跟 tag 對不上就擋下——避免「這裡說 0.2.0、那裡說 0.1.0」各說各話。 | 🛑 擋 | | `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(...)`。 | 🛑 擋 | | `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` 都放行。 | 🛑 擋 | | `reply-identity-guard.sh` | 直接打 Gitea API 貼留言到票上時,內文第一行沒有 `【身份】``總管``subagent``leo`)就擋下——票上多條線並行時,看不出哪一則是誰寫的。純讀取、走 `scripts/ticket` 正門、指令裡加 `reply-identity-ok` 都放行。 | 🛑 擋 |
| `comment-carries-task-guard.sh` | AI 要在票裡留一則「等某某上線才驗得了」這種**還沒做完的事**,卻沒有把它開成一張子票時,擋一次。留言沒人會回頭讀,票的 open/closed 撈一次就看得到。 | 🛑 擋(同一輪只擋一次) | | `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 注入) | | `session-start-recall.sh` | 對話一開始就自動把「全局現況」(Gitea 各 repo 的票、KBDB 的藏書地圖)推到 AI 眼前,不必等它自己想到要查。 | 📝 記錄(context 注入) |
| `skill-deploy-drift-guard.sh` | 如果「全機真正在用的 skill」跟「repo 裡版控的正本」內容對不上,就在開場講出來——避免用著一份沒人知道已經跟正本分家的舊拷貝。 | 📝 記錄 | | `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 條註冊**。 `README.md` 也寫「42 支 `hooks.json`」「共 52 條註冊」——但實測是 **43 支檔案、53 條註冊**。
差 1 支、差 1 條,猜測是今天(2026-08-20)新增的 `leo21c-write-guard.sh``release-tag-guard.sh` 差 1 支、差 1 條,猜測是今天(2026-08-20)新增的 `leo21c-write-guard.sh``release-tag-guard.sh`
`ticket-api-bypass-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`)是刻意保險還是舊名稱沒清掉**——見上面「重複掛載」段落,我沒有把握單靠讀檔案判斷,需要看實際觸發紀錄或問總管。 - **`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」還是「舊的該退休了」,這份盤點表不下判斷,留給你在下一步的分類會議裡定奪。 - **`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 支」做的事,可以照同樣方法定期重做。 2. **有沒有閘的行為跟這裡寫的不一樣了**:抽幾支重新讀一次源碼,跟這裡的「一句話」對一遍——就是本文「抽驗 5 支」做的事,可以照同樣方法定期重做。
3. **`.claude-plugin/plugin.json` 與 `README.md` 的數字**:這兩處各自寫了一次「幾支、幾條註冊」,前面已經抓到一次對不上(42/52 vs 實際 43/53)。這兩個數字沒有機制保證跟著 `hooks/` 目錄自動更新,是本表發現的第一個具體漂移案例。 3. **`.claude-plugin/plugin.json` 與 `README.md` 的數字**:這兩處各自寫了一次「幾支、幾條註冊」,前面已經抓到一次對不上(42/52 vs 實際 43/53)。這兩個數字沒有機制保證跟著 `hooks/` 目錄自動更新,是本表發現的第一個具體漂移案例。