#!/usr/bin/env python3 """hooks/lib/evidence.py — 「這段要寫上票的內容,帶不帶得出出處?」(inkstone/ISEP#87) 依 inkstone/ISEP#40 S7 的慣例:`lib/` 裡的東西是共用零件,本身不決定 allow/block, 判決由呼叫它的閘做(`hooks/diagnosis-evidence-guard.sh`)。 ━━ 規則本身(leo,inkstone/ISEP#87)━━━━━━━━━━━━━━━━━━━━━━━━━ 「身為派人去查的人,我要自己在拿到調查結果前寫不出診斷, 我才不會用猜的結論把工人的判斷力關掉。」 票上原文的兩個壞法: · 診斷寫完了,**工人就不知道自己要做什麼**——它會照著我的結論去驗證,而不是去查 · **我不是那個 repo 的專家,它才是**。我的結論通常是猜的, 但因為寫在票上,看起來就像事實 ⇒ 順序倒過來:**先派人查 → 拿到查的結果 → 才可以寫診斷。** ━━ 🔴 為什麼判準不能是「找出診斷的句型」━━━━━━━━━━━━━━━━━━━━ 票上寫死:「『根因』『因為』『應該是』這類詞**一律不准當判準**」。 leo 2026-08-17 已證偽文字層封路:當日 **8 次誤攔、0 次正確攔截**,而且方向穩定—— **紅線寫得越細,命中關鍵字的機率越高 ⇒ 那些閘在懲罰謹慎。** 所以本檔**沒有任何「命中某個詞就違規」的比對**。它只做一件事: **認出「出處」在不在**——而且是**往放行的方向**做字面比對 (認出來 ⇒ 放行;認不出來 ⇒ 交給閘去看別的結構訊號)。 這是 `pr-verdict-guard.sh` ③ 用過的形狀:識別碼有限且唯一, 比對錯了只會**少擋一次**,不會多罰一次。 ━━ 什麼算「出處」(七種,全部是可以走過去看的東西)━━━━━━━━━━━━━━ 檔案:行號 / commit sha / comment 號 / 票號 / 網址 / 檔案路徑(帶目錄與副檔名)/ 圍欄裡的實測輸出 共同點:**讀的人可以自己走過去確認**。這正是「轉述別人查到的東西」與 「我猜的」之間唯一機械分得出來的差別(票上驗收條件 4:有出處的轉述不能被誤擋)。 用法: import evidence hits = evidence.sources(text) # [(種類, 命中的字串), ...] body = evidence.body_of(command) # 從一段 shell 指令裡把「要貼上去的內文」挖出來 """ import os import re # ── 七種出處。**方向是放行**:認出來就代表這段話走得回它的來源 ────────────── _SOURCE_PATTERNS = [ ("檔案:行號", re.compile(r"[\w./-]+\.\w{1,6}:\d+")), ("commit", re.compile(r"\b[0-9a-f]{7,40}\b")), ("comment 號", re.compile(r"(?:#issuecomment-|comment\s*)\d{2,}", re.I)), ("票號", re.compile(r"[A-Za-z0-9_.-]+/[A-Za-z0-9_.-]+#\d+")), ("網址", re.compile(r"https?://\S{4,}")), ("檔案路徑", re.compile(r"(?` 就讀那個檔, # 否則就拿指令文字本身當內文(PreToolUse 只看得到指令,這是這一層的天花板)。 # 🔴 一定要把「真正要貼上去的那段字」跟指令的鷹架分開。第一版沒分, # 結果 `curl … https://git.uncle6.me/api/v1/…/comments -d '{"body":"<沒出處的診斷>"}'` # **永遠放行**——因為指令裡的**那個 URL 自己就被當成出處了**。 # 同一個病 `ticket-api-bypass-guard.sh` 檔頭也記過:認錯了要看的東西, # 閘就在驗一個跟規則無關的欄位。 _FARG_RE = re.compile(r"(?:^|\s)(?:-F|--file)\s+([^\s'\"]+)") _BODY_FLAG_RE = re.compile(r"(?:^|\s)--body[\s=]+(['\"])(.*?)\1", re.S) _JSON_BODY_RE = re.compile(r"""['\"]body['\"]\s*:\s*['\"](.*?)['\"]\s*[,}]""", re.S) def body_of(command): """回 (內文, 來源)。來源 ∈ {"file", "--body", "json", "command"}。 依序試四種:`-F <檔>` → `--body <字串>` → payload 裡的 `body` 欄 → 整段指令。 前三種都是「這段字才是要貼上票的東西」,指令的其餘部分(網址、token、旗標) **不算內文**——它們不是誰查來的,把它們算成出處等於這道閘自己拆自己。 """ if not command: return "", "command" m = _FARG_RE.search(command) if m: path = m.group(1) try: if os.path.isfile(path): with open(path, encoding="utf-8", errors="ignore") as f: return f.read(), "file" except Exception: pass m = _BODY_FLAG_RE.search(command) if m: return m.group(2), "--body" m = _JSON_BODY_RE.search(command) if m: return m.group(1).replace("\\n", "\n"), "json" return command, "command"