review-inbox — independently scanned and version-tracked by SaferSkills.
SaferSkills independently audited review-inbox (Agent Skill) and scored it 100/100 (green). The audit ran 55 deterministic rules across Security, Supply Chain, Maintenance, Transparency, and Community; it found 0 high-severity and 0 lower-severity findings. The full rule-by-rule trace and per-finding evidence are below. Free, methodology-open.
Findings & checks · 0 flagged
Every scanned point with the score it earned and what moved between them.
First recorded scan — no prior version to compare against.
The primary manifest — the file an agent reads to learn what this artifact does.
找出 team 內需要自己 first review、re-approve、或 re-review 的 PR,批次執行 review, 並依來源回 Slack 通知。
此 skill 只處理多 PR discovery + batch review orchestration。單一 PR URL 轉 review-pr; 「我的 PR」approval 狀態轉 request-pr-review。
支援三個來源:
| Source | Use when |
|---|---|
| Slack | 預設;掃 PR channel 最近訊息中的 PR URLs——含 thread 回覆,不只 top-level |
| GitHub 條件掃描 | 一律與 Slack 取聯集:我投過票而 head 已推進的 open PR,不靠任何人說話 |
| Thread | 使用者提供 Slack thread URL 並要求 review |
| Label | 使用者明確提到 need review label |
不得 review 自己的 PR。不得對 waiting_for_author PR 重複 review。 Review inbox 屬 reviewer-side read-only lane;它可以 advisory,但對 awaiting_re_review、 mergeable_ready、unsupported_mutation、changes_requested 的解釋必須沿用 shared PR state。 它不得把 batch review 結果升格成 author-side completion / release authority;所有 「可 merge / 已修完 / 可 release」語句只能轉述 shared state,不可自行推論。
| Situation | Load |
|---|---|
| Any run | context-budget-contract.md, review-inbox-discovery-flow.md, stale-approval-detection.md, workspace-config.yaml |
| Batch review execution | review-inbox-batch-review-flow.md, .claude/skills/review-inbox/dispatch-context-bundle.md |
| Slack notification | review-inbox-slack-reporting.md, slack-message-format.md, ../review-pr/references/github-slack-user-mapping.md, scripts/validate-language-policy.sh |
每張 PR 交給一個 sub-agent 執行。 用哪一種 agent、幾個並行、先跑哪一張,由執行的人 當下判斷——這一支提供判斷需要的事實(姊妹單關係、規模、風險等級、授權狀態),不提供結論。 它不指名任何一種 agent 型別,要求與禁止都不指名:一支 scope: universal 的 skill 指名一個 它不 ship 的東西,換一個環境就不成立。
主 session 不讀完整 diff。 這一條與怎麼派無關,它由 context-budget-contract.md 直接 規定,任何 sub-agent 都滿足它。以前這件事由一條「禁用 general-purpose sub-agent」的規定 代理,那條規定引用的證據從來沒有產出過(DP-575);代理拿掉了,被代理的沒有。
Batch review dispatch 由 main session 讀 dispatch-context-bundle.md 一次,把它 inline 注入 每個 review packet。Packet 自帶執行 review 需要的全部內容;另外附上延伸參考的路徑, 要不要讀、讀多少由 sub-agent 自己判斷。
scripts/scan-need-review-prs.sh,Slack mode 走 channel dump + scripts/extract-pr-urls.py);派工前照〈Scan Freshness〉重核 一次,60 秒從那次重核起算。 Slack channel scan 使用 MCP 時指定 detailed output——concise 不輸出 === Message from 與 Message TS: 這兩個 marker,parser 會找不到 message header 而 靜默回傳 0 個 URL(stderr 只印一行 WARN,離場碼仍然是 0),而那跟「channel 真的空」 分不開;fallback CLI 的 --oldest 可接受 Slack timestamp 或 ISO date/datetime。 產出 candidates 之前要先過 `scripts/review-inbox-discovery-probe.sh`。 它非零就停在 那裡、把 marker 與說明回報出來——不要宣告空的收件匣,也不要靜默改走 label scan。 它現在除了「讀不讀得懂」也問「讀完了沒」:時間窗翻到底了嗎、窗內有新回覆的 thread 讀進來了嗎。--window-seconds 在 channel 模式必填,值是這一趟宣告的回溯時間窗。 4b. Slack 那條做完,再跑兩支 GitHub 條件掃描,逐支取聯集。頻道掃描的前提是有人說話, 這兩支都沒有這個前提,而它們的定義域不重疊——兩支都要跑:
scripts/scan-my-stale-reviews.sh --my-user <u> --org <org> --merge-with <Slack 的 candidates>——我投過票、而 head 已經推進的 open PR。2026-09-04 兩輪 discovery 都空手,而同一時間 有五顆 PR 擋在我方舊票上、作者早就推了修正。
scripts/scan-unreviewed-prs.sh --my-user <u> --org <org> --repo <name>... --merge-with <上一支的輸出> --open-prs-out <表>——指名的 repo 裡我一票都沒投過的 open PR。前兩條來源都錨在「有人針對我做了動作」, 一顆沒有人貼、我也還沒碰過的 PR 結構上進不了它們。實跑一趟:43 秒撈 29 顆,其中 13 顆是另外兩條都撈不到的;那 13 顆批次讀完 28 秒。 --open-prs-out 順手把那幾個 repo 全部 open PR 的 head 與預設分支寫成一份表—— 它取的是那三道濾網(draft、作者、更新窗)之前那一份,因為判「這一顆疊在誰身上」 問的是「誰是 open PR」,不是「誰該被派」。第 5 步的 --open-prs 讀它。
要問哪幾個 repo 是呼叫者的知識,讀公司自己的 config,這一支不掃整個 org。其餘旗標、 預設值與為什麼判準不是「有人指名要我」,都在 discovery reference 的第三來源那一節。
annotate-review-candidates.py --open-prs <上一步的表> enrich,補上 sister PR clustermetadata 與 model_tier semantic class。Slack mapping 若含 root_ticket_key,cluster 必須優先使用 root ticket;若沒有 umbrella ticket 但同一 Slack root message 有可辨識 topic,使用 root_topic_key;最後才 fallback 到每張 PR 自己的 ticket。
鍵相同不等於同一批改動。 同一個 repo 的兩顆 PR 要進同一個 cluster,還要量得到改動 交集——共用一個檔案,而且該檔在 base 那一側的 hunk 區塊重疊。量不到就兩顆都走完整 review:sibling 走的是 lead summary 的六條判準,判錯的代價是一顆 PR 只被半審過,而判成 standalone 的代價只是多花一次 review。跨 repo 的兩顆不套這條,因為那裡量不到交集, 而「同一件事在三個 repo 各開一顆」正是 sister PR 要服務的形狀。每一顆都帶著一句 cluster_reason 說出憑什麼——它分得出這一顆的交集是量到的(same_repo_overlap)還是 量不到而放行的(cross_repo_key_only)。
這條規則來自一次真跑的收件匣:同一則 thread 裡有兩張不同單的 PR,同一個 repo、 同一個 controller 檔案,而區塊零重疊。舊的判準讓後面那顆走 sibling,於是它只被 lead 的六條判準看過,漏掉一條 must-fix。
但交集量得到也還不夠,因為它對串行堆疊恆為真。 同一個 repo 裡第二顆踩在第一顆改過 的檔案上往前疊,交集必然量得到——而第 N 顆帶的是它自己那一段沒有人讀過的改動,只是 順便帶著前面那幾顆的行。所以同一個 repo 的兩顆還要問這一顆從哪裡長出來的:base 落在 同一個 repo 任何一顆 open PR 的 head 上就是串行,那幾顆一律走完整 review (stacked_on_candidate 或 stacked_on_open_pr,看 parent 在不在這一輪的候選集裡)。 問不到其中一顆的 base 時分不出平行與串行,也走完整 review (same_repo_lineage_unmeasurable)——量不到不得讀成可以半審。
2026-09-16 的實例,一批八顆:b2c-web 的 PR-1 建護欄、後七顆逐顆疊在上面,八顆同一張 單、同一則 thread。舊的判準把它們判成一個 cluster,其中 +3155/+6578/+11222 行的三顆 走了 sibling 的半審,由人手動覆寫回來。
沒有需要 review 的 PR 並停止。probe 沒過的空清單不是空的收件匣,是來源壞掉了。
張數多或 diff 大自行縮小範圍。** 這一支只在兩種情況停下來,而且要說出是哪一種:來源 拿不到,或是需要授權而授權不存在。
build-review-prompt.sh 產生 review packets + manifest。人已經授權送出時,把授權一起傳進去(--authorized-by 與 --authorization-quote),packet 才有一條到得了執行 那一層的路——沒有這兩個參數時 packet 明講「未授權」,sub-agent 產出 payload 但不送出。 蒐證放在 sub-agent 那一層:主 session 的 per-PR 預算不會被 diff 灌爆,而讀 diff 以外 的檔案(追消費端、對照姊妹 repo、實跑驗證)只有在那一層做得到。
在那張 PR 的 review 開始的那一刻才取,計畫時不整批預取——理由與量到的形狀寫在 `review-inbox-batch-review-flow.md` 的〈什麼時候取那份 diff〉。Prompt 必須使用 deterministic handbook resolver 列出已存在的 project handbook paths,空清單時明確標示 no project handbook。Prompt 必須要求執行者先讀 changed-file names,再依 diff size sampling;existing inline comments 的完整 body 不進主 session,reviewer envelope 內 讀得到。Cluster lead 先跑完整 review;cluster sibling 使用 sibling-diff mode 與 `small_fast` model class hint(那是一個事實,不是一道指令——adapter 認不認得由執行的人判斷),不確定時標記 `needs_standard_review`——但兩端行為對不上 本身就是一個發現**,不是只是一個要標記的例外。
不在這裡再問一次要不要送。
--verify-delivered 模式回讀這個帳號在輪次起點之後送出的 review,把「看起來沒有把正文送到」的那幾則指名出來;有可疑的就 非零離場:
bash .claude/skills/review-inbox/scripts/measure-review-inbox-session.sh --verify-delivered \
--my-user {my_user} --since {輪次起點 ISO8601} --pr OWNER/REPO#N [--pr ...]這一層不在送出者手上,所以繞過腳本自己 gh api 的那幾次它也看得到——它問的是 GitHub 上的最終狀態,誰送的、之後怎麼改的都不影響。判準是三條腿:送出時間在標記上線 之後、body 長度大於 0、而且缺 polaris-review-target 標記。空 body 是合法形狀 (只帶 inline comment 的那一種),不進可疑。
measure-review-inbox-session.sh 產生 telemetry JSON,並用polaris-learnings.sh add --type telemetry --tag review-inbox 寫入 metadata.review_inbox_run。若無法取得完整 transcript,仍需用 line-count proxy 記錄 candidate count、reviewed count 與 artifact volume。
review-pr 流程負責。scripts/validate-language-policy.sh。reply_broadcast: true。輸出 reviewed count、APPROVE / REQUEST_CHANGES / COMMENT counts、Slack notification count、 任何 blocked PR 的原因,以及 telemetry run_id。Telemetry 可用:
POLARIS_WORKSPACE_ROOT={workspace_root} .claude/skills/review-inbox/scripts/polaris-learnings.sh query --type telemetry --tag review-inbox查到 metadata.review_inbox_run.main_session_input_tokens。
<!-- PROSE-EXTERNAL-PATHS: docs-manager/ — 動手對象:那是 specs 站台自己的 repo,這支 skill 往它寫東西、讀它的結構,不是我們抄一份放著的知識 -->
~30 seconds. Free. No account. Every finding cites a rule and a line of evidence.