閘教的那條出路要真的走得通(inkstone/ISEP#112) #114

Merged
claude-code merged 1 commits from fix/gate-teaches-a-command-that-runs into main 2026-08-31 11:10:44 +00:00
Member

【身份】isep-hand/inkstone/ISEP/fix/gate-teaches-a-command-that-runs

inkstone/ISEP#112

病在哪(兩個獨立的原因,各自都足以害死那一行)

① 相對路徑。 閘印的是 scripts/ticket subtask …,而相對路徑是對貼上去那個人的 cwd
解析的。總管的 cwd 是 InkStoneCo/,那裡的 scripts/ticket 是正本停在 2026-08-27
之前的舊複本。實測(cwd=/home/user/inkstoneco/InkStoneCo):

$ grep -c subtask scripts/ticket
0
$ python3 scripts/ticket subtask inkstone/arcrun-rag#136 --title "身為x,我要y,我才z" -F /tmp/b.md --label s/todo --assign claude-code
ticket — 讓 Gitea 變成「可追蹤的線」,不是「越積越大的池子」。
...
四個動詞,各有一道閘:
...
exit=2

⇒ 票上寫的「噴出四個動詞的說明然後什麼都沒發生」就是這個。
(ISEP 正本 grep -c subtask = 10;hooks/lib/beacon_report.py ② 已經會在 SessionStart
報這個舊複本,但報告不會改掉閘印出來的那一行。)

② 用法各寫一份,而且已經漂了。 閘那份寫 --assign <誰做>沒有 --next
就算路徑對了,跑在正本上照樣:

$ TICKET_HOST=http://127.0.0.1:9 python3 scripts/ticket subtask inkstone/arcrun-rag#136 \
    --title "身為…,我要…,我才…" -F /tmp/b.md --label s/todo --assign claude-code
🚫 指派了人卻沒寫 --next。
exit=2

修法:拿掉可以漂的那一格,不是把兩份對齊一次

會漂的東西 拿掉它的方式
腳本路徑 scripts/ticketself_path()os.path.realpath(__file__)印指令的人與跑指令的人是同一個檔案,沒有第二種可能
用法 USAGE / usage_text() 一份。閘去 ticket usage subtask --example 現要,不自己抄
內文模板 body_template()REQUIRED_SECTIONS 現生。模板與檢查同源 ⇒ 不可能生出「照著貼卻過不了自己那道閘」的票

新增動詞:ticket usage <verb> [--example] [--parent <owner/repo#N>] [--draft <路徑>]

閘的訊息改成一整塊可貼可跑:腳本絕對路徑、母票已填、內文草稿附在同一塊 heredoc 裡,
只剩標題/目標/驗收條件三格是機器不可能知道的
正本叫不動時 fail-open 的只有「訊息內容」(只指路、不補一份手抄用法),擋不擋不受影響。

順手把同一份檔案裡另外三處印給終端機的相對路徑改掉(cmd_loose 兩行、journey 提示一行)。
⚠️ 貼進 Gitea 留言的那幾行刻意維持相對寫法——留言會被別台機器讀到,
寫死本機絕對路徑等於寫死一個他們沒有的檔案。分界寫在 _writeback 那段註解裡。

驗收條件逐條

① 照閘印出來的那行原樣貼上就能跑完,產出母子相依成立的子票

把閘 stderr 那塊原樣複製、只填三格,實跑:

✅ 子票 inkstone/ISEP#113 已開:https://git.uncle6.me/inkstone/ISEP/issues/113
   tag:s/todo(它卡在哪一段)
   相依:已掛上 inkstone/ISEP#112(它存在、且擋著母票)
   回指:已在母票 inkstone/ISEP#112 的時間軸貼上指向子票的留言
📌 母票 inkstone/ISEP#112 目前有 1 張未關的相依:
     ◻ inkstone/ISEP#113  身為照著閘的訊息貼指令的人,我要每一支閘印的路徑都叫得到正本,…

② 子票沒關時母票關不掉(Gitea 原生相依,實測)

母票 #112 的相依: [('inkstone/ISEP#113', 'open')]
$ PATCH /repos/inkstone/ISEP/issues/112  {"state":"closed"}
HTTP 412  {"message":"cannot close this issue or pull request because it still has open dependencies", ...}
#112 現在 state = open

③ 閘訊息與能跑的指令不再有第二種可能漂掉的關係

保證方式是結構,不是紀律:閘的訊息裡沒有任何一段用法是它自己寫的
整塊都是 python3 "$TICKET" usage subtask --example 的 stdout。
$TICKET${CLAUDE_PLUGIN_ROOT}/scripts/ticket,它印的路徑是自己的 __file__

驗這件事的是 scripts/test-comment-carries-task-guard.sh 新增的 ⑮–㉑(22 → 29 條):

── 閘教的那行指令要真的跑得動(inkstone/ISEP#112)──
  ✅ ⑮ 要執行的那一行開頭是絕對路徑,且就是這一份正本
  ✅ ⑯ 訊息裡沒有任何相對路徑的 scripts/ticket
  ✅ ⑰ 訊息裡的用法就是 `ticket usage subtask` 的輸出,沒有第二份
  ✅ ⑱ ★ 訊息裡那塊指令原樣貼上就跑得完(走到網路才停,不是被閘擋)
  ✅ ⑲ 對照組:閘原本那組旗標(--assign 沒配 --next)確實跑不完
  ✅ ⑳ 草稿模板由 REQUIRED_SECTIONS 現生,訊息裡也齊
  ✅ ㉑ 正本叫不動時仍然擋,且只指路、不補一份手抄用法

29/29 通過

⑱ 是核心:它把閘 stderr 裡那塊指令原樣抽出來、只填三格、真的執行一次
離開碼必須是 1(TICKET_HOST 指到連不上的位址,走到網路才停)。
是 2 就代表又被某道閘擋下 = 這個病復發。全程離線,不開任何測試票。

變異測試(證明這幾條真的有鑑別力)

變異 預期 實測
example 改回相對路徑 ⑮⑯ 紅 26/29
閘自己抄一份用法 ⑰ 紅 28/29
example 加回 --assign(沒 --next ⑱ 紅 27/29
body_template 寫死、少一段 ⑱⑳ 紅 26/29
fallback 補回一份手抄用法 ㉑ 紅 28/29

(第一輪還抓到我自己寫的 ⑮ 是空過的——用相對路徑的變異沒讓它紅,
因為它比對的是「訊息裡出現過的所有路徑」,別的行還有絕對路徑,all() 照樣真。
已改成只看「要執行的那一行」,再跑一次變異才紅。)

其他驗過的

  • scripts/test-ticket-handoff-writeback.sh 49/49、test-ticket-where-seen-guard.sh 17/17、
    test-baton-handback-guard.sh 10/10、hooks/tests/diagnosis-evidence-guard.test.sh 26/26、
    reply-identity.test.sh 11/11、isep-presence-beacon.test.sh 14/14 全綠
  • claude plugin validate .√ Validation passed
  • scripts/check-version-consistency.sh✅ 版本一致
  • 五個盤點數字在本樹實數:hooks 61/註冊 84/agents 7/commands 7+skills 2/scripts 48
    ——這次沒有增減,README 與 plugin.json 不用動

⚠️ 沒驗的 / 要總管處理的

  1. 版本:待總管定版。 plugin.json 仍是 0.17.0
    plugin update 比的是版本號不是內容 ⇒ 不升版這個修正到不了任何人手上
  2. 雲端沒驗(我沒有雲端 session)。本機以 CLAUDE_PLUGIN_ROOT 指到 worktree 跑過,
    fallback(指到不存在的 root)也跑過。
  3. 這 7 支測試在 main 上就是紅的,不是本 PR 造成(同一組指令在 main 跑過對照):
    test-ticket-api-bypass-guard.sh 23/24、dispatch-format-guard.test.sh 40/52、
    gitea-arm-check.test.shmain-and-prod-push-guard.test.sh
    main-and-prod-push-guard-cross-repo.test.shprod-write-guard.test.sh 18/19 紅、
    stage-before-prod-guard.test.sh 9/7。
  4. 另外三支閘還是印相對路徑baton-handback-guard.shdispatch-format-guard.sh
    factory-idle-guard.sh)——同一個病、不在這張票的範圍內,已長成子票 inkstone/ISEP#113
  5. 小發現,沒修ticket subtask 貼回母票的那則留言預設簽 【身份】總管/…
    _identity()),有名字的工人跑它時要自己帶 ISEP_IDENTITY 才會簽對名字。
    這次我帶了。要不要讓它自動抓工人名字,是另一件事。
【身份】isep-hand/inkstone/ISEP/fix/gate-teaches-a-command-that-runs 修 `inkstone/ISEP#112`。 ## 病在哪(兩個獨立的原因,各自都足以害死那一行) **① 相對路徑。** 閘印的是 `scripts/ticket subtask …`,而相對路徑是對**貼上去那個人的 cwd** 解析的。總管的 cwd 是 `InkStoneCo/`,那裡的 `scripts/ticket` 是正本停在 2026-08-27 之前的舊複本。實測(cwd=`/home/user/inkstoneco/InkStoneCo`): ``` $ grep -c subtask scripts/ticket 0 $ python3 scripts/ticket subtask inkstone/arcrun-rag#136 --title "身為x,我要y,我才z" -F /tmp/b.md --label s/todo --assign claude-code ticket — 讓 Gitea 變成「可追蹤的線」,不是「越積越大的池子」。 ... 四個動詞,各有一道閘: ... exit=2 ``` ⇒ 票上寫的「噴出四個動詞的說明然後什麼都沒發生」就是這個。 (ISEP 正本 `grep -c subtask` = 10;`hooks/lib/beacon_report.py` ② 已經會在 SessionStart 報這個舊複本,但**報告不會改掉閘印出來的那一行**。) **② 用法各寫一份,而且已經漂了。** 閘那份寫 `--assign <誰做>` 卻**沒有 `--next`**。 就算路徑對了,跑在正本上照樣: ``` $ TICKET_HOST=http://127.0.0.1:9 python3 scripts/ticket subtask inkstone/arcrun-rag#136 \ --title "身為…,我要…,我才…" -F /tmp/b.md --label s/todo --assign claude-code 🚫 指派了人卻沒寫 --next。 exit=2 ``` ## 修法:拿掉可以漂的那一格,不是把兩份對齊一次 | 會漂的東西 | 拿掉它的方式 | |---|---| | 腳本路徑 | `scripts/ticket` 的 `self_path()`=`os.path.realpath(__file__)`。**印指令的人與跑指令的人是同一個檔案**,沒有第二種可能 | | 用法 | `USAGE` / `usage_text()` 一份。閘去 `ticket usage subtask --example` **現要**,不自己抄 | | 內文模板 | `body_template()` 由 `REQUIRED_SECTIONS` **現生**。模板與檢查同源 ⇒ 不可能生出「照著貼卻過不了自己那道閘」的票 | 新增動詞:`ticket usage <verb> [--example] [--parent <owner/repo#N>] [--draft <路徑>]`。 閘的訊息改成一整塊可貼可跑:腳本絕對路徑、母票已填、內文草稿附在同一塊 heredoc 裡, **只剩標題/目標/驗收條件三格是機器不可能知道的**。 正本叫不動時 fail-open 的只有「訊息內容」(只指路、不補一份手抄用法),擋不擋不受影響。 順手把同一份檔案裡另外三處印給終端機的相對路徑改掉(`cmd_loose` 兩行、journey 提示一行)。 ⚠️ **貼進 Gitea 留言**的那幾行刻意維持相對寫法——留言會被別台機器讀到, 寫死本機絕對路徑等於寫死一個他們沒有的檔案。分界寫在 `_writeback` 那段註解裡。 ## 驗收條件逐條 **① 照閘印出來的那行原樣貼上就能跑完,產出母子相依成立的子票** ✅ 把閘 stderr 那塊原樣複製、只填三格,實跑: ``` ✅ 子票 inkstone/ISEP#113 已開:https://git.uncle6.me/inkstone/ISEP/issues/113 tag:s/todo(它卡在哪一段) 相依:已掛上 inkstone/ISEP#112(它存在、且擋著母票) 回指:已在母票 inkstone/ISEP#112 的時間軸貼上指向子票的留言 📌 母票 inkstone/ISEP#112 目前有 1 張未關的相依: ◻ inkstone/ISEP#113 身為照著閘的訊息貼指令的人,我要每一支閘印的路徑都叫得到正本,… ``` **② 子票沒關時母票關不掉(Gitea 原生相依,實測)** ✅ ``` 母票 #112 的相依: [('inkstone/ISEP#113', 'open')] $ PATCH /repos/inkstone/ISEP/issues/112 {"state":"closed"} HTTP 412 {"message":"cannot close this issue or pull request because it still has open dependencies", ...} #112 現在 state = open ``` **③ 閘訊息與能跑的指令不再有第二種可能漂掉的關係** ✅ 保證方式是**結構**,不是紀律:閘的訊息裡**沒有任何一段用法是它自己寫的**, 整塊都是 `python3 "$TICKET" usage subtask --example` 的 stdout。 而 `$TICKET` = `${CLAUDE_PLUGIN_ROOT}/scripts/ticket`,它印的路徑是自己的 `__file__`。 驗這件事的是 `scripts/test-comment-carries-task-guard.sh` 新增的 ⑮–㉑(22 → 29 條): ``` ── 閘教的那行指令要真的跑得動(inkstone/ISEP#112)── ✅ ⑮ 要執行的那一行開頭是絕對路徑,且就是這一份正本 ✅ ⑯ 訊息裡沒有任何相對路徑的 scripts/ticket ✅ ⑰ 訊息裡的用法就是 `ticket usage subtask` 的輸出,沒有第二份 ✅ ⑱ ★ 訊息裡那塊指令原樣貼上就跑得完(走到網路才停,不是被閘擋) ✅ ⑲ 對照組:閘原本那組旗標(--assign 沒配 --next)確實跑不完 ✅ ⑳ 草稿模板由 REQUIRED_SECTIONS 現生,訊息裡也齊 ✅ ㉑ 正本叫不動時仍然擋,且只指路、不補一份手抄用法 29/29 通過 ``` ⑱ 是核心:它**把閘 stderr 裡那塊指令原樣抽出來、只填三格、真的執行一次**, 離開碼必須是 1(`TICKET_HOST` 指到連不上的位址,走到網路才停)。 是 2 就代表又被某道閘擋下 = 這個病復發。全程離線,不開任何測試票。 ## 變異測試(證明這幾條真的有鑑別力) | 變異 | 預期 | 實測 | |---|---|---| | example 改回相對路徑 | ⑮⑯ 紅 | ✅ 26/29 | | 閘自己抄一份用法 | ⑰ 紅 | ✅ 28/29 | | example 加回 `--assign`(沒 `--next`) | ⑱ 紅 | ✅ 27/29 | | `body_template` 寫死、少一段 | ⑱⑳ 紅 | ✅ 26/29 | | fallback 補回一份手抄用法 | ㉑ 紅 | ✅ 28/29 | (第一輪還抓到我自己寫的 ⑮ 是**空過的**——用相對路徑的變異沒讓它紅, 因為它比對的是「訊息裡出現過的所有路徑」,別的行還有絕對路徑,`all()` 照樣真。 已改成只看「要執行的那一行」,再跑一次變異才紅。) ## 其他驗過的 - `scripts/test-ticket-handoff-writeback.sh` 49/49、`test-ticket-where-seen-guard.sh` 17/17、 `test-baton-handback-guard.sh` 10/10、`hooks/tests/diagnosis-evidence-guard.test.sh` 26/26、 `reply-identity.test.sh` 11/11、`isep-presence-beacon.test.sh` 14/14 全綠 - `claude plugin validate .` → `√ Validation passed` - `scripts/check-version-consistency.sh` → `✅ 版本一致` - 五個盤點數字在本樹實數:hooks 61/註冊 84/agents 7/commands 7+skills 2/scripts 48 ——**這次沒有增減**,README 與 `plugin.json` 不用動 ## ⚠️ 沒驗的 / 要總管處理的 1. **版本:待總管定版。** `plugin.json` 仍是 `0.17.0`。 `plugin update` 比的是版本號不是內容 ⇒ **不升版這個修正到不了任何人手上**。 2. **雲端沒驗**(我沒有雲端 session)。本機以 `CLAUDE_PLUGIN_ROOT` 指到 worktree 跑過, fallback(指到不存在的 root)也跑過。 3. **這 7 支測試在 main 上就是紅的,不是本 PR 造成**(同一組指令在 `main` 跑過對照): `test-ticket-api-bypass-guard.sh` 23/24、`dispatch-format-guard.test.sh` 40/52、 `gitea-arm-check.test.sh`、`main-and-prod-push-guard.test.sh`、 `main-and-prod-push-guard-cross-repo.test.sh`、`prod-write-guard.test.sh` 18/19 紅、 `stage-before-prod-guard.test.sh` 9/7。 4. **另外三支閘還是印相對路徑**(`baton-handback-guard.sh`、`dispatch-format-guard.sh`、 `factory-idle-guard.sh`)——同一個病、不在這張票的範圍內,已長成子票 `inkstone/ISEP#113`。 5. **小發現,沒修**:`ticket subtask` 貼回母票的那則留言預設簽 `【身份】總管/…` (`_identity()`),有名字的工人跑它時要自己帶 `ISEP_IDENTITY` 才會簽對名字。 這次我帶了。要不要讓它自動抓工人名字,是另一件事。
claude-code added 1 commit 2026-08-31 11:03:22 +00:00
comment-carries-task-guard 擋下留言時教人跑 `scripts/ticket subtask …`,
而那一行跑不動。兩個獨立的原因,各自都足以害死它:

① 相對路徑對「貼上去那個人的 cwd」解析。總管的 cwd 是 InkStoneCo/,
   那裡的 scripts/ticket 是停在 08-27 之前的舊複本(grep -c subtask → 0),
   照著貼只印出它「四個動詞」的說明然後 exit 0。
② 用法是手抄的第二份,而它已經漂了:寫了 --assign 卻沒有 --next,
   正本會因為「指派了人卻沒寫 --next」直接擋下(exit 2,在打 API 之前)。

修法是拿掉可以漂的那一格,不是把兩份對齊一次:
- 路徑     scripts/ticket 的 self_path()(__file__ 的絕對路徑)
           ⇒ 印指令的人與跑指令的人是同一個檔案
- 用法     USAGE / usage_text() 一份,閘去 `ticket usage subtask --example` 現要
- 內文模板 body_template() 由 REQUIRED_SECTIONS 現生,跟檢查同源

新增動詞 `ticket usage <verb> [--example] [--parent] [--draft]`。
閘的訊息改成整塊可貼可跑:腳本絕對路徑、母票已填、內文草稿附在同一塊裡,
只剩標題/目標/驗收條件三格是機器不可能知道的。
正本叫不動時 fail-open 的只有「訊息內容」(只指路,不補一份手抄用法),
擋不擋不受影響。

測試 scripts/test-comment-carries-task-guard.sh 22 → 29 條。
新增的 ⑮–㉑ 驗的是「出路走不走得通」,不是「有沒有擋」——
⑱ 把閘 stderr 裡那塊指令原樣抽出來、只填三格、真的執行一次,
離開碼必須是 1(走到網路才停);是 2 就代表這個病復發。
六個變異全部驗過會紅(相對路徑/閘自己抄用法/--assign 沒配 --next/
模板寫死少一段/fallback 補回手抄用法)。

版本:待總管定版(plugin update 比的是版本號不是內容)。

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01SP7DiGMfSkWjZ15CHMbPFE
claude-code merged commit 85f76c556a into main 2026-08-31 11:10:44 +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#114