Skip to content

context-mode plugin:rejected-approach 分類混淆 UX 建議與真實安全攔截,且 WebFetch deny 跟系統規則衝突 #3

Description

@ohyeh

背景

在查本機 context-mode-local-insight 的 governance 數字(86 次 rejection / 127 次 decision)時,深入到 context-mode plugin 的 hook 原始碼(~/.claude/plugins/cache/context-mode/context-mode/1.0.169/hooks/),發現兩個設計層級的問題。這不是這個 repo(agent-scripts)自己的問題,是第三方 context-mode plugin(vendored from mksglu/context-mode,ELv2 license)的行為,但跟我們自己的 global 規範(web_fetch 使用規則)有直接衝突,記錄在這裡供追蹤。

發現一:rejected-approach 這個 category 混淆了「純 UX 建議」跟「真的攔截」

實際撈本機 92 筆 rejected-approach 原始資料:

  • 88 筆是固定字串 "Redirected to context-mode sandbox" —— 對應 pretooluse.mjsaction: "modify" 分支,工具照樣執行,只是被塞了一段「建議改用 ctx_execute」的文字(Agent 41、ctx_execute 25、ctx_batch_execute 16、Bash 6)
  • 4 筆是 WebFetch 的強制轉導(見發現二)
  • 0 筆包含 "Blocked by security policy"(真正安全攔截該有的字串)—— 這台機器上這個 category 從未記錄過一次真正的安全攔截

問題:routing.mjs 對 Bash/ctx_execute 真的撞到 security.evaluateCommand 的 deny pattern 時,回傳的也是 action: "deny",一樣被寫進同一個 category = 'rejected-approach',跟純建議的 action: "modify" 混在一起,資料庫 schema 沒有欄位區分兩者。analytics-core.mjs 算出來的 governance.totalRejections 因此無法分辨「這是好意提醒」還是「真的擋下危險操作」——如果哪天真的發生一次安全攔截,會被淹沒在大量無害建議裡,光看聚合數字完全看不出來。這跟 context-mode-local-insight 自己抓出來的 11 個 withheld metrics 是同一種病(free-text/未配對計數),但這次病灶在上游 context-mode 本身,不在 local-insight wrapper。

發現二:WebFetch 的 action: "deny" 跟系統內建的 web_fetch 規則字面上互斥

routing.mjscanonical === "WebFetch" 無條件回傳 action: "deny",強制轉導到 ctx_fetch_and_index

if (canonical === "WebFetch") {
  const url = getWebFetchUrl(toolInput);
  return mcpRedirect({
    action: "deny",
    reason: `context-mode: WebFetch redirected. Call ${t("ctx_fetch_and_index")}(...)...`,
    ...
  }, mcpToolsAvailable);
}

但 Claude 本身的系統提示(不屬於這個 repo,屬於 Anthropic 平台層)明講:「Whenever the user references a URL or a specific site in their query, ALWAYS use the web_fetch tool」。這兩條規則字面上互斥:一個說「一定要用 web_fetch」,context-mode 的 hook 卻無條件把每一次 WebFetch 呼叫攔截、換成別的工具。實務上 hook 會贏(PreToolUse 在模型的工具呼叫執行前就介入),行為上不會卡住、也感覺不到衝突,但這是兩個權威來源在同一件事上給出互斥指令,只是被 hook 的執行時機悄悄蓋過去,沒有經過任何協調或宣告。

建議追蹤方向(不代表要在這個 repo 修,多數要回報上游 mksglu/context-mode)

  1. 上游:rejected-approach 的 marker 應該多帶一個欄位區分 modify(UX 建議)vs deny(真實攔截),至少是 source_hook/decision.action 本身而非統一塞進 data 字串。
  2. 上游或這裡:如果之後要在 ~/.claude/CLAUDE.md~/.agents/rules/ 明文要求「WebFetch 給特定 URL 時必須使用」,應該同時註記「context-mode 啟用時這條規則會被 hook 攔截取代,不算違反」,避免未來哪個 session 因為 WebFetch 沒真的被呼叫而被誤判成沒遵守規範(跟 L006/issue global 規範漏洞:工具鏈中間旁白未套用語言/結尾規則 #2 是同一類「先查機制實際生效範圍再下違反判斷」的教訓)。

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions