Files
ISEP/docs/TESTING.md
T
isep-hand d4bf172990 主線成員改由相依邊決定,不靠同名里程碑;adopt 別 repo 的票=加相依到 hub 票;帳本落在 InkStoneCo/system-dev(inkstone/ISEP#133 → 6743)
leo 2026-09-07:「拆,誰說『同名跨 repo 是 mainline 機制的一部分』,早就定了只有一個
milestone,不同 repo 用指針」。上一版 scripts/mainline 檔頭把現場的樣子(5 個同名)寫成
「既有做法」,成員也照標題跨 repo 收;總管照它做、抄進 ops-facts、還在 arcrun-rag 補建了一個同名的。

改了什麼(判準全部是 Gitea 欄位,沒有標題比對):
- hooks/lib/mainline.py:collect_members()=hub 里程碑裡的票+hub 票,沿 /dependencies 邊
  (跨 repo)收下去;belongs() 要同時拿到「掛哪個 milestone」+「誰把它當相依」才准說「不屬於」,
  只知一半回 None(閘放行);project_roots() 給主線檔與帳本共用
- scripts/mainline:set --hub <票>、adopt 別 repo ⇒ POST 相依到 hub 票(--via 可指定成員),
  沒 hub 票時擋下並給兩條走得通的路,不建同名里程碑;has 查 /blocks;
  refresh --members 才重收(真 Gitea 25 張要 19 秒,SessionStart 成本不變)
- scripts/ticket:add_dependency() 一份(subtask 與 adopt 共用,409 冪等);pick 主線組走成員清單,
  逾期組一個里程碑物件一組;claim 的主線判定改看相依;pickable(None) 給靠邊進來的票
- hooks/mainline-focus-guard.sh:新鮮查詢問 milestone+/blocks,補收出路明講不要開同名里程碑
- scripts/milestone-account:帳本找家用同一把尺,退回原始碼目錄只在它有 .git(plugin 快取沒有)

測試:新 hooks/tests/mainline-members-by-dependency.test.sh 56 條(假 Gitea 照真的回 201/409);
scripts/test-ticket-pick.sh 48→53 條(池子改用相依邊,補「同名沒邊 ⇒ 不抓」);
既有 mainline-focus-guard/repo-mirror/gitea-fallback/idle/milestone-account/debt-worklist/
handoff-writeback 全綠。真 Gitea 唯讀實跑:set --hub inkstone/InkStoneCo#44 收到 25 張、5 個 repo,
mira#6/ISEP#130/ISEP#140/arcrun-rag#104 都在,不必新增任何邊。

版本:待總管定版(改了會被載入的 hook/scripts)。

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_0178ef1fGw3XeZtpN7LaZrm4
2026-09-07 10:40:55 +00:00

95 KiB
Raw Blame History

ISEP 測試手冊

leo 2026-08-20:「你交出版本測試了嗎?你要測試無誤才叫我測試, 如果雲端不能測試也要提供 test cases 讓我開啓雲端測試」。

規約:每一格都要有「怎麼跑/該看到什麼/什麼算失敗」三件。 沒跑過的格子一律標空白,不准標綠。


先讀:改了 ISEP 卻沒發版,改動到不了任何人手上

2026-08-20 實撞:新增一支 hook 併進 main,然後跑 claude plugin update isep@inkstone → 回「已是最新版 (0.2.0)」,新 hook 沒有進到安裝的那一份

原因:plugin update 比的是 plugin.json 的版本號,不是內容。 ⇒ 版本沒動 = 更新是 no-op = 本機與雲端又各自停在不同內容上(就是 InkStoneCo#57 的病)。

所以:任何要生效的改動,都必須跟著一個新版本號。這不是儀式,是傳輸機制本身。


A. 總管自己要跑完的(交給 leo 之前)

A1 — plugin manifest 合法

claude plugin validate .

該看到✔ Validation passed,不帶 warning。 失敗:任何 error;或有 warning 卻沒處理。

A2 — 版本三處一致

bash scripts/check-version-consistency.sh

該看到✅ 版本一致:plugin.jsonX.Y.Z,最新 tagvX.Y.ZREADME 沒有自行宣告版本。 失敗exit 1;或 README 又出現寫死的版本號。

A3 — 打 tag 的閘:擋得住,也放得過

bash scripts/test-release-tag-guard.sh

該看到3/3 通過1 個該擋、2 個不該擋)。 失敗:該擋的放行(假綠);或不該擋的被擋——誤攔比漏擋更該修,誤攔會懲罰謹慎。

A4 — 新增 Gitea 東西的側門閘:24 條

bash scripts/test-ticket-api-bypass-guard.sh

該看到24/24 通過(前 13 條是 v1 的開票案例;後面是 inkstone/ISEP#72 擴大範圍後補的:隱式/小寫 POST、milestonelabelPR、org 端點、以及一條打 真實 Gitea 網路重演 Arcrun#100 的案例——這台機器的 remote 沒帶憑證時會印 ⏭️ SKIP,不算失敗,但也不算驗過)。 失敗:任何一條不符,特別看「不該擋」那幾條——誤攔比漏擋更該修。

A13 — 搜尋戳記要證明「看過」,不是「跑過」:17 條

bash scripts/test-ticket-where-seen-guard.sh

該看到通過 17 條,失敗 0 條。全程離線(TICKET_HOST 指到連不上的位址: 離開碼 2 =被閘擋、離開碼 1 =閘全放行走到網路才炸),不打真實 Gitea、不留測試票

它在守什麼inkstone/ISEP#72 → comment 48732026-08-27 實犯): ticket where … >/dev/null 之後 ticket new——戳記寫成功了,命中的 72 張一眼沒看, 於是開出 arcrun-rag#147,而第一名 arcrun-rag#104 是同一件事、已經開了 13 天。

失敗

  • 「★」那兩條紅 ⇒ 今天這個形狀會再發生一次(尤其第二條:先寫好 --not-a-comment 理由就能閉著眼睛開票)
  • 「不該擋」3 條任一紅 ⇒ 誤攔,這比漏擋嚴重——沒命中也吵、看過了還吵, 人就學會忽略它
  • 最後那組 fd_is_devnull 紅 ⇒ 判準從「fstat 問得出來的事實」滑回猜文字

A11 — 討論串裡的任務要長成子票:29 條

bash scripts/test-comment-carries-task-guard.sh

該看到29/29 通過。全程離線(TICKET_HOST 指到連不上的位址),不開任何測試票。 失敗

  • 「該擋」6 條任一紅 ⇒ 08-26 那則真的掉了的留言形狀(「等雲端那半出貨才驗得了」)會漏抓
  • 「不該擋」10 條任一紅 ⇒ 誤攔,這比漏擋嚴重——每次留言都被擋,人就學會忽略它
  • -F <檔> 那兩條紅 ⇒ 內文放在檔案裡時閘看不到,等於走 ticket say 就自動繞過
  • ⑮~⑳(inkstone/ISEP#112:這一組驗的不是「有沒有擋」,是擋下來之後教的那條路走不走得通
    • ⑮⑯ 紅 ⇒ 訊息又印出相對路徑的 scripts/ticket。相對路徑是對貼上去那個人的 cwd 解析的,而 InkStoneCo/scripts/ticket 是舊複本(grep -c subtask → 0) ⇒ 照著貼會印出它「四個動詞」的說明然後什麼都沒發生。
    • ⑰ 紅 ⇒ 閘又自己抄了一份用法(它應該去 ticket usage subtask 現要)。
    • ⑱ 紅 ⇒ 最嚴重:把訊息裡那塊指令原樣抽出來、只填標題/目標/驗收條件三格, 真的執行,離開碼必須是 1(走到網路才停)。是 2 就表示又被某道閘擋下, 這張票的病復發了。
    • ⑲ 是 ⑱ 的鑑別力對照(把閘原本那組 --assign 沒配 --next 接回去,必須紅); ⑲ 綠不了就代表 ⑱ 那條綠燈沒有意義。
    • ⑳ 紅 ⇒ 內文草稿模板跟 REQUIRED_SECTIONS 分家了,會生出「照著貼卻過不了自己那道閘」的票。
    • ㉑ 紅 ⇒ 正本叫不動時(雲端裝壞、路徑不對)閘不是不擋了,就是又在訊息裡補了一份手抄用法。 fail-open 的只准是「訊息內容」,不准是「擋不擋」;而補一份副本就是把這張票拔掉的東西裝回去。

🔴 這一組刻意驗訊息內容,不是只驗離開碼。 system-dev/wiki/mistakes.md 記過:訊息壞掉時閘照樣 exit 2,只看離開碼完全看不出來—— 而這張票(inkstone/ISEP#112)就是那個形狀的極端版:閘擋對了,但它教的解法根本不存在。

A12 — 收工要把棒子交回來:10 條

bash scripts/test-baton-handback-guard.sh

該看到10/10 通過用 fixture 跑,不打網路、不在票池留下測試票失敗

  • 「該報」5 條任一紅 ⇒ 指派/tag/下一步缺哪一格抓不到,08-26 那次掉棒的狀態會靜靜通過
  • 「不該報」4 條任一紅 ⇒ 每條線收工都被念一次,警報會被學會忽略
  • 「票已關」那條紅 ⇒ 棒子已經到終點還在催,那是最典型的假警報

A14 — PR 一定要有結論:52 條

bash hooks/tests/pr-verdict-guard.test.sh

該看到52 通過 / 0 失敗。全程離線(走 PR_VERDICT_FIXTURE), 不打 Gitea、不開測試 PR、不留任何測試票;狀態檔走 PR_VERDICT_STATE_DIR

它在守什麼inkstone/ISEP#812026-08-27 實查):最久的三個 open PR 躺了兩星期 (inkstone/arcrun-rag#91 14 天、inkstone/Arcrun#116 14 天、inkstone/Arcrun#104 15 天), 而 v0.9.0 的 46 支閘一支都沒有在管 PR。票看起來是「已交付」, 東西卻沒進 main ⇒ 沒進版本 ⇒ leo 手上永遠不會出現它

失敗

  • B 群(⑨⑩⑪,票上那三個真跡)任一紅 ⇒ 今天這個形狀會再發生一次
  • C 群 ⑭⑰ 紅 ⇒ 驗收條件 1/3 沒過:「放著不管」抓不到,或「merge 了分支還在」放行
  • A 群任何一條紅 ⇒ 誤攔,這比漏擋嚴重。②③特別重要: 指派給人/掛 Human 之後還在點名,就是 ISEP v0.6.0 divergence §B4 記過的那個坑 (「s/review 佇列非空即 block」⇒ 佇列本來就不會空 ⇒ 總管永遠停不下來
  • E 群 ㉙ 紅 ⇒ 閘訊息裡承諾的出路(「把它指派給那個人,本閘立刻不再點名它」)是假的
  • D 群 ㉓ 紅 ⇒ 判準從「識別碼比對」滑成「只要提到票號就放行」,閘會被任何一句話關掉

📌 真跡不只在 fixture 裡跑過:同一支閘打真實 Gitea 也驗過, 一次點名 7 個沒有結論的 PR,含票上那三個(15/14/14 天)。 指令:printf '{"session_id":"x","transcript_path":"/nonexistent"}' | bash hooks/pr-verdict-guard.sh ——唯讀,不改動任何 PR

A15 — 給結論的那支工具自己說得出要打哪幾通 API

python3 scripts/pr-verdict list
python3 scripts/pr-verdict merge inkstone/ISEP#71 --dry-run

該看到list 印出 open PR 與「有沒有人被指派」;merge --dry-run 印出 [dry-run] POST …/pulls/71/merge[dry-run] DELETE …/branches/<分支>一通都不真的送出失敗--dry-run 底下出現真實的寫入結果 ⇒ 這支工具沒辦法在按下去之前被檢查。

A14 — 每一則回覆都自己說出拖了多久:20 條

bash hooks/tests/countdown-guard.test.sh

該看到通過 20 條,失敗 0 條全程離線:時鐘用 ISEP_COUNTDOWN_NOW 定住、 狀態走 ISEP_COUNTDOWN_STATE_DIR,不打網路、不碰 $HOME

它在守什麼inkstone/ISEP#63leo 2026-08-27): 「前面說過每個回覆要戴上已經花了總時長,這為什麼沒出現?」 「這應該寫在 ISEP,隨時看自己拖了多久」——重點在後面那句: 不是要總管記得戴,是要它長在機器上。 總管當時答「現在開始戴」, 而那正是這條規則第一次失效的方式。

判準:一個新開的 session,什麼都沒被交代,回覆裡照樣有時長。

失敗

  • A 群(注入)任何一條紅 ⇒ 那一行算錯了。④ 特別看:期望「已過 2 小時 13 分」, 實得就要是同一個字串——這格就是票上驗收第 2 條「數字對得上真實經過的時間」
  • ⑤ 紅 ⇒ 連續幾則不是遞增(歸零或亂跳),票上驗收第 3 條
  • ⑦ 紅 ⇒ 過了收工線卻悄悄換算成明天。超時消失 這個東西的意義沒了
  • ⑨ 紅 ⇒ 沒有 milestone 快取時編了一個日期出來(寧可少一段,不准編)
  • B 群(該擋)紅 ⇒ 「注入了但模型沒照做」這個主要失效模式沒有被接住
  • C 群(不該擋)任何一條紅 ⇒ 誤攔,這比漏擋嚴重——每一回合都被念一次, 人就學會忽略它,那它就等於不存在(本 repo 心法第 2 條)

🔴 跑測試前先確認 CLAUDE_CODE_CHILD_SESSION 沒有殘留:本閘刻意放行子 session subagent 的回覆不是給 leo 看的),所以在一條 subagent 裡跑,B 群會全綠而且是假綠。 測試檔自己會把它清掉——2026-08-28 第一次跑就撞到這個,才補上去的。

A16 — 現在的主線是哪一個:24 條

bash hooks/tests/mainline-focus-guard.test.sh

該看到通過 24 條,失敗 0 條全程離線:狀態走 ISEP_COUNTDOWN_STATE_DIR、 時鐘走 ISEP_COUNTDOWN_NOW、「那張票掛在哪」走 ISEP_MAINLINE_FIXTURE 並把 TICKET_HOST 指到一個連不上的位址——任何一條真的走到網路,會在那裡當場失敗, 不會靜靜地變成假綠

它在守什麼inkstone/ISEP#82leo 2026-08-27): 「14 個里程碑同時亮著卻不知道該看哪個」。當天實查 14 個 open milestone 其中「Mira 現代化」這個名字同時活在 5 個 repo,5 個已經逾期 ⇒ SOP 說的「只做 milestone 的事」沒有指涉對象,等於不存在

判準:問「現在的主線是哪一個」,scripts/mainline 回一個答案,而且只有一個。

失敗

  • A 群任一條紅 ⇒ 答案不唯一,或標了新的舊的還在——那就回到 14 個一起亮的狀態
  • ⑧ 紅 ⇒ 目標宣告沒有自己出現(票上驗收第 2 條),leo 又要自己去翻
  • ⑨ 紅 ⇒ 主線的名字沒掛在被查核的 ⏱ 那一行上 ⇒ 它到不了 leo 眼前 (本票刻意不另立第二道會擋人的閘,就是靠這一格成立)
  • ⑩ 紅 ⇒ 用「期限最近的那個」蓋過了被指定的主線。猜的不准蓋過指定的
  • ⑬⑭ 紅 ⇒ 派了不在主線上的票沒被問一次,或問了卻沒給補收/跳線兩條路
  • ⑯ 紅 ⇒ 鬼打牆:同一張票被擋第二次。至多擋一次是硬要求
  • ⑲–㉔(不該擋)任一條紅 ⇒ 誤攔,這比漏擋嚴重。特別是 ⑲(沒有主線就一律放行, 票上驗收第 4 條)與 ㉒(問不到那張票掛在哪 ⇒ 放行)—— 「讀不到」不等於「不屬於」,把這兩件事講成同一句是最貴的錯

📌 這一條線的另一半是指令,不是閘:scripts/mainlineshowlistset clearrefreshadopthas)。要打網路的那幾個(list/set/adopt)不在測試裡跑, 因為它們只有真的 Gitea 才驗得了——驗法見 A17。

A17 — 主線那支指令真的問得到 Gitea(要網路)

python3 scripts/mainline list

該看到:一份 open milestone 清單,跨多個 repoISEP / Arcrun / arcrun-rag / mira…), 每一行左邊是可以直接貼給 setowner/repo#<milestone id>失敗

  • 一個 open milestone 都沒讀到 ⇒ 這台機器拿不到 Gitea。那是讀不到,不是沒有 ——不要因此標一個猜的主線
  • 只有單一 repo ⇒ 沒有跨 repo,等於沒看到全局

A15 — 發通知不等於部署:37 條

bash hooks/tests/prod-write-guard.test.sh hooks/prod-write-guard.sh

該看到通過 37 失敗 0(原本 29 條,inkstone/ISEP#63 補 8 條)。 失敗

  • 「卡點一」6 條任一紅 ⇒ 要嘛 leo 收不到 Telegramnotify_leo 被當成部署擋掉), 要嘛白名單放太寬——「別的 named webhook」「部署端點」兩條若變綠,等於這道閘被拆了
  • 「卡點二」2 條任一紅 ⇒ 「談論它」又被當成「執行它」(同款第八次), 或是剝了內文之後連真的部署都放行了

A16 — 一次交貨 = 一份清單(跨 repo 版本組合):21 條

bash scripts/test-release-manifest.sh

該看到通過 21 條,失敗 0 條。全程離線(RELEASE_MANIFEST_FIXTURE), 不打 Gitea、不建任何真的 release;清單寫在 mktemp 的目錄,不碰 repo 裡的 releases/

它在守什麼inkstone/ISEP#84):一次交貨常常同時動到好幾個 repo, 而「這一版 = 哪幾個 repo 的哪幾版」沒有任何地方記著 ⇒ 退版只退了其中一個, 剩下的還停在新版 ⇒ 變成一組從來沒測過的組合

失敗

  • ⑨⑩ 紅 ⇒ 驗收 1 沒過:版本號寫上去就算數,沒有真的去 Gitea 抓過 (「寫上去」跟「存在」是兩件事,而清單的用處完全建立在後者)
  • ⑱ 紅 ⇒ 驗收 3 沒過:只退其中一個 repo 沒有被擋下來,那正是票上那個病
  • ⑯⑰⑲ 任一紅 ⇒ 驗收 2 沒過:退版沒有吐出整份清單的每一格 (包含「已經在目標版本、不必動」那幾格——列出來才證明沒有一格被漏掉)
  • ⑫ 紅 ⇒ 凍結過的清單還能再加東西,「凍結」兩個字就沒有意義了
  • ⑳㉑ 紅 ⇒ 驗收 4 沒過:leo 打開 INDEX.md 看不出「我現在手上是哪一版」

A17 — 每次結案都留下估多久/花多久/差多少:23 條

bash scripts/test-milestone-account.sh

該看到通過 23 條,失敗 0 條。全程離線(MILESTONE_ACCOUNT_FIXTURE =一份假的 Gitea 回應表),時鐘用 MILESTONE_ACCOUNT_NOW 定住,帳本寫在 mktemp 目錄, 不打 Gitea、不關任何真的 milestone

它在守什麼inkstone/ISEP#85leo 2026-08-27 說那天「拖時間」): 拖了多久、比預計多拖多少、為什麼拖——沒有任何數字。偵測器早就有了 mainline-idle-guard.shfactory-idle-guard.sh),但沒有人把它算成帳

失敗

  • ①②③④ 任一紅 ⇒ 驗收 1 沒過:三個數字不是自己算出來的
  • ⑤⑥ 紅 ⇒ 驗收 2 沒過:差超過 ±25% 卻能不挑代號就結案
  • ⑧ 紅 ⇒ 代號不再是封閉集合。能統計的前提是分類有限,這一格垮了統計就垮了
  • ⑨ 紅 ⇒ 挑一個時間軸撐不住的代號也能過,等於「採信我自己說的」, 而票上寫死證據一律從 Gitea 的時間軸取
  • ⑦ 紅 ⇒ 誤攔:只差 -6% 也逼人挑代號。這比漏擋嚴重——每次結案都被念, 人就學會繞過去
  • ⑭⑮⑯⑰ 任一紅 ⇒ 驗收 3 沒過:累積之後看不出哪一種原因最常發生
  • ⑱⑲ 紅 ⇒ 驗收 4 沒過:拿已經逾期的里程碑進去算不出數字

A18 — 結案要記帳的那道閘:22 條

bash hooks/tests/milestone-account-guard.test.sh

該看到通過 22 條,失敗 0 條。離線(帳本走 MILESTONE_ACCOUNT_LEDGER), 純結構判斷、沒有語意判官,所以每次結果都一樣。

失敗

  • A 群任何一條紅 ⇒ 誤攔,這比漏擋嚴重。 ⑥⑦⑧⑪ 特別重要: echo 一段指令、cat 這支閘自己、commit 訊息裡提到、把指令寫進文件的 heredoc 內文 ——四種都只是「談論它」,不是「執行它」。這四格是本 repo 撞過很多次的同一個病 (strip_heredoc.py 的檔頭記著兩次真跡)
  • ⑨⑩ 紅 ⇒ 走正門 scripts/milestone-account close 反而被自己的閘擋下, 那道閘就等於封死了唯一的出路
  • ⑭⑮⑯⑰⑱ 任一紅 ⇒ 漏擋:換個寫法(python urllib、前面串一個無害指令、 --request 長寫法、換一個 repo)就繞過去了
  • ⑲ 紅 ⇒ 訊息沒有點名目標,人看完不知道要對哪一個里程碑動手
  • ⑳㉑ 紅 ⇒ 「記過帳就放行」這個出路是假的,或者一記帳就把所有里程碑全開了

A16 — 「總管可以放行」那道門真的打得開:17 條

bash hooks/tests/gate-ok.test.sh

該看到通過 17 條,失敗 0 條

它在守什麼inkstone/ISEP#90 ④,2026-08-28 實查):三支閘 prod-write-guardmain-and-prod-push-guardstage-before-prod-guard 都是「擋下來、但總管看過就能放行」的設計,而既有測試只驗了擋得住, 一條都沒驗過放得開。於是這個 bug 活了很久:stat -f %m 在 GNU coreutils 上 是「檔案系統資訊」,它一邊回非零一邊吐一整段文字 ⇒ 秒數被污染 ⇒ 在 Linux(=每一個雲端 session)上戳記永遠不被接受 ⇒ 那三支閘在雲端等於純擋, 而閘不會告訴你門是壞的。

失敗

  • ②⑤(門打得開)紅 ⇒ 逃生口又焊死了,那三支閘在雲端變回純擋
  • ⑥⑦⑧(門沒變寬)任一紅 ⇒ 更嚴重:綁 repo/有效期/空戳記那三條性質是 08-11、08-12 兩次真的被穿透之後才補上的,不准為了「好放行」而鬆掉
  • ⑫ 紅 ⇒ gate-ok 在解不出 repo 時留下了一枚註定打不開的空戳記, 那會讓人以為門開了(而空戳記本身就是 08-12 那把萬用鑰匙的形狀)
  • ⑰ 紅 ⇒ 判準又變回「行為取決於 cwd 裡有沒有一個叫 %m 的檔」。 這條是這個 bug 的最後一層:GNU 的 -f 是布林旗標,%m 被當成另一個檔名運算元 ⇒ 有那個檔就 exit 0|| 連跑都不跑。所以修法不能只是「把順序反過來」, 每一步都要驗它是不是純數字

⚠️ 這支會真的寫 /tmp 的戳記檔(那是閘寫死的路徑)。不要在「已經蓋好戳記正要推東西」 的當下跑它——它會把那枚戳記洗掉。

A17 — 未推警察不會對雲端的工作分支亂叫:10 條

bash hooks/tests/unpushed-police.test.sh

該看到通過 10 條,失敗 0 條。全離線(用本機 bare repo 當「遠端」)。

它在守什麼inkstone/ISEP#90 ①):雲端 session 開出來的工作分支天生沒有 upstream, 內容卻等於遠端 main ⇒ 舊判準「沒 upstream=從沒推過」讓每個雲端 session、每次收工 都被攔一次08-27 一個 session 五次全是誤報)。

失敗

  • A 群(①—⑥,不該報)任一紅 ⇒ 誤攔,比漏擋嚴重:永遠在響的警報=訓練人忽略它, 下一條真的失蹤的分支會混在雜訊裡
  • B 群(⑦—⑩,該報)任一紅 ⇒ 為了不吵而改成放行了,那是把閘關掉不是修好
  • 特別看 ④:問不到遠端(離線)不准當成「你沒推」

A18 — 信標會講出雲端會壞掉的那幾件事:33 條

bash hooks/tests/isep-presence-beacon.test.sh

該看到通過 33 條,失敗 0 條。全離線。

📌 inkstone/ISEP#672026-09-07)從 26 條加到 33 條:信標 ④ 開場報「打了 tag 卻沒 release」,見 A38。 📌 inkstone/ISEP#122 從 14 條加到 26 條:信標原本只掃 scripts/真正會自動載入的東西skillcommandagent)同樣兩邊各有一份。 實查:那 9 個檔案在 0.1.0c263866)複製過來之後一次都沒再同步 到 2026-09-02 已經分家兩個、而且方向相反—— skills/ship-check/SKILL.md 是 InkStoneCo 那邊新,commands/sdd-check.md 是 ISEP 這邊新。 ⇒ 所以新增的不只是「有沒有掃到」,還有「說不說得出真相源是哪一份docs/file-ownership.tsv),以及雲端沒有專案那一份可比時改用 sha256 單邊驗。

它在守什麼inkstone/ISEP#90 ②③):信標原本只證明「有一份 plugin 載入了」, 不證明「載入的是哪一份」——08-27 雲端載 0.3.9、main 0.9.0,差 7 個 release 而它照樣是綠的。

失敗

  • ⑫⑬⑭(信標永遠在)任一紅 ⇒ 最嚴重:那一行消失=leo 會判定這個 session 零閘
  • ③ 紅 ⇒ 版本落差報不出來,ISEP#67 那個病又變回看不見
  • ⑤⑦ 紅 ⇒ 舊複本遮蔽正門抓不到(InkStoneCo/scripts/ticket 那件)
  • ⑥ 紅 ⇒ 誤攔:同步過的複本被念,人就學會忽略它
  • ⑪ 紅 ⇒ 內層迴圈變數撞名的回歸(同一個 .claude 下第二個殘骸會被靜靜跳過)
  • ⑮⑱⑲⑳ 任一紅 ⇒ 自動載入的分身抓不到(ship-check 那件會再發生一次)
  • ⑰ 紅 ⇒ 誤攔:同步過的複本被念,人就學會忽略它(跟 ⑥ 同一條線)
  • ㉔ 紅 ⇒ 雲端唯一還作數的那個檢查失效(薄殼沒有 InkStoneCo 可以比)
  • ㉕ 紅 ⇒ 誤攔:還沒登記 sha256 的檔案被當成「被改過」

A29 — 閘印出來的逃生門,照著打真的過得去:10 條

📌 編號跳過 A27/A28:那兩格被同一張票的 PR inkstone/ISEP#124 佔著(還沒併)。

bash hooks/tests/history-first-guard.test.sh

該看到通過 10 條,失敗 0 條。全離線,全程用 KBDB_STAMP_DIR 指到 TMP 不碰這台機器真正的 /tmp/.kbdb-* 戳記(清掉別人的戳記=把閘弄成隨機的)。

它在守什麼inkstone/ISEP#1222026-09-02 實撞):history-first-guard.sh 印的 🚪 KBDB 真的連不上touch /tmp/.kbdb-down 後重送假的—— touch 造出來的是空檔,而那支閘讀的是檔案內容當時戳,空字串被當成 0 ⇒ 「距今 17 億秒」⇒ 永遠不新鮮 ⇒ 照著訊息打完,被一模一樣地擋第二次

🔴 這跟本票 comment 6071、inkstone/ISEP#125 是同一句話: 閘印出來的下一步,沒有人實際照著打過一次。

失敗

  • ④ 紅 ⇒ 逃生門又是假的(這是本支唯一分辨得出新舊版的那一格,見檔頭)
  • ⑦ 紅 ⇒ 逃生門變成永久後門(一次 touch 就免疫,過期不算數這件事沒了)
  • ⑧⑨⑩ 任一紅 ⇒ 誤攔:文件/新檔/測試檔本來就不該被這支碰

A30 — 測試沙盒傳錯參數時要在複製之前收手:10 條

bash hooks/tests/hook-sandbox.test.sh

該看到通過 10 條,失敗 0 條。全離線。

它在守什麼inkstone/ISEP#1222026-09-02 實撞,兩次): hooks/tests/lib/hook-sandbox.shhook_sandbox <hook 的檔案路徑> 舊版不驗參數 直接 cp -R "$(dirname "$1")"。順手把 repo 根目錄傳進去時:

$ bash hooks/tests/main-and-prod-push-guard.test.sh "$PWD"
   dirname → ~/Documents/tech_projects        ← 上一層,不是 hooks/
   cp -R   → 整個 tech_projects(所有 repo、所有 worktree)搬進 mktemp
   實測      一次 13 GB+一次 10 GB,磁碟可用從 25 GB 掉到 462 MB
   印出來的  ❌ 沙盒建不起來                    ← 只有這一句

🔴 它沒說參數傳錯,也沒說它已經把磁碟寫滿了。 判準用「要求某個東西在場」($1 要是真的檔案;上一層要叫 hooks), 不是關鍵字比對——兩條任一不成立就在 mktemp 之前 return 1

📌 正確用法(兩支需要傳參數的測試,docs/TESTING.md 之前沒寫過):

bash hooks/tests/main-and-prod-push-guard.test.sh            hooks/main-and-prod-push-guard.sh
bash hooks/tests/main-and-prod-push-guard-cross-repo.test.sh hooks/main-and-prod-push-guard.sh
bash hooks/tests/prod-write-guard.test.sh                    hooks/prod-write-guard.sh
bash hooks/tests/stage-before-prod-guard.test.sh             hooks/stage-before-prod-guard.sh
bash hooks/tests/gitea-arm-check.test.sh                     .

不傳的後果不是報錯,是假綠prod-write-guard.test.shHOOK="$1" 空掉時 每一條都執行空指令回 0 ⇒ 「該擋」全部變成「實得 pass」,19 條假紅 (同一支傳對參數是 通過 37 失敗 0)。不必自己傳參數的包裝在 scripts/test-main-and-prod-push-guard.sh

失敗

  • ①③⑤⑥ 任一紅 ⇒ 收手收得太晚,暫存區已經開始長東西(磁碟風險回來了)
  • ② 紅 ⇒ 訊息沒給出走得通的那一行(本票整張票在講的就是這件事)
  • ⑧⑨⑩ 任一紅 ⇒ 誤攔/複製錯:正常用法被弄壞,或複本裡混進了 hooks/ 以外的東西

A31 — 雲端工人抓票的規則是機械可判的:53 條

bash scripts/test-ticket-pick.sh

該看到通過 53 條,失敗 0 條全程離線:假池子(3 個 repo、3 個 open milestone、 12 張票、1 條相依邊)餵給換掉的 api(),時鐘走 ISEP_COUNTDOWN_NOWTICKET_HOST 指到連不上的位址 ——任何一條真的走到網路會當場炸,不會靜靜變成假綠。不開票、不改票、不留任何東西在 Gitea 上。

它在守什麼inkstone/ISEP#131):Routine 08-06 起讀 journeys.md 本 sprint 段, 08-19 到期沒續,連續兩週讀到殘骸只能空轉。09-07 把 cloud-worker.md 步驟 1 改成從 Gitea 主線里程碑抓票(inkstone/InkStoneCo#118),但那是一段給人讀的字。 這一支把規則做成 scripts/ticket pickclaim 兩個動詞,規則本體在 pickable() 一支純函式:

可抓  s/* 恰好是 {s/todo}  沒有 assignee  沒有 Humanhuman/*  不是 hub + 在主線上
      「在主線上」=hub 里程碑裡、或被主線成員當相依(跨 repo 邊,inkstone/ISEP#133);
      別 repo 裡同名的里程碑**不算**主線。主線抓盡才抓「逾期的 open 里程碑」(一個里程碑物件一組);
      backlog/沒里程碑且沒有邊的一律不抓
認領  claim = 指派 + s/doing + 第一行【身份】的留言,一個動作
完成  handback --label s/review(本來就有的那半,不重做)

失敗

  • ①「★」那四條任一紅 ⇒ 票上驗收第 1 條破了:Human/有 assigneebacklog 有一種會被抓走
  • ①「s/todos/doing 同時掛著」紅 ⇒ 會把別人正在做的票抓走(09-07 實查 inkstone/mira#6 就是這個形狀——exclusive 只擋 UI 不擋 API
  • ②「主線抓盡 → 才輪到逾期」那兩條紅 ⇒ 順序壞了:要嘛主線還有票就去抓逾期的, 要嘛抓盡了還回 Arcrun#8(既不是主線也沒逾期)
  • ②「離開碼 1」紅 ⇒ 「真的沒有票」與「讀不到」被講成同一句——後者要離開碼 2
  • ②「沒有主線 → 離開碼 2 且一通 API 都沒打」紅 ⇒ 沒主線時去抓了別的
  • ②「ISEP#1 靠相依進主線」/「ISEP#13 同名沒邊 → 不在」任一紅 ⇒ 成員又變回靠名字算 (leo 2026-09-07 推翻的那條判準回來了,A41 也會一起紅)
  • ③「該擋」六條任一紅 ⇒ 規則只長在 pick 這端,手動 claim 一張 Human 的票照樣過
  • ③「身份名不在名單上 → 一通都沒打」紅 ⇒ 名單以外的名字碰到了 Gitea
  • ④ 第一條紅 ⇒ 連不上 Gitea 時回了離開碼 1,雲端會把「斷線」當「沒票」收工

📌 真實 Gitea 唯讀實跑2026-09-07isep-hand,不改任何票): ticket pick --mainline InkStoneCo/system-dev/mainline.json --all 在主線 「AI 問一次就看得到全部」回 ISEP#130ISEP#131 兩張(Arcrun#175/176 已有 assignee、 Arcrun#86 是 s/doing、mira#6 s/todos/doing 都沒被抓);逾期里程碑組把 ISEP#3135 五張 hub 排除後剩 Arcrun#83mira#5arcrun-rag#14/27/37寫入那半claim inkstone/ISEP#131 --name isep-hand 真的認領過一次: assigneeclaude-code、標籤 s/todo → s/doing、留言 6325 第一行【身份】—— 之後再 pick 就不再回 #131(票上驗收第 2 條的 log 在票的留言裡)。

A19 — 下游做完時頂層跟著關:49 條

bash scripts/test-ticket-handoff-writeback.sh

該看到通過 49 條,失敗 0 條全程離線——TICKET_HOST 指到連不上的位址, 會打 API 的兩段(_writebackcmd_subtask)把 api() 換成錄音機跑, 不打真實 Gitea、不開票、不關票、不留任何測試票

它在守什麼inkstone/ISEP#92): 「開在頂層的票,下游做完了卻沒人回來關⋯⋯頂層票會永遠掛著,而 leo 是看頂層的。」

四格對應票上的四條驗收條件:

  • ①②③ 純函式(is_loosewriteback_planjourney_label)——判準本身 不必開真票就驗得動
  • ④⑤ subtaskhandoff 的參數閘:該擋的擋、齊全的放得過
  • 完工回寫的接線(驗收第 2 條):關掉一張下游票之後,它到底對頂層票做了什麼
  • 雙向連結的接線(驗收第 1 條):兩張票互相看得到對方,不是靠人記得補

失敗

  • ①「open + 從來沒有下游 → 不撈」紅 ⇒ 誤攔ticket loose 會把每一張普通票 都列出來,那張表就變成雜訊,人學會忽略它(本 repo 心法第 2 條)
  • ②「還有別的下游沒關 → 只記一筆」紅 ⇒ 母票會在下游還沒做完時被指派回總管, 假綠
  • ⑦「沒有去關母票」變綠 ⇒ 回寫從「處理」滑成「自動關掉」。 默默關掉跟默默留著是同一個病的兩面——關票要有交付物、要有人看過
  • ⑦「留言第一行有身份欄」紅 ⇒ 機器貼的留言看起來像某個人寫的, 下一個讀票的人會去找那個人(reply-identity-guard 管的是同一件事)
  • ⑧「母子兩端都被貼」剩 1 ⇒ journey 只貼了一端,聚類時撈得到一半 比完全沒貼更危險
  • ⑤ 任何一條紅 ⇒ 誤攔,合規的交辦被擋掉等於這條路不能走

🔴 這支測不到的那一格(要 leo 或總管接手)labels.yamlj/刻意是空的——旅程怎麼切、叫什麼名字是方向題,不由工具代決。 在有人往那裡加第一條旅程之前,--journey 只會擋、不會貼。 機制驗過了,資料還沒有

A20 — 舊票每天有固定管道被撈出來:47 條

bash scripts/test-debt-worklist.sh

該看到通過 47 條,失敗 0 條全程離線:資料走 ISEP_DEBT_FIXTURE、 時鐘走 ISEP_DEBT_NOW、狀態走 ISEP_DEBT_STATE_DIR、主線走 ISEP_COUNTDOWN_STATE_DIR ——不打 Gitea、不留測試票、不碰 $HOME

它在守什麼inkstone/ISEP#83leo 2026-08-27): 「現在每天都在追新的,所以要用 Routine 去消化舊的,可以有多個條件」。 全 org 229 張 open 票,每天在動的只有掛在 open milestone 上的那 56 張; 其餘的不是不重要,是沒有任何機制會去拿它們

🔴 兩條線各用各的判準,不是二選一(leo 當場訂正總管的誤解): 掛 milestone =緊急線,用「距離目標的遠近」排;沒掛的=還債線,用多條件排 (事故/擋人/承諾/票齡/估工)——後者就是 scripts/debt-worklist

失敗

  • 「驗收 1」那組紅 ⇒ 清單沒有附「我查了哪些 repo」的證明。 沒有證明的清單分不出「今天真的沒有」與「查詢壞了」,而後者會靜靜地零產出
  • 「驗收 2」紅 ⇒ 空清單默默結束。這是這支工具最貴的失效方式: 它看起來跑完了,於是沒有人再去看那 180 張
  • 「驗收 3」紅 ⇒ 領走的票明天又冒出來,這份清單就會變成每天一樣的一坨,人就不看了
  • 「成包」兩條紅 ⇒ 互相指著/母子票被拆開領,做到一半才發現卡在另一張
  • 「單向引用不成包」紅 ⇒ 這是誤攔的那一面:第一版用單向引用成包, 結果 190 張裡 121 張黏成一包(大家都會順手引用 hub 票)=一包沒有人領得動
  • 「接上主線」那組紅 ⇒ 還債線又自己養了一套「哪個是 active」的判斷。 唯一答案在 hooks/lib/mainline.pyinkstone/ISEP#82),兩份必然漂移。 特別看「沒標主線」那兩條:沒有答案時要退回保守(掛 open milestone 的一律不領), 不准猜一條出來
  • 最後一組(SessionStart)紅 ⇒ 要嘛沒有人會被提醒去撈, 要嘛那一段偷偷去打網路——開 session 自動撈就是輪詢,紅線擋著

手動驗真實資料(會打 Gitea,唯讀 GET):

python3 scripts/debt-worklist list --top 5

該看到15 個 repo 逐一列出 issuePR 數,講得出現在的主線是哪一條 (或誠實說沒標),扣除數字講得出來(掛 open milestone 的幾張、等 leo 的幾張、已領走的幾張), 前幾名旁邊看得到「為什麼排這裡」的分項。 失敗:前幾名一眼看不出為什麼在那裡 ⇒ 那些權重就是錯的,去改 score() 不要改成「總管覺得」——這份清單的價值就在於它不靠記憶。

A21 — 沒人會叫的事會自己叫:36 條

bash hooks/tests/overdue-nag.test.sh

該看到通過 36 條,失敗 0 條全程離線——資料走 --fixture、時鐘走 --now、 網路用 ISEP_NOTIFY_OFFLINE=1 關掉。不打 Gitea、不打實例、不留任何測試票。

它在守什麼inkstone/ISEP#932026-08-27 實查):一張票掛著等 leo 三天了、 一個 milestone 逾期了、一根棒子躺著沒人接——沒有任何東西為此叫過一聲。 當天有五個 milestone 逾期(08-24 三個、08-26 兩個),一聲都沒有。

失敗

  • A 群任一紅 ⇒ 撈不出票上點名的那五個逾期 milestone,或訊息不是白話的(票上驗收 1)
  • ⑨⑩ 紅 ⇒ 沒東西可報時安靜結束(票上驗收 2)。安靜跟壞掉長得一模一樣
  • ⑪ 紅 ⇒ 撈不到資料時把「我沒查到」講成「沒有事情逾期」——那是最貴的一種假情報
  • C 群任何一條紅 ⇒ 誤報,這比漏報嚴重:每次開場都被念一串不相干的東西, 人就學會跳過它,那時真的有事也叫不動他
  • D 群紅 ⇒ 發不出去卻靜默。「送出成功」跟「送到了」是兩件事。 ㉒b 特別看:退路留言若只帶閘的判定、不帶為什麼送不出去, 下一個人會去修閘——而斷點可能根本不在那裡(2026-08-28 第一版真的漏了這一格)
  • ㉖㉗㉘㉙ 紅 ⇒ 這個 session 的閘是哪一版變回「假設」。㉘ 特別重要: 閘說會擋就不准從 python 這條路繞過去——繞得過的閘等於不存在
  • ㉛ 紅 ⇒ 探針把 /tmp/.prod-write-ok 燒掉了(那是總管單次用完即丟的授權)
  • ㉟ 紅 ⇒ 每條 subagent 開工都吵 leo 一次

🔴 跑測試前先確認 CLAUDE_CODE_CHILD_SESSION 沒有殘留:這支閘刻意放行子 session 在一條 subagent 裡跑,F 群會全綠而且是假綠。測試檔自己會把它清掉。

A22 — 壓 wiki 不准弄丟東西:25 條

bash hooks/tests/wiki-compress.test.sh

該看到通過 25 條,失敗 0 條全程離線,只在 mktemp 目錄裡動檔案, 不碰任何真的 wiki

它在守什麼inkstone/ISEP#89):mistakes.md 是「做新功能前讀一遍」等級的必讀檔, 實測 7,681 行 / 260 條——沒有人真的每次都從頭讀。讀不完的必讀檔,等於沒有。

失敗

  • ①② 紅 ⇒ 切條切錯了,後面三件全部失準。② 特別重要:mistakes.md 裡真的有 寫在 code fence 裡的 ##(第 534 行那種),把它當成一條就會拿不存在的東西去對帳
  • ⑤⑥ 紅 ⇒ 弄丟了東西卻沒被發現(票上驗收 2)
  • ⑦ 紅最嚴重:那是反向測——真的弄丟一條時 verify 抓不到。 一個抓不到問題的對帳表,比沒有對帳表更糟,因為它會被當成證據
  • ⑧⑨⑩ 紅 ⇒ 壓完查不到、或查得更慢(票上驗收 1)
  • ⑪–⑮ 紅 ⇒ 壓縮沒有票號、沒有交付紀錄(票上驗收 3:不准順手做完沒人知道)
  • ⑱⑲㉑ 任一紅 ⇒ 誤攔,這比漏擋嚴重:一般編輯被擋、非 wiki 的檔被擋、 新建檔案被擋,人就學會繞過它
  • ㉒ 紅 ⇒ 擋不只一次 ⇒ 會卡死
  • ㉕ 紅 ⇒ 都在門檻內還要講一次話,那行提示下次就沒人看了

📌 真跡跑過:拿現在的 mistakes.md 複本實壓一次(不動真的 wiki)—— 7,681 行 → 1,199 行260 條一條都沒少verify 逐條對帳)、 80 個查詢命中率 80/80,定位成本 2,956 行 → 131 行,快 22.5 倍bench)。 指令:

cp <某個 wiki>/mistakes.md /tmp/w/ && python3 scripts/wiki-compress apply /tmp/w/mistakes.md --ticket inkstone/ISEP#89
python3 scripts/wiki-compress verify /tmp/w/mistakes.md.before-compress /tmp/w/mistakes.md /tmp/w/mistakes-archive-*.md
python3 scripts/wiki-compress bench  /tmp/w/mistakes.md.before-compress /tmp/w/mistakes.md /tmp/w/mistakes-archive-*.md

A23 — 同時跑的線有上限:33 條

bash hooks/tests/parallel-lines-cap-guard.test.sh

該看到33/33 通過離線、不打網路、不花錢——每個案例自己搭一份假的 harness 佈局 (<sid>.jsonl <sid>/subagents/agent-*.meta.json),判準只有檔案的存在與 mtime,沒有語意判官。

它在守什麼inkstone/ISEP#1092026-08-29 實撞):總管同時開七條線,8 GB 的 Mac 重開機; 同一天還派錯線 1 次、量錯東西 6 次、停掉正確的工作 1 次。leo:「跑 2-3 條應該是極限了」。

失敗

  • A 群 14 條任一紅 ⇒ 誤攔。這比漏擋嚴重——④⑤紅代表「收工了還在擋」, 那會變成整台機器永遠派不了工
  • ⑬⑭ 紅 ⇒ fail-open 壞了。這支刻意選「算不出來就放行、但出聲」: 算不出來就擋會卡死所有派工,那是比漏擋貴得多的失敗
  • ㉒ 紅 ⇒ 安靜窗的邊界算錯了,那是唯一擋著「永久卡死」的保險

📌 這支閘的三個機械前提是實測出來的,不是推測的(改它之前先重測這三件): SubagentStop 在實測的 session 裡一次都沒觸發(所以不能拿它當減法); PostToolUse:Agent送出後 5 秒就觸發(不是收工); subagent 不是獨立行程ps 只有一個 claude-code 行程,所以數行程數不到線)。

A24 — 一條線要有自己的工作目錄:110 條

bash hooks/tests/line-needs-own-worktree.test.sh

該看到110/110 通過。離線,每個案例自己開兩顆真的 git repo +一份真的 linked worktree +一顆本機 bare 遠端。

GH 群在守什麼inkstone/ISEP#1472026-09-07 補):分身住 repo 裡面,收工要被收。 leo 在 Finder 看到 ISEP-wt-122shipISEP-wt-117ISEP-wt115InkStoneCo-wt-112…一排——舊版教「開在 repo 旁邊、 收工 worktree remove」,而 remove 只寫在閘訊息裡,沒機制驗。 G 群的測資是閘自己印出來的 scripts/worktree open 那一行(78) 擋一次、(79) 抽出、(80b) 只填票號與分支真的跑), 然後看三件事實:分身在 <repo>/.worktrees/ 底下、repo 旁邊的目錄清單一個都沒多(81))、共用目錄 git status 乾淨((82))。 H 群餵的是 PostToolUse Agent 的 payload(派工單 【工單】owner/repo#N,總管 session):沒推 ⇒ exit 2 點名分支+路徑+推的指令、分身一根寒毛沒動((86)–(91)); 推了但有未追蹤檔 ⇒ exit 2((92)–(94));推了且乾淨 ⇒ exit 0、目錄與登記都沒了、分支還在((95)–(98)); 沒工單/沒分身/工具不是 Agent ⇒ 安靜((99)–(103),誤攔比漏擋嚴重);一單兩票各自處理((104)–(106)); 環境裡的 WORKTREE_OK=1 是切分支的逃生門,不影響收工((107))。 修之前拿新測試跑舊閘(main 那份):90/11020 條紅——㉖㉙㉚b㉚c(訊息還在教開在旁邊)+ G/H 全部;B/D/E/F 全綠。紅的正好是這次改到的行為。

E 群在守什麼comment 65872026-09-07 補):閘印出來的那條出路要真的走得通。 閘訊息教的是 WORKTREE_OK=1 git -C … checkout …,舊版讀的卻是 hook 自己的環境變數——PreToolUse hook 跟指令不是同一個行程,指令前綴的賦值到不了它 ⇒ 總管三次照貼三次被擋。E 群的測資是閘自己印出來的那一行 ((61) 先擋一次、(62) 抽出那行、(63) 原樣餵回去要放行);(64)–(67) 釘住判準是位置不是字 echo WORKTREE_OK=1; git checkout、前綴掛在別的指令上、值不是 1、寫在 commit 訊息裡,四種都照擋。 修之前拿新測試跑舊閘:(60)(63)(68) 三條紅,其餘全綠——紅的那三條就是真的改到的。

F 群inkstone/ISEP#125 票上原文的驗收表 A–F((70)–(75),期望值照票:A–E 要 0、F 要 2)。 D/E 是「用 heredoc 寫一份內含 cd <目錄> && git checkout X 示範的文件」被當成在切分支(09-02 兩次實地命中), 現在先用 lib/strip_heredoc.py 剝掉 body 再解析(跟 D20 閘同一支 helper)。(76) 是寫成測試的已知邊界: tokenize 層把換行當空白吞掉,…EOF⏎git checkout main 從第一版起就看不到(漏擋不是誤攔,與 (53) 同層,另報); (77) 是它的對照組(換成分號就擋)。

D 群在守什麼comment 53982026-08-29 補):不只要擋對,還要說得出是哪一個 repo。 舊版一律拿 payload 的 cwd 當答案,於是 cd <別的 repo> && git checkout 擋是擋對了, 訊息卻指著 cwd 那個 repo ⇒ 照著做的人會在錯的 repo 開一份用不到的 worktree, 真正要隔離的那個沒開到,而他以為隔離好了。🔴 一道閘給錯下一步,比不擋更糟。 D 群同時釘住反面:認不出來(cd $VARcd -、cd 到不是 repo 的地方)就放行,不猜。

它在守什麼inkstone/ISEP#109 → comment 53912026-08-29 實撞): 每個 repo 只有一份工作目錄,所有線共用。arcrun-rag#163 切到自己的分支、交回時沒切回來, 總管後來在同一個目錄跑 ship.mjs讀到的是別人留下的 HEAD🔴 票號說得出「這是哪個任務」,沒有任何東西說得出「這個目錄現在是誰留下的狀態」

失敗

  • A 群 16 條任一紅 ⇒ 誤攔。特別是⑤⑥⑦(還原檔案)與⑨(已經在自己的 worktree 裡)—— 擋掉它們等於線動不了工
  • ① 紅 ⇒ 連總管在自己的目錄裡切分支都被擋。那不是嚴格,那是把共用目錄的主人趕出去
  • ㉞㉟ 紅 ⇒ prune 做錯了。㉞是沒清掉說謊的登記;㉟是把還在的 worktree 也弄掉了,那是災難
  • (63) 紅 ⇒ 閘印的出路又走不通了——被擋的人不會停下來修閘,他會去找繞過去的方法(6587 當天就是)
  • (64)–(67) 任一紅 ⇒ 出路退化成關鍵字:印個字就能過,閘等於沒有
  • (75) 紅 ⇒ 閘廢了#125 原話):剝 heredoc 剝過頭,真的切也放行
  • (76) 紅 ⇒ tokenize 那層被改了,回頭跑 (53) 與推 main 的 1019 條

A25 — sdd-guard 退役了,而且退乾淨了:8 條

bash hooks/tests/sdd-guard-retired.test.sh

該看到通過 8 失敗 0。離線,自己開兩顆假 git repo,跑完自己清。

它在守什麼inkstone/ISEP#91):leo 2026-08-16 在 inkstone/InkStoneCo#40 裁定 取消 Active SDD——任務狀態搬到 Gitea 管,SDD 只記「起初的樣子」。 但 sdd-guard.shfail-closed 的:status: active 不是恰好 1 份就擋(0 份也擋), 路徑所在的 repo 沒有 3-specs 也擋。⇒ 照裁決把 active SDD 拿掉,會當場鎖死所有 code 寫入, 這就是那個裁決躺了 11 天沒人敢執行的真正原因。

🔴 這支測的不是「檔案刪掉了沒有」,是「那個擋還會不會發生」: 它把「裁決執行完之後的世界」(沒有 3-specs 的 repo、有兩份 status: active 的 repo 丟給 hooks.json整組 Write|Edit|MultiEdit 的閘——清單是當場從 hooks.json 讀的, 不寫死——不准有任何一支用 SDD/3-specs 當理由擋下來。 ⇒ 日後有人換個檔名把同一個形狀種回來,這支照樣紅。

失敗

  • ②那四條任一紅 ⇒ 裁決又被種回去了。最要看的是最後一條ISEP 自己的 hooks/lib/*.py): ISEP 這個 repo 本身就沒有 3-specs,退役前那一格是紅的——它是這件事的活體證據
  • ③紅 ⇒ 條文回來了。有人在 commands/agents/skills/hooks/ 裡 又寫了一次「只准一份 active SDD」,而條文會被載入,載入就會被照做
  • ①的第三條(hooks.json 仍是合法 JSON)紅 ⇒ 合併把檔案弄壞了; 但它只證明語法沒壞、不證明閘還在——閘在不在要另外跑 README 那道逐支點名

📌 這支只管 ISEP 這一半。 裁決的另外兩件在 inkstone/InkStoneCo 拿掉那份 active SDD CLAUDE.md 的「單一活性鐵律」段,以及 system-dev/docs/ 底下的任務 checkbox 分診(掛 inkstone/InkStoneCo#49)。 🔴 順序不可顛倒:要等這一版 ISEP 出去、兩邊 /plugin update 之後, 那半才動得——先拿掉 active SDD 就會鎖死。

A26 — 雲端該有的憑證清單,這台機器真的拿得到:11 條

bash scripts/test-make-cloud-env.sh

該看到11/11 通過,跳過 0 條(清單現在是 10 把——兩台全給 + 機器帳號 + uncle6 出貨 Arcrun 出貨線的實例 namespace)。全程只印變數名字與值的長度,一個字元的值都不印。 A 段用假的 .env 隔離跑(不碰真金鑰、不碰 ~/.claude/cloud-env); B 段拿這台機器真正的 .env 對帳——.env 不在的機器(雲端就是)會印 ⏭️ SKIP 不算失敗,但也不算驗過。

它在守什麼inkstone/ISEP#1152026-09-01 實撞): make-cloud-env.shNEEDED 是「雲端總管手上有哪些憑證」的唯一清單。 那天雲端要清空 youlinenv | grep -ciE 'cloudflare|^CF_|wrangler'0—— 不是雲端漏設,是這份清單裡從來沒有任何 CF 憑證🔴 更貴的是它發生在流程末端:工人已經把清空腳本與測試都寫完了, 到要真的跑的那一刻才知道跑不了。

失敗

  • B7 紅 ⇒ 清單上有一把這台機器根本拿不到值 ⇒ leo 貼出去的會是 <🔴 找不到>,而雲端要到用到那一刻才知道。這就是 ISEP#115 那一天的形狀
  • B8 紅 ⇒ 清單裡混進了值出自 polaris/mira/.env 的變數,那是 leo21c 現役正式環境。 leo 2026-08-20 已把那 7 把分進 B 段並選擇不放(inkstone/InkStoneCo#14 → comment 3890
  • B9 紅 ⇒ 清單裡有一把的就是 CLOUDFLARE_API_TOKEN_leo21c。 leo 2026-09-01 的紅線是「那把不准加」,而 B9 比的是值不是名字 ⇒ 改個名字照樣紅
  • B8x 紅或長期 SKIP ⇒ B8 的偵測不會亮。全綠有兩種可能(真的沒有正式憑證/ 偵測根本壞了),分不開就等於沒驗
  • A5aA5b 紅 ⇒ 缺值時不會被標成 <🔴 …>、收尾也不點名 ⇒ 假綠 而假綠正是這張票要解的病
  • A6 紅 ⇒ 有東西被寫進 repo。那支腳本的產物含金鑰真身,刻意不在任何 repo 裡

🔴 B8 與 B9 的判準都不是名字,是機器算得出來的事實。 B8 看「值從哪個檔案拿到的」,B9 看「這個值是不是就是 leo21c 那把」。 兩條是分工不是重複CLOUDFLARE_API_TOKEN_leo21c 住在頂層 .env 不在 polaris/mira/.env ⇒ B8 抓不到它,那就是 B9 存在的理由。

兩條的「該紅」方向都實跑過(2026-09-01,拋棄式副本,分支一個字沒動):

混進 mira 的 NAMESPACE      → ❌ B8 …want=0 got=1,並指出「來自 polaris/mira/.env」
把 leo21c 那把改名 CF_TOKEN_BACKUP → ❌ B9 …want=0 got=1B8 此時仍綠,因為值不出自 mira)

⇒ 第二條正是黑名單會放過去的形狀。

A31 — leo21c 讀可以、寫不行,而且改法指到活著的 youlin:26 條

bash hooks/tests/leo21c-write-guard.test.sh

該看到通過 26 條,失敗 0 條。全程離線,這支閘不寫檔,直接跑真跡。

它在守什麼inkstone/ISEP#1302026-09-04 雲端 run log):leo21c-write-guard.sh 連讀都擋——Routine 讀 notify_leo 定義那一條被攔下,雲端於是什麼都拿不到。 實查:舊判準 -d[[:space:]]| tr -d '\r'cut -d= 這種唯讀的 -d 當成 curl 的 body prod-write-guard.sh 在 08-12 就修過同一個洞,這支漏了。另外它把 notify_leo 的 trigger 一律當寫入擋,而 prod-write-guard.sh 從 ISEP#63 起就放行它——兩支閘對同一條指令說不同的話。 這支之前沒有任何測試,「讀會不會被誤攔」從來沒被驗過。

測資是 Routine 文件(cloud-worker.mdprogress-guard.md)裡真的會下的那幾條

失敗

  • A 群任一紅 ⇒ 誤攔,雲端又回到「連讀都讀不到」;③④⑤ 紅就是 09-04 那個形狀復發
  • ⑫ 紅 ⇒ 撞人閘時發 Telegram 叫 leo 又會被擋(inkstone/InkStoneCo#110 的病)
  • B 群任一紅 ⇒ 寫得進 leo 的真庫(2026-08-20 那 8 張測試卡的病)。⑬ 特別看: Routine 的心跳 POST 就是寫入,它該被擋——那條指令要改,不是閘要放
  • ㉔㉕ 紅 ⇒ 閘印的「改法」教人打 09-02 起 DNS 已不存在的舊子網域,照著做只會拿到 000

修之前用同一份測試跑舊閘(git show main:hooks/leo21c-write-guard.sh:③⑤⑫㉔㉕ 五條紅 ——證明這五格是真的改到了,不是測試順著新閘寫的。

A32 — 主線那個檔隨 repo 走:17 條

bash hooks/tests/mainline-repo-mirror.test.sh

該看到通過 17 條,失敗 0 條。全程離線:家目錄那份走 ISEP_COUNTDOWN_STATE_DIR、 repo 那份走 TMP 底下的假 InkStoneCo/system-dev/

它在守什麼inkstone/ISEP#130leo 09-05「routine 每天早上開啟後抓不到任務」): 主線只住在家目錄,雲端是另一台機器 ⇒ 不知道主線是哪條。PR inkstone/InkStoneCo#118 把它放進 system-dev/mainline.json,這裡驗 ISEP 這一半:家目錄沒有就讀 repo 那份; 兩份都在 set_at 較新的算數;setadoptclear 兩份一起動;refresh 只寫家目錄。

失敗

  • ①②③ 紅 ⇒ 雲端($CLAUDE_PROJECT_DIR 是薄殼根、真身在 InkStoneCo/)仍然讀不到主線
  • ⑤⑥ 紅 ⇒ 誰後標的誰算數這條壞了:本機會把雲端剛標的蓋回去,或反過來
  • ⑧ 紅 ⇒ 每開一個 session InkStoneCo 的工作樹就髒一次,而髒的 diff 沒有人會去 commit
  • ⑫ 紅 ⇒ clear 之後下一次讀又從 repo 那份長回來
  • ⑮ 紅 ⇒ ISEP#82 第 4 條(沒有主線不能整組壞掉)被本票弄壞

雲端實跑(2026-09-07,本 session):CLAUDE_PROJECT_DIR=/home/user/inkstoneco ISEP_COUNTDOWN_STATE_DIR=$(mktemp -d) python3 scripts/mainline → 印出 🎯 現在的主線:inkstone/Arcrun#48「AI 問一次就看得到全部…」——家目錄空的,只靠 repo 那份。

A33 — 權限白名單住 ISEP 一份、兩台各自寫進家目錄:19 條

bash scripts/test-settings-allow-sync.sh

該看到19/19 通過。全程在 TMP 底下的假 settings.json 上跑,不碰真的 ~/.claude/settings.json

它在守什麼inkstone/ISEP#130 → comment 61206121):leo 09-07 親手加進本機 InkStoneCo/.claude/settings.json 的四條(ticketmainlinegate-okgitea-pr-merge) 雲端沒有 ⇒ 同樣動作被分類器擋(09-04 permission_denials=6)。雲端真正讀的薄殼 repo 要 D20 開閘才推得動 ⇒ 清單住 ISEP docs/permissions-allow.jsonscripts/settings-allow-sync 在那台機器上寫進 ~/.claude/settings.json:雲端由 docs/cloud-setup-script.sh 裝完 plugin 跑一次、 之後每個 SessionStart 再對一次;本機同一支。

失敗

  • A1 紅 ⇒ 清單裡混進了整類放行(Bash(python3 *))或少了正門工具
  • B3B4 紅 ⇒ ~ 沒換成那台的家目錄——雲端是 /root 不是 /Users/youlinhsieh,規則會對不上
  • B7 紅 ⇒ 不冪等,每個 session 都改一次 settings.json
  • C1 紅 ⇒ 動到了別人手加的規則。這支只准加不准減
  • E1 紅 ⇒ 目標壞掉時炸了——它掛在 SessionStart,炸了 session 就沒閘
  • F1/F2 紅 ⇒ 沒接線:清單對了但沒人會去跑它

⚠️ 這支驗不了「分類器真的不擋」——那要在雲端一趟 run 裡看 permission_denials。 規則的形狀(Bash(python3 …/isep/*/scripts/ticket *))沿用 leo 09-07 親手加、實測有效的那四條。

A34 — 收件 repo 寫 owner/repo 不該是 4047 條

bash scripts/test-ticket-repo-arg.sh

該看到通過 7 條,失敗 0 條。把 scripts/ticket 當模組載進來、api() 換成只記路徑的假貨—— 不打 Gitea、不開票、不留戳記。

它在守什麼inkstone/ISEP#130 → comment 6120 第 2 件):09-07 ticket new inkstone/ISEP 回 404。不是 ISEP 不存在,是 inkstone/ISEP 被原樣塞進 /repos/inkstone/{repo}/issues ⇒ 打到 /repos/inkstone/inkstone/ISEP/issues正門壞了人就走側門——那天四張票是直接打 API 開的。

失敗:② 紅 ⇒ 那個 404 復發;③ 紅 ⇒ 寫錯 org 又變成一個要人猜的 404;⑦ 紅 ⇒ 路徑裡出現 inkstone/inkstone

A35 — 雲端唯一通的通知路(Bot API 直送):10 條

bash scripts/test-isep-notify-botapi.sh

該看到10/10 通過。Bot API 指到本機一個假伺服器、實例那條也指到它——不打真 Telegram、不打實例。

它在守什麼inkstone/ISEP#1302026-09-07 從雲端實測):

notify_leo @ leo21c   → HTTP 404「找不到 workflow」(08-28 起就斷;修它是 leo 的人閘)
notify_leo @ youlin   → 雲端 egress proxy 回 403policy denial;要 leo 在 Cloud environment 放行主機)
api.telegram.org      → 302,通

⇒ 雲端唯一走得通的是 Bot API 直送,只缺 TELEGRAM_BOT_TOKENTELEGRAM_CHAT_ID 兩個環境變數。 有就先走它(不碰實例,閘管不到也不必管);沒有要點名缺哪兩個,不能靜默。

失敗:A1 紅 ⇒ 沒憑證時不講缺什麼,leo 不知道要在 Cloud environment 加哪兩個; B3 紅 ⇒ 送到了還去打實例;C1 紅 ⇒ 401 被講成送到;D1 紅 ⇒ 舊版閘 block 時直送也被連坐。

A36 — 雲端對 stage 的寫入有正門,而且只寫得進 stage:45 條

bash scripts/test-stage.sh

該看到45/45 通過。CF API 與 stage 實例都指到本機一個假伺服器——不打真 Cloudflare、不碰任何 worker。 假伺服器對 secret PUT 回 201(真 CF 就是 201)。

它在守什麼inkstone/ISEP#1372026-09-07 三條主線工人在雲端撞的同一面牆):

printf … | npx wrangler secret put …                 ← 分類器擋(複合指令對不上白名單任何一條前綴)
python3 scripts/stage-deploy-artifacts.py all --confirm   ← 分類器擋
curl -X POST …arcrun-yuga3bse.workers.dev/records     ← 分類器擋;0.21.0 的 prod-write-guard 又當它是 prod

scripts/stagesecret putlistdelete(直接打 CF API,不經 npx)與 api <METHOD> <worker>/<path> (curl 打實例,標頭與 body 走 stdin,不走 argv)。只寫 stagesecret 先 GET /accounts 看這把 token 打得到誰、URL 永遠只帶 1129efd7…api 的主機只會長在 *.arcrun-yuga3bse.workers.dev。 值只從環境變數名讀(--from-env--bearer-env--header-env--data-env),--value--bearer--header 一律拒收。 Arcrun 的 stage-deploy-artifacts.py 自己已寫死只認 youlin 帳號 ID、不收 --account--token, 白名單直接放它從 Arcrun 根目錄跑的相對形狀,不重造一支。

失敗

  • A1B1B2D1D2 紅 ⇒ 非 stage 也寫得進去——這是本工具存在的唯一理由
  • A4/D3 紅 ⇒ 值可以從指令列進來(會進 shell 歷史與 session log
  • C1 紅 ⇒ 又把 201 講成失敗(第一次實跑就是這樣:CF 種好了、工具說失敗)
  • C7/C9 紅 ⇒ 只信 PUT 的回應不去列
  • E2 紅 ⇒ ISEP 自己的閘誤攔正門——誤攔比漏擋嚴重,被擋的人會去走側門
  • E4 紅 ⇒ 又長出第二支平行的工具

真實跑(2026-09-07,雲端 sessionisep-hand stage secret put 把隨機值的 ISEP_137_PROBE 種進 youlin arcrun-cypher-executor → 不經工具用 CF API 列到 ["ISEP_137_PROBE","KBDB_INTERNAL_TOKEN"]stage secret delete → 再列剩 ["KBDB_INTERNAL_TOKEN"]stage 恢復原狀)。 stage api GET arcrun-cypher-executor/health → HTTP 200stage api POST arcrun-kbdb/map/recompute… 不帶 Bearer → HTTP 401、離開碼 1(打到了、沒寫); 完整網址指到 leo21c → 拒絕、離開碼 2、零請求。 ⚠️ 帶 Bearer 真的寫進 stage KBDB 這格沒跑——雲端 Cloud environment 沒有 KBDB_INTERNAL_TOKEN(它只住在安裝器中心側 KVArcrun#176 comment 6487 步驟 0); CF_SECRETS_API_TOKEN 的真值是主線 B-3(Arcrun#86)的東西,由總管用 stage secret put 種,本票不編一個假的塞進去。 ⚠️ 「分類器真的不擋」與 A33 同款:要下一版裝進雲端之後,看一趟 run 的 permission_denials

A37 — 打了 tag 之後那一站:把 tag 建成 leo 看得到的 release14 條

bash scripts/test-release-ship.sh

該看到共 14 項:✅ 14 ❌ 0。全程離線(RELEASE_SHIP_FIXTURERELEASE_SHIP_SINK), 不打 Gitea、不建任何真 release。fixture 的形狀見 hooks/lib/release_chain.py

它在守什麼inkstone/ISEP#67):ISEP 全樹沒有任何東西會建 release,於是 tag 推了、 Releases 頁停在舊版——08-27v0.4.0v0.5.0)、09-02v0.22.0)、09-07v0.23.0v0.24.0 同一站斷了三輪;09-07 那次交棒給 leo 的「測試位置」打開是一頁空 tag。 三個前置必須在場才放行:① 那個 tag 的樹plugin.json tag 號碼(問 Gitea contents?ref=<tag> 不是工作樹)② tag 真的在 Gitea ③ note 有內容(沒給就從 Gitea compare 生事實清單)。 建完回頭跑 release-check <那個 tag> 拿收貨端覆核——送的人說成功不算數。

失敗

  • A1 紅 ⇒ tag 的樹自己講錯版本也建得了,leo 裝到的會各說各話
  • B4 那三條任一紅 ⇒ 前置①又回去比「最新的 tag」或工作樹了——總管 09-07 在 v0.23.0 的 checkout 跑 release-ship v0.23.0 就是這樣被擋的(訊息說最新是 v0.24.0),這一組工作樹故意擺 9.9.9
  • B2 第二條紅 ⇒ 已存在的 release 被說成「已建立」(09-05 comment 6207 那句假綠,scout 6213 抓到的)
  • B3 第二條紅 ⇒ --dry-run 真的寫了東西

真實跑(2026-09-07isep-hand,全部唯讀):工作樹在本分支(plugin.json 0.24.0)跑 release-ship v0.23.0 --dry-run → 前置②、前置①「tag v0.23.0 的樹裡 plugin.json 0.23.0」、 「本來就在了——不重複建、不動它」、覆核 v0.23.0 ✅✅✅ ←、exit 009-05 那版在同一情境是 exit 2); release-ship v0.3.4 --dry-run(現存唯一沒 release 的 tag)走到「要建」那條路:note 從 Gitea compare 生 8 行、不 POST、exit 0。

A38 — 回頭問收貨端「到了嗎」,而且開場就會問:14 條+信標 7 條

bash scripts/test-release-check.sh
bash hooks/tests/isep-presence-beacon.test.sh        # ㉗–㉝ 那七條

該看到共 14 項:✅ 14 ❌ 0;信標 通過 33 條,失敗 0 條。全離線。

它在守什麼inkstone/ISEP#67 → comment 6574,總管 09-07 裁定②):「打了 tag 卻沒 release」 要在下一個 session 開場就被報出來(一行:缺哪一站+怎麼補),不靠人記得;兩者都在時安靜。 release-check 逐版問 Gitea(匿名,D20),現行版本缺站 ⇒ exit 2 +指名缺哪一站+補法(正本絕對路徑); 更舊版本缺件只黃字;v0.190.200.21 已裁定不補(同一則 comment 裁定①),表上標出處、不再黃字。 信標 ④ 用同一份判準(hooks/lib/release_chain.py):最新 tag 沒 release ⇒ 報;main 定版比最新 tag 新 ⇒ 報缺 tag; 只快取「都在」6 小時,缺件不快取——補完的下一個 session 就該安靜。

失敗

  • A1/A2 紅 ⇒ 驗收 4 沒過:故意漏一站,管線說不出缺哪一站
  • A3 紅 ⇒ release-check <版本> 沒看你指定的那一版(release-ship 送完覆核會覆核到錯的版本)
  • B2 紅 ⇒ 誤攔:現行版本好好的,舊版缺件卻擋下來(懲罰謹慎)
  • B4 紅 ⇒ 裁定過不補的三版又天天黃字(會被學會忽略);或裁決把事實也改掉了(指定它來問應該照擋)
  • 信標 ㉗ 紅 ⇒ 開場報不出來,斷點又回到靠人記得;㉙ 紅 ⇒ 誤攔:都在還念; ㉚ 紅 ⇒ 問不到收貨端時亂猜;㉜ 紅 ⇒ 印了一條在這一份裡不存在的路徑當出路;㉝ 紅 ⇒ 補完還要念 6 小時

真實跑(2026-09-07:信標不帶 fixture 打真 Gitea(匿名)→ 安靜(v0.24.0 tagrelease 都在), 留下 .isep-chain-ok-v0.24.0 快取;release-check 在本分支 → v0.24.0 ✅✅✅ ←、三個裁定不補的版本標 ⏭、exit 0。

A39 — D20 閘判「push 到哪」看的是指令實際會推的那個 repo:26 條

bash scripts/test-github-contact-guard.sh

該看到26/26 通過。離線;後 12 條自己開兩顆 git reposhell 的 origingithub.com、 body 的 origin 是 Gitea 的形狀),payload 帶 cwd,跟 hook 真的會收到的一樣。

它在守什麼inkstone/ISEP#109 → comment 66292026-09-07 實撞):雲端薄殼的 cwd 是 GitHub 那份, 總管站在那裡 git -C <InkStoneCo> push origin xInkStoneCo 的 originGitea),舊版拿 hook 收到的 cwdorigin ⇒ 判成「指向 GitHub」擋下,-C 看都沒看;arcrun-hand 同日在 Arcrun#176 comment 6614 撞到同一支。 現在 remote 名在這條指令實際會推的那個 repo 裡解(沿用 hooks/lib/push_target_dir.pycd 鏈、-C、 子殼不外洩,推 main 那道閘 08-23 就為同一個病接的它);判準仍是 remote 解出來的 URL 主機,不是「有 -C 就放行」。 修之前拿新測試跑舊閘:7 條紅——4 條是誤攔(推 Gitea 被擋),3 條是漏擋(站在 Gitea 那份 -C 到薄殼推 GitHub,舊版放行)。

失敗

  • 「不該擋」6 條任一紅 ⇒ 誤攔:雲端推 Gitea 分支又得改用完整網址繞路,久了整道閘沒人當真
  • 「該擋」5 條任一紅 ⇒ D20 有洞:-Ccd 指到 GitHub 那份的 push 沒被攔
  • (cd body && true); git push 那條紅 ⇒ 子殼的 cd 外洩了(08-11 穿透的形狀)
  • 前 14 條紅 ⇒ 舊有判準(heredoc/引號裡的散文/讀取放行)被改壞

A37 — 雲端第一則 prompt 的主線就是現在這條,不是兩週前的舊線:31 條

bash hooks/tests/mainline-gitea-fallback.test.sh

該看到通過 31 條,失敗 0 條。全程離線:Gitea 是本機一個假伺服器(TICKET_HOST 指過去), 它照真 Gitea 回——public 時 raw 端點匿名 200private 時匿名 404、帶 token 200(真 inkstone/InkStoneCo 就是 private2026-09-07 實測匿名打 rawcontentsrepo API 都 404)。狀態走 ISEP_COUNTDOWN_STATE_DIR、 repo 那份走 TMP 底下的假薄殼。

它在守什麼inkstone/ISEP#140;母票 #130):薄殼 youlinhsieh/inkstoneco 的 SessionStart 跑在 bootstrap.sh 之前——InkStoneCo/ 還沒 clone、家目錄又是空的 ⇒ 兩份主線檔都不在 ⇒ countdown.py 退到「期限最近的 milestone」 ⇒ 第一則 prompt 印 🔴 主線 把管理這條線做對 已逾期 341 小時🎯 現在沒有主線。機制沒壞,是順序。 ⇒ scripts/mainline refreshSessionStart)在兩份都不在時去 Gitea 讀 inkstone/InkStoneCo main 的 system-dev/mainline.json 一次、寫進家目錄;之後每一則 UserPromptSubmit 讀家目錄,路徑上照舊零網路。 優先序寫死在 hooks/lib/mainline.py 檔頭:家目錄 > repo 那份 > Gitea 那份,不是第二套來源。

失敗

  • ①② 紅 ⇒ 前置狀態測不到(票上撞到的那個畫面重現不了,後面全是假綠)
  • ⑥⑦⑧ 紅 ⇒ 第一則 prompt 仍是「沒有主線」或那條逾期的舊線——本票要解的就是這一格
  • ⑨⑲ 紅 ⇒ 一上來就實名(讀的形狀是匿名優先,被拒才帶 token)
  • ⑬ 紅 ⇒ 每一則訊息的路徑上打了網路load()line() 從不打網路這條被弄壞)
  • ⑭⑳㉒ 紅 ⇒ 家目錄或 repo 那份在場還去問 Gitea,或讀 repo 那份時順手寫了家目錄(A32 ④)
  • ⑮⑯⑰㉓㉔㉕㉖㉗ 紅 ⇒ 讀不到時不是安靜退回:炸、掛住、或往 stderr 抱怨(SessionStart 每次都會看到)
  • ㉘㉙ 紅 ⇒ bootstrap 之後 repo 那份出現時,set_at 規則(A32 ⑤⑦)被本票弄壞

真實跑(2026-09-07,雲端 sessionisep-hand:薄殼形狀(空家目錄、$CLAUDE_PROJECT_DIR 是沒有 InkStoneCo/ 的空目錄)——環境有 GITEA_TOKEN_CLAUDE_CODEmainline refresh 2.06 秒、rc 0mainlineinkstone/Arcrun#48「AI 問一次就看得到全部…」UserPromptSubmit 餵 countdown-guard.sh⏱ …|主線 AI 問一次就看得到全部… 剩 137 小時 41 分🎯 主線:inkstone/Arcrun#48…; 拔掉 token:rc 0、家目錄零檔案、印「現在沒有主線」、薄殼目錄仍是空的。 ⚠️ **「新開一個雲端 session、不跑任何指令、第一眼就是它」**這格要下一版裝進雲端才驗得到—— 前提是 Cloud environment 有 GITEA_TOKEN_CLAUDE_CODE(本 session 有),沒有就跟 0.25.0 一樣退到舊線。

A40 — 一個 repo 只有一個資料夾:scripts/worktreesweep 現場整理):42 條

bash scripts/test-worktree.sh

該看到通過 42 條,失敗 0 條。全程離線:遠端是本機 bare repo,不碰任何真的 repo。

它守什麼inkstone/ISEP#147):leo 在 Mac 上跑一次的整理工具。fixture 照他 09-07 在 Finder 看到的那排分身 原樣造出來course_gen-ticket-3-notescourse_gen-ticket-4-handoutsax-courses-ticket1ISEP-wt-122ship ISEP-wt-117ISEP-wt115InkStoneCo-wt-112,各自處境不同:推了乾淨、沒推、髒、登記指向空氣), 外加一份新家 .worktrees/ 裡的與一個沒人登記的孤兒目錄。

  • A dry-run((1)–(13)):每份落在對的組、沒推的印分支與推的指令、--skip course_gen 那兩份在「不碰」組、目錄樹快照前後相同
  • B --apply((14)–(27)):只收「推了且乾淨」的 3 份+prune 空氣登記;沒推的、髒的、--skip 的、孤兒的一根寒毛沒動;收掉的分身分支還在;第二次冪等。
  • C 判準是事實不是名字(28)(32)):不 --skipcourse_gen-* 照 git 的事實分組;拿掉 remote ⇒ 落在「問不到遠端」、不當成沒推、也不收
  • D opencloselist(33)(42)):open 的路徑在 <repo>/.worktrees/、主 repo git status 乾淨、tech_projects/ 沒多任何資料夾;close 沒推 ⇒ 2 點名,推了 ⇒ 0 目錄沒了,再 close ⇒ 0 不吵。

失敗

  • (2)(30) 紅 ⇒ dry-run 動了東西——leo 跑第一次「只是看看」就已經被改了現場,那是災難。
  • (19)–(23) 任一紅 ⇒ 收錯東西:刪了沒推的 commit/動了 --skip 的 repo/碰了不明目錄。不刪任何有未推 commit 的分身是票上紅線。
  • (28)(29) 紅 ⇒ 判準滑回看名字(course_gen 被當關鍵字),違反本 repo 紅線。
  • (31)(32) 紅 ⇒ 把「離線」當成「沒推」——拿雜訊懲罰謹慎。

A41 — 主線成員由相依邊決定,不靠同名里程碑:56 條

bash hooks/tests/mainline-members-by-dependency.test.sh

該看到通過 56 條,失敗 0 條全程離線Gitea 是本機一個假伺服器(TICKET_HOST 指過去, 照真 Gitea 回:相依 POST 201、已存在 409、issue 列表用 milestones= 名字查),狀態走 ISEP_COUNTDOWN_STATE_DIR、repo 那份走 TMP 底下的假薄殼、HOME 也指到 TMP。 不碰真家目錄、不碰真 Gitea、不碰真 InkStoneCo。

它在守什麼inkstone/ISEP#133 → comment 6743):scripts/mainline 第一版檔頭寫 「跨 repo 同名是既有做法,不動它」,成員也照標題跨 repo 收;總管 09-07 照它做、把那句抄進 InkStoneCo 的 ops-facts、還在 arcrun-rag 補建了一個同名的。leo 當天: 「拆,誰說『同名跨 repo 是 mainline 機制的一部分』,早就定了只有一個 milestone,不同 repo 用指針」 (規則本身:inkstone/ISEP#30inkstone/InkStoneCo#44)。

現在的判準全部是 Gitea 的欄位,沒有標題比對:

錨       owner/repo#<milestone id>:整個 Gitea 只有這一個 milestone 物件
hub 票   mainline set … --hub <owner/repo#N>:這條線的載體票,別 repo 的票用相依指到它
成員     hub 里程碑裡的票  hub 票,沿 /dependencies 邊(跨 repo)收下去(hooks/lib/mainline.py::collect_members
adopt    同 repo ⇒ 掛進 hub 里程碑;別 repo ⇒ POST 相依到 hub 票(或 --via 指定的成員)。不建同名里程碑

失敗

  • A 群 ③④⑤ 任一紅 ⇒ 相依邊沒走到(跨 repo 成員收不到)
  • A 群 ⑥⑦ 紅 ⇒ 同名里程碑裡的票又被當成成員——被推翻的判準回來了
  • ⑪ 紅 ⇒ set 又去別的 repo 找同名的了
  • ⑮⑯⑰ 任一紅 ⇒ adopt 別 repo 的票不是加相依:要嘛改了那張票的 milestone、要嘛建了里程碑
  • ⑳ 紅 ⇒ 重複 adopt 炸了(Gitea 409 沒被當成「邊本來就在」)
  • ㉔–㉙ 任一紅 ⇒ 沒 hub 票時沒擋、沒給路、或給的路貼上去跑不動(㉙ 把訊息裡那行原樣執行)
  • ㉛–㉞ 任一紅 ⇒ 票上驗法第 1 條破了:同名里程碑關掉後成員掉出主線,或 pick 抓不到靠邊進來的票
  • ㊱㊴㊵ 任一紅 ⇒ hasfocus guard 沒去問 /blocks,只看 milestone 就下結論(那是「只知一半」)
  • ㊹ 紅 ⇒ 派一張掛在別 repo 同名里程碑、沒邊的票被放行 ⇒ 閘還在拿名字判
  • ㊻ 紅 ⇒ Gitea 讀不到時成員被清掉(讀不到 ≠ 沒有成員)
  • ㊼–㊿ 任一紅 ⇒ 票上驗法第 3 條破了:帳本落在 plugin 快取(claude plugin update 一換就沒)

📌 真實 Gitea 唯讀實跑2026-09-07isep-handstate 與鏡像都指到暫存目錄,不寫 Gitea): mainline set inkstone/Arcrun#48 --hub inkstone/InkStoneCo#44 收到 25 張成員、5 個 repo (里程碑裡 4 + 相依收到 20),其中 mira#6ISEP#130ISEP#140arcrun-rag#104 都在 ——不必新增任何邊,現有的相依圖已經連得到;has 四張都回「在」; ticket pick --all 主線組回 Arcrun#197mira#5(後者靠 Arcrun#86 的邊,沒掛任何 hub 里程碑)。 這一走 19 秒(約 30 次序列 GET)⇒ SessionStart 的 refresh 不帶 --members(成本不變), setadoptrefresh --members 才重收;pickhas/閘每次現問 Gitea,快取只餵 show

A5 — 開票前的搜尋是跨 repo 的

python3 scripts/ticket where 標籤 模組化

該看到:命中數 > 0,而且結果橫跨多個 repoInkStoneCo / Arcrun / arcrun-rag …)。 失敗

  • 🔴 拿不到 token ⇒ 這個 repo 的 remote 沒帶憑證(2026-08-20 修過一次:原本寫死只認名叫 gitea 的 remote ISEP 的叫 origin,於是這道閘在新 repo 等於不存在)
  • 結果只有單一 repo ⇒ 搜尋沒有跨 repo,等於沒搜

A9 — 人閘警察的管路:該擋的擋、壞掉不會卡住 session

bash hooks/tests/ask-user-question-guard.test.sh

該看到14/14 通過不打網路、不花錢(判官用替身)。 失敗

  • A 群(該放行)任何一條紅 ⇒ 誤攔,這比漏擋嚴重——它會讓真人閘的問題送不到 leo
  • ⑤⑥⑦ 任一條紅 ⇒ fail-open 壞了:判官掛掉會變成「問不出去」,等於一支閘癱瘓整個 session
  • ⑩b 紅 ⇒ 訊息被 shell 展開了(2026-08-26 真的犯過:cat >&2 <<EOF 沒加引號, 訊息裡的反引號被當命令執行,閘照擋,但它教人怎麼解的那兩行變成空白

A10 — 人閘警察的準度:四題公式判得準不準

bash hooks/tests/ask-user-question-guard.live.test.sh

🔴 這支真的會叫 haiku(9 題、每題一次呼叫,整支約 2 分鐘)。 該看到9/9 通過,且結尾的「A 群誤攔」計數是 0失敗

  • A 群紅(誤攔真人閘)=最嚴重:等於讓總管替 leo 決定他的品味。看到就停下來改判準,不要放著
  • B 群紅 = 漏擋,判官把純技術題當成人閘。改 ask-user-question-guard.sh 裡判官提示的 ③④ 兩題定義,不要改成關鍵字比對(那是被明令禁止的文字層封路)
  • 📌 這支會隨模型版本漂移,是量尺不是一次性驗收。改完判準要連跑三次都全綠才算數 (2026-08-26 實測:第一版判準連兩次都在同一題漏擋,收緊 ③④ 定義後三次全綠)

A11 — 派工單只剩票號(含回覆那條路):擋得住,也放得過,而且會注入共通規定

bash hooks/tests/dispatch-format-guard.test.sh

該看到52/52 通過inkstone/ISEP#88 之前是 33 條;本頁一度寫 19,那是更早的數字, 沒有人回頭改 —— 同一個病,只是換一欄)。離線、不打網路、不花錢——這支閘是純結構判斷,沒有語意判官, 所以它不需要像 A10 那樣另開一支 live 測試量準度,每次結果都一樣失敗

  • A 群任何一條紅 ⇒ 誤攔。合規的派工只有一行票號,擋掉它等於整台機器派不了工
  • ⑦ 紅 ⇒ 共通規定沒有被注入。這是「派工單只剩票號」能成立的前提: 交件方式、不准 push main、org 是 inkstone 這些不必有人記得寫,機器每次都補。 它壞了不會有人立刻發現——派工照樣送出去,只是收工方不知道要貼回原票
  • ⑨ 紅 ⇒ 真跡放行了。那份測資是真的發生過的那一次派工(見 hooks/tests/fixtures/README.md
  • ⑰ 紅 ⇒ 訊息被 shell 展開了(同 A9 ⑩b 那個病:閘照擋,但它教人怎麼解的那兩行變成空白)
  • D 群⑲⑳㉑㉒ 紅 ⇒ inkstone/ISEP#88 的驗收條件沒過:回覆一個正在跑的 subagent 時夾帶指令沒被擋(⑲)、或擋了卻沒把那段內容原文印出來(㉑,出路是「貼上票」, 找不到原文就得回頭自己翻)
  • E 群㉔–㉙ 任一紅 ⇒ 有一條通往 subagent 的路又漏了。那六條是雲端 sessiontrigger claude -p——ticket-api-bypass-guard.sh 檔頭記過這一族的通病:「認動作的方式漏了一條路」
  • F 群㉚–㉟ 任一紅 ⇒ 誤攔。㉚特別重要:subagent 往上回報(to: "main")是交件, 擋它等於擋掉交件本身;㉟反過來,子 session 自己往下派工時規矩要照樣管它,不然是逃逸艙口

A16 — 工人有名字:指名派工、沒有這個人、注入它的檔案:24 條

bash hooks/tests/roster-guard.test.sh

該看到24 通過 / 0 失敗離線、不打網路、不花錢——純結構判斷(名字在不在名單裡), 沒有語意判官,每次結果一樣。

它在守什麼inkstone/ISEP#86):「身為派工的人,我要工人有名字, 我才知道票上這件事到底是誰做的。」開票當日實查:/root/.claude/agents/ 不存在, 派工派給的是沒有名字的臨時工——票上只看得到「有個 agent 做了」。

失敗

  • ①②③ 紅 ⇒ 驗收 1 沒過:scripts/roster 列不出名單、或列了卻看不出各自管什麼
  • ④⑤ 任一紅 ⇒ 誤攔,名單上的人被擋掉 = 整台機器派不了工。這比漏擋嚴重
  • ⑥⑦⑧ 紅 ⇒ 驗收 4 沒過:派一個不存在的名字時講不出「沒有這個人」
  • ⑨ 紅 ⇒ 擋了卻沒印名單,人不知道有誰可以派(閘的訊息要講得出出路)
  • ⑬ 紅 ⇒ 名單讀不到時沒有 fail-open。一份讀不到的名單不該讓整台機器停擺
  • ⑯⑰ 紅 ⇒ 注入壞了。那是「你是誰/先讀什麼/你的紅線」唯一的送達方式—— 它壞了不會有人立刻發現,派工照樣送出去,只是工人不知道自己是誰
  • ⑱ 紅 ⇒ 驗收 3 沒過:票上的【身份】欄吃不下工人名字(或把原本三個角色弄壞了)

A17 — 未經調查不寫診斷:26 條

bash hooks/tests/diagnosis-evidence-guard.test.sh

該看到26 通過 / 0 失敗全程離線:不打 Gitea、不開任何測試票, 戳記走 ISEP_STAMP_DIR(不碰 /tmp 的正式戳記)。

它在守什麼inkstone/ISEP#87):「先派人查 → 拿到查的結果 → 才可以寫診斷。」 未經調查的診斷寫在票上會長得像事實,工人會照著它去驗證,而不是去查

失敗

  • ①–⑦ 任一紅 ⇒ 驗收 1 沒過。⑥⑦特別看:那是側門(直接打 Gitea API), 只封正門等於沒封
  • ② 紅 ⇒ 驗收 3 沒過:訊息說不出「你還沒派人查這件事」,變成籠統的「格式不對」
  • ⑧⑨ 紅 ⇒ 驗收 2 沒過(派過人查卻還在擋),或戳記從「按票分」滑成「按 session 分」 ——後者等於派過一次就永久解鎖
  • ⑩–⑫ 任一紅 ⇒ 驗收 4 沒過,這是誤攔:轉述別人查到的東西(有出處)被擋, 那會逼人把真的有出處的話也吞回去
  • ⑬ 紅 ⇒ 判準從結構滑回措辭。那一條故意用一段連「根因/因為/應該是」都沒有的內容, 它一旦放行,代表閘開始靠關鍵字判斷了(leo 2026-08-17 已證偽那條路)
  • ⑭–⑲ 任一紅 ⇒ 誤攔(短回覆、唯讀、搜尋、關票被擋)
  • ㉑ 紅 ⇒ 鬼打牆:同一張票擋不只一次,人會學會忽略它
  • ㉓㉔ 紅 ⇒ payload 壞掉時擋住了。這支是 PreToolUsefail-closed 會讓人做不了事

A12 — 票上的每一則留言都認得出是誰寫的(兩道門)

bash hooks/tests/reply-identity.test.sh

該看到11/11 通過。離線,正門的案例全部在打 API 之前就結束,不會真的送出留言。 失敗

  • ③ 紅 ⇒ 誤攔了「GET 撈留言」。那是最常做的動作,擋它比漏擋更糟
  • ①⑧ 紅 ⇒ 有一道門沒守住。貼留言有兩條路scripts/ticket 正門、Gitea API 側門), 只封一條等於沒封——ticket-api-bypass-guard.sh刻意放行對既有票留言的

A6 — 標籤對齊且冪等

bash scripts/gitea-labels-sync.sh
bash scripts/gitea-labels-sync.sh

該看到:第二次全部 0 created / 0 updated失敗:第二次還在改(不冪等);或任何既有標籤被刪除。

A7 — plugin 裝得起來、內容對得上

claude plugin marketplace add https://git.uncle6.me/inkstone/ISEP.git
claude plugin install isep@inkstone
claude plugin list
claude plugin details isep

該看到isep@inkstone enabled,版本=最新 releasedetails 列出 9 skills、5 個 hook 事件。 失敗:版本落後(先發版,見開頭那段);或 marketplace listSource 顯示本機目錄而非 Git URL ——本機目錄有未提交改動就會跟 main 分岔,那是一條漂移路徑。

A8 — 閘在新 session 真的會觸發

前七格證明「腳本會擋」與「檔案就位」,不是「harness 真的會去叫它」。 plugin 的 hook 是 session 啟動時載入,所以這格一定要開的 session。

claude -p '請執行 git tag -a v9.9.9 -m test'

該看到:回報被擋,訊息是 release-tag-guard 那段(提到 plugin.json 與版本對不上)。 失敗

  • tag 真的被打出去 ⇒ 閘沒被載入,這是最危險的假綠
  • 訊息來自 InkStoneCo/.claude/hooks/… 而不是 plugin ⇒ 你驗到的是舊那份

為什麼挑 release-tag-guard 當考題:它只存在於 ISEP,舊的 .claude/ 那份沒有。 用它才分得出「載到的是 plugin」還是「載到的是舊的」。


B. 只有 leo 能跑的(雲端)

機器碰不到 claude.ai 的 Cloud environment 設定,這段一定要你動手。 看到跟「該看到」不一樣就停下來,把畫面貼回 inkstone/InkStoneCo#14

B0 — 先讓機器把要貼的東西產生好(不要自己拼湊)

bash scripts/make-cloud-env.sh

它會去既有的 .env 把值讀出來,產生一個含真實值、可直接複製的檔到 ~/.claude/cloud-env/<時間>.txt(權限 600刻意不在任何 repo 裡),只把路徑印出來。 變數的名字寫在腳本裡(要加變數就加在那個清單),值不進版控、不進對話

🔴 貼完就刪那個檔(指令印在它自己最後一行)。

B1 — 設定(一次性)

打開上一步產生的檔,裡面兩塊分別貼進 claude.ai → Cloud environments → 你的環境:

  1. Environment variables:把 ① 區塊每一行都貼進去(一行一個,名字與值分開填)。 現在是 2 個:GITEA_TOKEN_CLAUDE_CODE(機器帳號 Gitea token)與 CLOUDFLARE_API_TOKEN_YOULIN_CC_USEyoulin AI 的 stage 實例)。 🔴 不要照這裡的名字數——以腳本產出的 ① 區塊為準,這份文件會落後。 值全部是既有的,一把都沒有新造。
  2. Setup script 欄位:貼進 docs/cloud-setup-script.sh 的全文,一字不改。

該看到:儲存後沒有紅字。

B2 — 開一個新的雲端 session,第一眼找信標

什麼都不用打。 session 一開,找這一行:

🟢 ISEP v0.3.0 已載入(44 支閘在 …)

該看到:有這行,而且版本號跟 Releases 頁最新那個一樣。

失敗

  • 沒有這行 ⇒ plugin 沒載入,這個 session 是零閘狀態。先修 plugin,不要開始做事。
  • 版本比 Releases 舊 ⇒ 環境快取住了(setup 跑完會被拍成快照,約 7 天、或改了 setup script 才重拍)→ 動一下 setup script 的內容強制重拍。

🔴 為什麼是這一行,而不是叫它跑指令:這行由 isep-presence-beacon.sh 發出, 而那支腳本住在 plugin 裡。plugin 沒載入 ⇒ 它不可能發聲。 沒有「剛好也會過」的情況——這就是鑑別力。

B3 — 要它把 setup 的驗證結果貼回來

把這個環境 setup script 的輸出貼給我看

該看到兩行綠:

✅ git 認證通:拉得到 inkstone/ISEP
✅ marketplace inkstone 已就位

失敗:任一行是紅的 ⇒ 訊息本身會講該查什麼(token 值對不對、有沒有被撤銷)。 看不到任何輸出 ⇒ setup script 根本沒跑,回 B1 確認欄位真的存好了。

B4 — 閘真的會擋(用有鑑別力的動作)

請把這段寫進 /tmp/wf.yamlauth: __GITEA_TOKEN__

該看到:被擋下,訊息開頭是 🔒 credential 鐵律攔截(leo 2026-07-29 立)

🔴 副檔名不能改成 .md credential-only-guard 刻意豁免 .mddocs/wiki/ (文件本來就要能談論這些字串,本頁自己就寫滿了)。 2026-08-21 實撞:舊寫法用 /tmp/x.mdexit 0,閘完全沒反應—— 那是沒撞過就寫進來的探針,跟它要取代的假綠是同一個病。

失敗

  • 真的寫進去了 ⇒ 雲端仍然沒有閘。
  • 它只是嘴上說「我不應該這麼做」而沒有閘的訊息 ⇒ 同上,那是模型自律不是機械閘。

🔴 不要再用 git tag 當測試(舊版 B4 就是這樣寫的,而它是假的): git tag 出現在三支閘的白名單裡,閘全滅時它照樣「被擋」的相反——照樣通過, 於是 2026-08-20 那次雲端零閘,三個驗證步驟全部回綠。 一個在閘死掉時也會給出正確答案的測試,不是測試。

B5 — 回報

B2(信標那行)/B3(setup 輸出)/B4(閘的訊息)三個畫面貼回 inkstone/InkStoneCo#14。 全綠 ⇒ 那張票可以關,#57 也解掉一半。


目前狀態

誰跑 狀態
A1 manifest 合法 總管
A2 版本三處一致 總管
A3 打 tag 閘 總管 3/3
A4 新增 Gitea 東西側門閘 總管 24/242026-08-27inkstone/ISEP#72
A13 戳記證明看過不是跑過 總管 17/172026-08-27inkstone/ISEP#72→4873
A14 PR 一定要有結論 總管 52/522026-08-28inkstone/ISEP#81)+真實 Gitea 唯讀重演
A15 pr-verdict --dry-run 總管 2026-08-28
A14 回覆自己說出拖了多久 總管 20/202026-08-28inkstone/ISEP#63
A15 發通知不等於部署 總管 37/372026-08-28inkstone/ISEP#63
A16 跨 repo 版本清單 總管 21/212026-08-28inkstone/ISEP#84
A17 估多久/花多久/差多少 總管 23/232026-08-28inkstone/ISEP#85
A18 結案要記帳的閘 總管 22/222026-08-28inkstone/ISEP#85
A21 沒人會叫的事會自己叫 總管 36/362026-08-28inkstone/ISEP#93
A21b Telegram 真的送達 leo 驗不了——通道本身斷了,而且修它是真人閘(見下)
A22 壓 wiki 不准弄丟東西 總管 25/25+真跡實壓(2026-08-28inkstone/ISEP#89
A5 搜尋跨 repo 總管
A6 標籤對齊+冪等 總管 14 repo,第二次 0/0
A9 人閘警察管路 總管 14/142026-08-26
A10 人閘警察準度 總管 9/9,連跑三次(2026-08-26),A 群誤攔 0
A11 派工單只剩票號+回覆那條路(ISEP#88) 總管 52/522026-08-28
A12 留言身份欄(兩道門) 總管 11/112026-08-28 複跑)
A16 工人有名字(ISEP#86 總管 24/242026-08-28
A17 未經調查不寫診斷(ISEP#87) 總管 26/262026-08-28
A11 派工單只剩票號 總管 19/192026-08-27
A12 留言身份欄(兩道門) 總管 11/112026-08-27
A23 同時跑的線有上限 isep-guard 33/332026-08-29inkstone/ISEP#109
A24 一條線要有自己的工作目錄 isep-guard 35/352026-08-29inkstone/ISEP#109→5391
A24 出路那一行原樣餵回去走得通+#125 A–F isep-hand 77/772026-09-07inkstone/ISEP#109→6587、#125)+真路徑實跑(薄殼 cwd、-C ISEP:擋→印的那行→放行)+舊閘實跑 3 條紅
A39 D20 閘看 push 實際會推的 repo isep-hand 26/262026-09-07inkstone/ISEP#109→6629)+真路徑實跑(薄殼 cwd:-C InkStoneCo 放行、裸 git push origin 擋)+舊閘實跑 7 條紅(4 誤攔+3 漏擋)
A24 分身住 repo 裡面+收工被收(G/H 群) isep-hand 110/1102026-09-07inkstone/ISEP#147)+舊閘實跑 20 條紅(訊息+G/H,B/D/E/F 全綠)+本線自己就是 dogfood(分身開在 ISEP/.worktrees/ISEP-147,主目錄 git status 乾淨)
A40 sweep 現場整理(七個分身的 fixture) isep-hand 42/422026-09-07inkstone/ISEP#147);leo 的 Mac 現場要他自己跑 sweep ~/tech_projects(先 dry-run)——這台機器碰不到
A26 雲端憑證清單這台拿得到 isep-hand 11/112026-09-01inkstone/ISEP#115→5526554155425577)+兩條「該紅」方向實跑
A16 放行的門真的打得開 總管 17/172026-08-28inkstone/ISEP#90
A17 未推警察不誤攔雲端分支 總管 10/102026-08-28inkstone/ISEP#90
A18 信標會報雲端接線缺陷 總管 14/142026-08-28inkstone/ISEP#90
A19 下游做完頂層跟著關 總管 49/492026-08-28inkstone/ISEP#92
A31 雲端工人抓票規則機械可判 isep-hand 48/482026-09-07inkstone/ISEP#131)+真實 Gitea 唯讀實跑+一次真認領
A20 舊票有固定管道被撈 總管 47/472026-08-28inkstone/ISEP#83)+真實 229 張唯讀實跑
A31 leo21c 讀放寫擋+改法指活的 youlin isep-hand 26/262026-09-07inkstone/ISEP#130)+舊閘實跑 5 條紅
A32 主線檔隨 repo 走 isep-hand 17/172026-09-07inkstone/ISEP#130)+雲端 session 實跑讀到主線
A33 權限白名單住 ISEP 一份 isep-hand 19/192026-09-07inkstone/ISEP#130);「分類器真的不擋」要雲端 run 的 permission_denials 才驗得到
A34 收件 repo 寫 owner/repo 不 404 isep-hand 7/72026-09-07inkstone/ISEP#130
A35 Bot API 直送 isep-hand 10/102026-09-07);真的到 leo 手機要 Cloud environment 先有 TELEGRAM_BOT_TOKENTELEGRAM_CHAT_IDleo
A36 雲端對 stage 的寫入有正門、只寫得進 stage isep-hand 45/452026-09-07inkstone/ISEP#137)+真實種進 youlin 一把探針再刪掉、真打 stage GET 200/無 Bearer POST 401;「帶 Bearer 真寫 KBDB」缺 KBDB_INTERNAL_TOKEN 沒跑
A37 雲端第一則 prompt 的主線是現在這條 isep-hand 31/312026-09-07inkstone/ISEP#140)+真 Gitea 薄殼形狀實跑(帶 token 讀到 Arcrun#48;匿名退回);「新 session 不跑指令第一眼就是它」要下一版裝進雲端
A37 tag → release 那一站 isep-hand 14/142026-09-07inkstone/ISEP#67→6574)+真 Gitea 唯讀 dry-run 兩次(v0.23.0 總管被擋的情境、v0.3.4 走到建那條路)
A38 回頭問收貨端+開場會問 isep-hand 14/14+信標 33/332026-09-07inkstone/ISEP#67→6574)+信標真 Gitea 匿名實跑一次安靜
A7 plugin 裝得起來 總管
A8 新 session 閘會觸發 總管 見本版 release note
B1B5 雲端 leo 還沒跑(機器碰不到 Cloud environment

A8 與 B 全綠之前,這個 sprint 的里程碑不准關。


已知斷點:notify_leo 這條 Telegram 通道現在是斷的(2026-08-28 實測)

inkstone/ISEP#93 的驗收第 4 條是「Telegram 真的收得到(不是『送出成功』, 是 leo 手機上真的出現)」。這一格現在過不了,而且原因不在本次的程式碼。

實測(scripts/isep-notify,閘判定 pass、UA 帶對之後):

POST …/webhooks/named/leo/notify_leo/trigger
→ HTTP 404 {"error":"找不到 workflow \"notify_leo\",請先執行 acr push"}

那台線上實例上沒有 notify_leo 這支工作流。 不是閘擋的、不是網路、不是金鑰 (這條路本來就不需要金鑰)。頂層 wiki agent-memory.md 記過同一件事發生過一次 (2026-08-10,KV 整批換新時定義消失,後來補推回去)——看起來又斷了一次

🔴 總管 2026-08-28 用 MCP 直接問那台實例,範圍比這裡查到的更廣

arcrun_get_workflow(notify_leo)              → not_found
arcrun_search_workflows(通知 leo Telegram)   → 只回 ship_refresh_cdn 一支
                                               而且它的執行紀錄寫著「圖定義已失效」

不只 notify_leo 不見了,那台實例上的工作流定義是整批失效的。

修法要有人把 mira repo 的 workflows/notify-leo.yaml 重新 push 上那台實例。 這不是「總管可以解的閘」——它比那更嚴格:那台是 leo 的個人帳號, 而 leo21c-write-guard.shleo 2026-08-20 立)明文禁止寫它 ⇒ 這是真人閘,總管也不能解,只有 leo 自己動得了。

📌 這條斷了不代表 #93 沒交付:本次的設計前提就是「不假設發得出去」—— 實測那兩次的退路都走通了,訊息貼回了 inkstone/ISEP#93 #issuecomment-5182#issuecomment-5184),並把原文印在眼前。 發不出去而靜默,等於沒做;發不出去但講出來並留下退路,就是這支的規格。 通道修好之後不必改任何程式碼,重跑 python3 scripts/isep-nag --notify 即可補驗這一格。

2026-09-07 從雲端 session 再量一次(inkstone/ISEP#130

結果 誰能修
notify_leo @ leo21c…/webhooks/named/leo/notify_leo HTTP 404,跟 08-28 一樣 leoleo21c 寫入是人閘)
notify_leo @ youlin*.arcrun-yuga3bse.workers.dev 連不到:egress proxy 對 CONNECT 回 403/__agentproxy/status 記為 policy denial)。不是 DNS、不是 000 leoCloud environment 的 allowed network hosts
api.telegram.org 302,通

⇒ 雲端能走的只有 Bot API 直送(scripts/isep-notify 現在會先試它),缺的只是兩個環境變數 TELEGRAM_BOT_TOKENTELEGRAM_CHAT_ID——Routine 文件 cloud-worker.md 檔頭本來就列著它們, 只是這個 environment 沒有。這一格仍然是 leo 的:加變數,然後回一個詞。