review-inbox · diff
v3.0.0 to v3.0.0
8 added, 1 removed. Audit A to A.
---
name: review-inbox
description: |
"Use when the user wants to discover and review PRs across the team awaiting their attention. NOT for a single specific PR (use review-pr). Supports three discovery modes: Label (GitHub label scan), Slack (channel-wide scan), Thread (specific Slack thread URL). Trigger: '掃 PR', 'review 大家的 PR', '批次 review', '有哪些 PR 要我看', Slack thread URL + review intent ('review <slack_url>', '幫我看這串'). Key: '我的 PR' → request-pr-review; '大家的 PR' / Slack URL → here; single PR URL → review-pr."
要掃出團隊裡等著自己看的 PR。例如「掃 PR」「review 大家的 PR」
「有哪些 PR 要我看」,或給一個 Slack thread URL 要人看那一串。
分辨:「我的 PR」→ request-pr-review;「大家的 PR」或 Slack URL → 這裡;
單一個 PR URL → review-pr。
metadata:
author: Polaris
version: 3.0.0
requires:
- skill: review-pr
why: 本支的輸入解析(resolve-pr-work-source.sh、pr-state-snapshot.sh)整個在它那裡;沒有它就拿不到要看的那個 PR
scope: universal
tools:
- name: gh
provision: manual
why: 開 PR、讀 review、建 release、查 CI
fix: 裝 GitHub CLI 並完成 `gh auth login`——二進位檔裝得起來,登入只有人做得到
- name: jq
provision: framework
why: 解析 API 回應的 JSON
install: mise:aqua:jqlang/jq
- name: rg
provision: framework
why: 掃樹用;這支的 selftest 缺了它就跑不完
install: mise:aqua:BurntSushi/ripgrep
---
# Review Inbox — 批次 Review 待審 PR
找出 team 內需要自己 first review、re-approve、或 re-review 的 PR,批次執行 review,
並依來源回 Slack 通知。
## Contract
此 skill 只處理多 PR discovery + batch review orchestration。單一 PR URL 轉 `review-pr`;
「我的 PR」approval 狀態轉 `request-pr-review`。
支援三個來源:
| Source | Use when |
|---|---|
- | Slack | 預設;掃 PR channel 最近訊息中的 PR URLs |
+ | 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,不可自行推論。
## Reference Loading
| 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 自己判斷。
## Flow
1. 讀 workspace config 與 defaults,取得 GitHub org、PR channel、approval threshold。
2. 解析 mode:Thread 優先,其次 explicit Label,其餘走 Slack。
3. 取得 current GitHub username,作為 exclude author 與 review-status 判定依據。
4. 依 discovery reference 產生 candidates JSON;scan snapshot 超過 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>`。
+ 頻道掃描的前提是有人說話,這一條沒有這個前提——2026-09-04 兩輪 discovery 都空手,
+ 而同一時間有五顆 PR 擋在我方舊票上、作者早就推了修正。
5. 將 candidates JSON 經 `annotate-review-candidates.py` enrich,補上 sister PR cluster
metadata 與 `model_tier` semantic class。Slack mapping 若含 `root_ticket_key`,cluster
必須優先使用 root ticket;若沒有 umbrella ticket 但同一 Slack root message 有可辨識
topic,使用 `root_topic_key`;最後才 fallback 到每張 PR 自己的 ticket。
6. 若 candidates 為空**而且 probe 回的是 `POLARIS_DISCOVERY_LEGITIMATE_EMPTY`**,回報目前
沒有需要 review 的 PR 並停止。probe 沒過的空清單不是空的收件匣,是來源壞掉了。
7. 顯示排序後清單,然後全部進入 review。**不問「先看哪一批」、不問「要不要送」、不因為
張數多或 diff 大自行縮小範圍。** 這一支只在兩種情況停下來,而且要說出是哪一種:來源
拿不到,或是需要授權而授權不存在。
8. 用 `build-review-prompt.sh` 產生 review packets + manifest。人已經授權送出時,把授權
一起傳進去(`--authorized-by` 與 `--authorization-quote`),packet 才有一條到得了執行
那一層的路——**沒有這兩個參數時 packet 明講「未授權」**,sub-agent 產出 payload 但不送出。
**蒐證放在 sub-agent 那一層**:主 session 的 per-PR 預算不會被 diff 灌爆,而讀 diff 以外
的檔案(追消費端、對照姊妹 repo、實跑驗證)只有在那一層做得到。
9. 執行 per-PR review packets,一張都不留。**每張 PR 的 head 與完整 diff
在那張 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`——但**兩端行為對不上
本身就是一個發現**,不是只是一個要標記的例外。
10. 收斂結果,依來源模式發 Slack summary 或 thread replies。**跟 review 一樣做完就回**,
不在這裡再問一次要不要送。
11. 跑 `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。
12. 在對話中回報每個 PR 的 review result、approve status 與 telemetry run_id。
## Write And Notification Rules
- Review body 與 inline comments 由 `review-pr` 流程負責。
- Slack message 送出前必須通過 `scripts/validate-language-policy.sh`。
- Slack mode 不發 channel-wide summary;只回覆原始 PR threads。
- Label mode 發一則 channel summary。
- Thread mode 回覆指定 thread。
- Thread replies 不設 `reply_broadcast: true`。
## Completion
輸出 reviewed count、APPROVE / REQUEST_CHANGES / COMMENT counts、Slack notification count、
任何 blocked PR 的原因,以及 telemetry run_id。Telemetry 可用:
```bash
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 往它寫東西、讀它的結構,不是我們抄一份放著的知識 -->