sdd-guard 退役:讓「取消 Active SDD」這個裁決真的執行得下去(inkstone/ISEP#91) #110

Merged
claude-code merged 1 commits from feat/retire-sdd-guard into main 2026-08-31 01:04:04 +00:00
Member

【身份】subagent/isep-hand/inkstone/ISEP#91

這個 PR 解什麼

leo 2026-08-16 在 inkstone/InkStoneCo#40 → comment 2942 裁定「取消 Active SDD」,
11 天沒被執行。原因不是有人偷懶,是執行它的第一步會鎖死自己

sdd-guard.sh 是 fail-closed 的
  · 動 code 檔時 status: active 不是恰好 1 份 → 擋(0 份也擋)
  · 路徑所在的 repo 沒有 3-specs             → 也擋

⇒ 照裁決把最後那份 active 拿掉 → 變 0 份 → 任何人動任何 .ts.py.go 全被擋

而且它現在就在誤攔。 ISEP 這個 repo 自己沒有 3-specs,本票開工第一件事就撞到:

$ echo '{"tool_name":"Edit","tool_input":{"file_path":".../hooks/lib/dispatch_parse.py"}}' \
    | bash hooks/sdd-guard.sh
🚫 SDD 協議攔截:… 找不到任何 SDD                exit 2

票上原本標「這一格沒驗,做這張票的人第一件事應該在拋棄式環境重現一次」——
重現不必拋棄式環境,在自己的樹上就撞得到。

改了什麼

改動
hooks/sdd-guard.sh 刪除
hooks/hooks.json 取消註冊(85 → 84 條,只少這一條
hooks/tests/sdd-guard.test.sh 刪除,由下面那支取代
hooks/tests/sdd-guard-retired.test.sh 新增,8 條
commands/sdd-check.md 改寫:SDD 只記「起初的樣子」,任務本體在 Gitea 票;找不到 SDD 不再是停下來的理由,找不到票才是
agents/inkstoneco-hand.md 拿掉「任何時刻只允許一份 status: active」那條紅線
hooks/lib/path-resolve.sh 只加註解:唯一 caller 走了,但別順手刪(#22 學到的東西住在裡面)
docs/hooks-inventory.md 刪那一列 + 補退役紀錄 + 數字重數
docs/TESTING.md 新增 A25
README.md.claude-plugin/plugin.json 數字重數
system-dev/wiki/mistakes.md 一條教訓:fail-closed 的閘會把「執行裁決」本身變成不可執行

迴歸測試測的不是「檔案刪了沒」,是「那個擋還會不會發生」

hooks/tests/sdd-guard-retired.test.sh 把「裁決執行完之後的世界」
(沒有 3-specs 的 repo、兩份 status: active 的 repo)丟給 hooks.json
整組 Write|Edit|MultiEdit 的閘——清單當場從 hooks.json 讀、不寫死——
不准有任何一支用 SDD/3-specs 當理由擋下來。
日後有人換個檔名把同一個形狀種回來,這支照樣紅。

🔴 判準刻意不是「一支閘都不准擋」:同組還住著跟 SDD 無關、且看 session 狀態決定
擋不擋的閘(history-firstsubagent-first)。把它們算失敗,這支測試會在別人改別的
東西時無故變紅,紅久了就沒人看——誤攔比漏擋更該修,對測試一樣成立

紅的證明(不是只驗綠):把 sdd-guard 暫時復原(檔案+註冊)重跑
通過 1/失敗 7,四條行為格全部指名 sdd-guard.sh。已還原。

自己跑過的

hooks/tests/sdd-guard-retired.test.sh            通過 8 / 失敗 0
逐支點名 hooks.json(README「裝什麼」那道指令)   84 條
  對 gitea/main 做集合差:少了 sdd-guard.sh × 1,多出 0 支,其餘一支不差
盤點數字(全部在這棵樹上實數,不是加減推)
  ls hooks/*.sh | wc -l                = 61(原 62)
  grep -c '"command":' hooks/hooks.json = 84(原 85)
  agents 7/commands 7/skills 2/scripts 48(皆未變動)
盤點表對帳三格(hooks-inventory 自己寫死的那三道)  三格皆無輸出
scripts/check-version-consistency.sh              ✅ 0.16.2 一致
claude plugin validate .                          ✅ Validation passed

驗收條件逐條對

  1. 「拿掉 active SDD 之後動 .ts 不能被擋」→ 測試 ②,四種情境
  2. sdd-check 與載入面不能再讀到『只准一份 active SDD』」→ 測試 ③
  3. 「搜 status: active 搜不到還在生效的規定」→ 全 repo 掃過,剩下的命中
    全部是測試自己的測資、或描述這次退役的文件,沒有一條是還在生效的規定

全套離線測試 24 支重跑,本次改動 0 退步。
有 6 支是紅的/跑不起來(dispatch-format-guard 40/52、prod-write-guard 18/19-fail、
stage-before-prod-guard 9/7-fail、另 3 支要帶參數或建不起沙盒)——
這 6 支在 gitea/main 上逐支重跑結果一模一樣,是既有狀態,不是本次造成的。

沒做的,以及為什麼

  • inkstone/InkStoneCo 那半(拿掉那份 active SDD + 刪 CLAUDE.md「單一活性鐵律」段)
    ——不是我的 repo(docs/governance/worker-roster.md:一個工人一個 repo)。
    而且順序上本來就要等這一版 ISEP 出去、兩邊 /plugin update 之後才動得
    先拿掉 active SDD 就會鎖死。派 inkstoneco-hand
  • checkbox 分診 → 掛 inkstone/InkStoneCo#49(票上明寫不要另開票)。
    順帶回報:ISEP 自己 0 條殘留docssystem-dev 全掃)。
  • 版本號:待總管定版。 這一版改到會被載入的東西(hooks.jsoncommands/agents/),
    沒有新版本號 = plugin update 是 no-op = 改動到不了任何人手上。

兩件回報給總管的發現(都沒動,等你裁)

  1. commands/cp-write.md 自己打架:第 71 行寫「CP 裡不准出現 - [ ]- [x]」,
    而第 261-262 行的步驟範本自己就在教人寫 - [ ]。這正好落在裁決的射程裡
    (「所有文件中都不帶有任務 checkbox」),但票上明寫 checkbox 那格不歸本票、也不要另開票
    ⇒ 我沒動它。要掛 InkStoneCo#49 還是另辦,請你裁。
  2. scripts/install.shupdate.sh 還會把 sdd-guard.sh 種進別的 repo
    install.sh:298update.sh:248,來源是 GitHub uncle6me-web/system-dev-template)。
    那兩支是別的 repo 的安裝器 vendored 在這裡,改它會跟上游漂移
    ⇒ 我沒動,回報給你決定要不要往 system-dev-template 派。
    (實務風險低:它們裝的是 .claude/hooks/ 那條退場中的舊接線。)
【身份】subagent/isep-hand/`inkstone/ISEP#91` ## 這個 PR 解什麼 leo 2026-08-16 在 `inkstone/InkStoneCo#40` → comment 2942 裁定「**取消 Active SDD**」, 11 天沒被執行。**原因不是有人偷懶,是執行它的第一步會鎖死自己**: ``` sdd-guard.sh 是 fail-closed 的 · 動 code 檔時 status: active 不是恰好 1 份 → 擋(0 份也擋) · 路徑所在的 repo 沒有 3-specs → 也擋 ``` ⇒ 照裁決把最後那份 active 拿掉 → 變 0 份 → **任何人動任何 `.ts`/`.py`/`.go` 全被擋**。 **而且它現在就在誤攔。** ISEP 這個 repo 自己沒有 `3-specs`,本票開工第一件事就撞到: ``` $ echo '{"tool_name":"Edit","tool_input":{"file_path":".../hooks/lib/dispatch_parse.py"}}' \ | bash hooks/sdd-guard.sh 🚫 SDD 協議攔截:… 找不到任何 SDD exit 2 ``` 票上原本標「這一格沒驗,做這張票的人第一件事應該在拋棄式環境重現一次」—— **重現不必拋棄式環境,在自己的樹上就撞得到。** ## 改了什麼 | 檔 | 改動 | |---|---| | `hooks/sdd-guard.sh` | **刪除** | | `hooks/hooks.json` | 取消註冊(85 → 84 條,**只少這一條**) | | `hooks/tests/sdd-guard.test.sh` | 刪除,由下面那支取代 | | `hooks/tests/sdd-guard-retired.test.sh` | **新增**,8 條 | | `commands/sdd-check.md` | 改寫:SDD 只記「起初的樣子」,任務本體在 Gitea 票;**找不到 SDD 不再是停下來的理由,找不到票才是** | | `agents/inkstoneco-hand.md` | 拿掉「任何時刻只允許一份 `status: active`」那條紅線 | | `hooks/lib/path-resolve.sh` | **只加註解**:唯一 caller 走了,但別順手刪(`#22` 學到的東西住在裡面) | | `docs/hooks-inventory.md` | 刪那一列 + 補退役紀錄 + 數字重數 | | `docs/TESTING.md` | 新增 A25 | | `README.md`/`.claude-plugin/plugin.json` | 數字重數 | | `system-dev/wiki/mistakes.md` | 一條教訓:fail-closed 的閘會把「執行裁決」本身變成不可執行 | ## 迴歸測試測的不是「檔案刪了沒」,是「那個擋還會不會發生」 `hooks/tests/sdd-guard-retired.test.sh` 把「裁決執行完之後的世界」 (沒有 `3-specs` 的 repo、兩份 `status: active` 的 repo)丟給 `hooks.json` 上 **整組** `Write|Edit|MultiEdit` 的閘——**清單當場從 `hooks.json` 讀、不寫死**—— 不准有任何一支用 SDD/3-specs 當理由擋下來。 ⇒ **日後有人換個檔名把同一個形狀種回來,這支照樣紅。** 🔴 **判準刻意不是「一支閘都不准擋」**:同組還住著跟 SDD 無關、且看 session 狀態決定 擋不擋的閘(`history-first`/`subagent-first`)。把它們算失敗,這支測試會在別人改別的 東西時無故變紅,紅久了就沒人看——**誤攔比漏擋更該修,對測試一樣成立**。 **紅的證明**(不是只驗綠):把 `sdd-guard` 暫時復原(檔案+註冊)重跑 → `通過 1/失敗 7`,四條行為格全部指名 `sdd-guard.sh`。已還原。 ## 自己跑過的 ``` hooks/tests/sdd-guard-retired.test.sh 通過 8 / 失敗 0 逐支點名 hooks.json(README「裝什麼」那道指令) 84 條 對 gitea/main 做集合差:少了 sdd-guard.sh × 1,多出 0 支,其餘一支不差 盤點數字(全部在這棵樹上實數,不是加減推) ls hooks/*.sh | wc -l = 61(原 62) grep -c '"command":' hooks/hooks.json = 84(原 85) agents 7/commands 7/skills 2/scripts 48(皆未變動) 盤點表對帳三格(hooks-inventory 自己寫死的那三道) 三格皆無輸出 scripts/check-version-consistency.sh ✅ 0.16.2 一致 claude plugin validate . ✅ Validation passed ``` **驗收條件逐條對**: 1. 「拿掉 active SDD 之後動 `.ts` 不能被擋」→ ✅ 測試 ②,四種情境 2. 「`sdd-check` 與載入面不能再讀到『只准一份 active SDD』」→ ✅ 測試 ③ 3. 「搜 `status: active` 搜不到還在生效的規定」→ ✅ 全 repo 掃過,剩下的命中 **全部是測試自己的測資、或描述這次退役的文件**,沒有一條是還在生效的規定 **全套離線測試 24 支重跑,本次改動 0 退步。** 有 6 支是紅的/跑不起來(`dispatch-format-guard` 40/52、`prod-write-guard` 18/19-fail、 `stage-before-prod-guard` 9/7-fail、另 3 支要帶參數或建不起沙盒)—— **這 6 支在 `gitea/main` 上逐支重跑結果一模一樣,是既有狀態,不是本次造成的。** ## 沒做的,以及為什麼 - **`inkstone/InkStoneCo` 那半**(拿掉那份 active SDD + 刪 `CLAUDE.md`「單一活性鐵律」段) ——不是我的 repo(`docs/governance/worker-roster.md`:一個工人一個 repo)。 而且**順序上本來就要等這一版 ISEP 出去、兩邊 `/plugin update` 之後才動得**; 先拿掉 active SDD 就會鎖死。派 `inkstoneco-hand`。 - **checkbox 分診** → 掛 `inkstone/InkStoneCo#49`(票上明寫不要另開票)。 順帶回報:**ISEP 自己 0 條殘留**(`docs`/`system-dev` 全掃)。 - **版本號:待總管定版。** 這一版改到會被載入的東西(`hooks.json`/`commands/`/`agents/`), 沒有新版本號 = `plugin update` 是 no-op = 改動到不了任何人手上。 ## 兩件回報給總管的發現(都沒動,等你裁) 1. **`commands/cp-write.md` 自己打架**:第 71 行寫「CP 裡不准出現 `- [ ]`/`- [x]`」, 而第 261-262 行的步驟範本**自己就在教人寫 `- [ ]`**。這正好落在裁決的射程裡 (「所有文件中都不帶有任務 checkbox」),但票上明寫 checkbox 那格不歸本票、也不要另開票 ⇒ 我沒動它。要掛 `InkStoneCo#49` 還是另辦,請你裁。 2. **`scripts/install.sh`/`update.sh` 還會把 `sdd-guard.sh` 種進別的 repo** (`install.sh:298`、`update.sh:248`,來源是 GitHub `uncle6me-web/system-dev-template`)。 那兩支是**別的 repo 的安裝器 vendored 在這裡**,改它會跟上游漂移 ⇒ 我沒動,回報給你決定要不要往 `system-dev-template` 派。 (實務風險低:它們裝的是 `.claude/hooks/` 那條退場中的舊接線。)
claude-code added 1 commit 2026-08-31 00:58:19 +00:00
leo 2026-08-16 在 inkstone/InkStoneCo#40 → comment 2942 裁定「取消 Active SDD」,
11 天沒被執行。原因不是有人偷懶,是**執行它的第一步會鎖死自己**:

    sdd-guard.sh 是 fail-closed 的
      · 動 code 檔時 status: active 不是恰好 1 份 → 擋(0 份也擋)
      · 路徑所在的 repo 沒有 3-specs           → 也擋

⇒ 照裁決把最後那份 active 拿掉 → 變 0 份 → 任何人動任何 .ts/.py/.go 全被擋。

而 ISEP 這個 repo 自己就沒有 3-specs——本票開工第一件事實測到:

    $ echo '{"tool_name":"Edit","tool_input":{"file_path":".../hooks/lib/dispatch_parse.py"}}' \
        | bash hooks/sdd-guard.sh
    🚫 SDD 協議攔截:… 找不到任何 SDD        exit 2

**它一直在誤攔 ISEP 自己,只是沒人回報。**

── 這一版做了什麼 ────────────────────────────────────
· hooks/sdd-guard.sh 刪除,hooks.json 取消註冊(85 → 84 條,只少這一條)
· commands/sdd-check.md 改寫:SDD 只記「起初的樣子」,任務本體在 Gitea 票;
  找不到 SDD 不再是停下來的理由,找不到票才是
· agents/inkstoneco-hand.md 拿掉「任何時刻只允許一份 status: active」那條紅線
· hooks/lib/path-resolve.sh 只加註解:它的唯一 caller 走了,但別順手刪
  (#22 學到的東西住在裡面,十幾支閘還在用它要修的那個寫法)

── 迴歸測試:測的不是「檔案刪了沒」,是「那個擋還會不會發生」──
hooks/tests/sdd-guard-retired.test.sh(通過 8/失敗 0,離線):
把「裁決執行完之後的世界」(沒有 3-specs 的 repo、兩份 status: active 的 repo)
丟給 hooks.json 上**整組** Write|Edit|MultiEdit 的閘——清單當場從 hooks.json 讀、
不寫死——不准有任何一支用 SDD/3-specs 當理由擋下來。
⇒ 日後有人換個檔名把同一個形狀種回來,這支照樣紅。

🔴 判準刻意不是「一支閘都不准擋」:同組還住著跟 SDD 無關、且看 session 狀態
決定擋不擋的閘(history-first/subagent-first)。把它們算失敗,這支測試會在別人
改別的東西時無故變紅,紅久了就沒人看——誤攔比漏擋更該修,對測試一樣成立。

**紅的證明**:把 sdd-guard 暫時復原(檔案+註冊)重跑 → 通過 1/失敗 7,
四條行為格全部指名 sdd-guard.sh。已還原。

── 自己跑過的 ──────────────────────────────────────
· hooks/tests/sdd-guard-retired.test.sh                通過 8/失敗 0
· 逐支點名 hooks.json(README「裝什麼」那道指令)      84 條,對 main 做集合差:
  少了 sdd-guard.sh × 1,多出 0 支,其餘一支不差
· 盤點數字全部在這棵樹上實數,不是加減推:
  ls hooks/*.sh|wc -l = 61(原 62)
  grep -c '"command":' hooks/hooks.json = 84(原 85)
  agents 7/commands 7/skills 2/scripts 48(皆未變動)
· 盤點表對帳三格(hooks-inventory 自己寫死的那三道):三格皆無輸出
· scripts/check-version-consistency.sh                  0.16.2 一致
· claude plugin validate .                              Validation passed
· hooks/tests/ 全部離線測試 24 支重跑:本次改動 0 退步
  (dispatch-format-guard 40/52、prod-write-guard 18/19-fail、
   stage-before-prod-guard 9/7-fail、另 3 支需帶參數/建不起沙盒——
   **六支在 gitea/main 上逐支重跑結果一模一樣,是既有狀態不是本次造成**)

── 沒做、也不該由這張票做的 ─────────────────────────
· inkstone/InkStoneCo 那半(拿掉 active SDD + 刪 CLAUDE.md「單一活性鐵律」段)
  ——那是 inkstoneco-hand 的 repo;而且順序上本來就要等這一版出去、
  兩邊 /plugin update 之後才動得,先拿掉就鎖死
· checkbox 分診(掛 inkstone/InkStoneCo#49,票上明寫不要另開票)
· 版本號:待總管定版

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_016ZBu4Sa1cGntKFRBYNZ6xs
claude-code merged commit 8b2c7cecac into main 2026-08-31 01:04:03 +00:00
Sign in to join this conversation.
No Reviewers
1 Participants
Notifications
Due Date
No due date set.
Dependencies

No dependencies set.

Reference: inkstone/ISEP#110