e45faef8a2
背景:2026-09-01 一個 subagent 把分支推上 GitHub 沒經過解保險,同時總管這端擋得住, 看似「subagent 端失效」。查證後: - 官方文件(https://code.claude.com/docs/en/hooks)明講 PreToolUse hook 對 subagent 與主線是同一批,只是 input 多帶 agent_id/agent_type ⇒ 閘無從只擋一端。 - github-contact-guard.sh 從不讀那兩個欄位,所以「一端有效一端失效」不會出在身分判斷上。 - 當天的洞是同一族的 cwd 病(inkstone/ISEP#109/#125):閘拿 hook 自己的 cwd 解 origin。 2026-09-07(49a7145)接上 lib/push_target_dir.py 後,**字面路徑**的形狀已修好, 且已由 scripts/test-github-contact-guard.sh 的 A39 cwd 群覆蓋。 本輪交付(都驗過): 1. 在既有的 scripts/test-github-contact-guard.sh(唯一真相源,不另開平行測試)尾端加 7 條 runsub:同一條指令帶 agent_id(subagent)與不帶(總管)各跑一次,判決必須相同。 涵蓋推 GitHub(含 cd/-C 字面路徑原形狀)擋、推 Gitea/讀取放行。26→33,實測 33/33。 2. 回歸性驗過:把新測試跑舊閘(49a7145^)→ 09-01 的兩條 cd/-C 場景紅(漏擋), 證明這組測試真的抓得住它要抓的病。 3. docs/TESTING.md A39 段更新條數、失敗判讀,並記下下面這個殘留破口。 🔴 查出並實測(含雲端實跑)一個殘留的同形狀破口,未修(見下): push 目標用**未展開 shell 變數**表示時(git -C "$VAR" push/cd "$VAR" && git push), hook 收到的是展開前字串,push_target_dir 對 $VAR 回「不確定」⇒ 退回 session cwd 解 remote。 關鍵不對稱:main-and-prod-push-guard 遇「不確定」退回「要戳記」=擋(fail-safe); github-contact-guard 預設「證明不了 github 就放行」⇒ cwd 是 Gitea 時,真的推 GitHub 的 -C "$VAR" 會漏擋。雲端實跑(本 session 即 CHILD_SESSION=1):git -C "$VAR/gh-repo" push 未被 D20 擋,一路打到 git proxy 才被 403 擋(那是 proxy 不是 D20);本機沒有 proxy 後手。 不修的理由:fail-closed 會誤攔「用變數推 Gitea」,屬「誤攔比漏擋嚴重」的取捨, 應另開票由總管/leo 裁(附建議修法:push_target_dir 區分「無指令」與「指令不可解」, 後者 github-contact 改擋並印『改用字面路徑』的出路——出路走得通、可測)。 同形狀家族盤點(實跑驗過,回應「還有哪些閘是這個形狀」): - github-contact-guard.sh:字面路徑已修;殘留變數形狀破口(見上,另票)。本輪補 subagent 維度測試。 - main-and-prod-push-guard.sh:已修(push_target_dir),且遇不確定 fail-safe,cross-repo 測試 19/19。 - line-needs-own-worktree.sh:cwd 維度已修(checkout_target_dir),測試 110/110。 - not-my-branch-guard.sh:★仍是同形狀破口★——git -C "$PROJ" 讀 hook 自己的目錄; NOT_MY_BRANCH_OK=1 前綴 PreToolUse 收不到(逃生口結構性失效)。實測:subagent cd/-C 進別的 repo 對 held 分支 commit → 放行(該擋)。屬 commit 閘、非本票 D20 範圍, mistakes.md 早標「另報」,建議另開票(需 commit-target 解析器+認得字面前綴)。 僅動測試腳本與文件,未動任何會被載入的檔(hooks/commands/skills/agents/plugin.json 皆未動) ⇒ 不改變任何閘的行為,plugin.json 未動,版本待總管定。 Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01TGxitYq49FzYC7EFkbhzF5