Review PRs (mcp-toolbox)
A review here is a proposal the maintainer edits and posts, not a rubber stamp. The value is
a fast, grounded read of the diff against the team's conventions.
Goal
Given a PR number or link, deliver a review the maintainer can post in seconds: a suggested
verdict (approve / request changes / comment), the findings that back it grouped by severity
so the important things aren't buried, and a paste-ready summary comment.
Prerequisites
gh authenticated for googleapis/mcp-toolbox, plus the PR number(s). A GitHub MCP
server substitutes for gh if it isn't available: the gh commands below map to its
read/list tools.
Workflow
Step 1: Read the source of truth
Read these live, not from memory. All three are symlinks to the repo-root
files, so they track main; cite them by their root names.
- references/maintainer-playbook.md: Reviewer's Checklist,
SLO/release context,
release candidate labeling.
- references/CONTRIBUTING.md: title/scope format (Conventional
Commits, with the
type table), keep-PRs-small, link-an-issue. Cite for title, description,
and process findings.
- references/DEVELOPER.md: tool/source naming, error taxonomy, the
patterns for adding a source/tool/integration test, CI-enforced docs structure, local
test/lint commands. Cite for code, test, and docs findings. Prefer it over
GEMINI.md
(CLAUDE.md/AGENTS.md symlink to it), which only summarizes.
Step 2: Fetch the PR, its diff, and its checks
gh pr view <n> --repo googleapis/mcp-toolbox --json number,title,body,author,labels,files,additions,deletions,commits,baseRefName,headRefName,state,isDraft,reviewDecision
gh pr diff <n> --repo googleapis/mcp-toolbox
gh pr checks <n> --repo googleapis/mcp-toolbox
Step 3: Triage before reviewing
Three shapes end the review early or change its bar:
- Auto-generated (
renovate, release-please): the only question is whether checks are
green. If so, propose merge and stop.
- Draft (
isDraft): review lightly and say so; the author isn't asking for a final pass.
- Non-code / policy (third-party badge, backlink, promotional README line, often a drive-by
contributor): acceptance is a maintainer policy call, not a code question. Say that plainly
instead of manufacturing code findings, and still check title convention and CI. Mark any URL
you haven't fetched
[UNVERIFIED].
Step 4: Read the whole diff, including what the title doesn't mention
Skim for the shape, then dive into hunks. Three failure modes:
- A docs-shaped title never lowers the read bar. PR #2473, "docs: fix typo in getting started
guide", added an npm
preinstall hook that hijacked git via GITHUB_PATH to exfiltrate an
RSA-encrypted GITHUB_TOKEN. Read every file in any PR touching .hugo/, package.json
lifecycle scripts, .github/workflows/, or .ci/. A file the title and description don't
account for is itself blocking.
- Look for what's missing, not just what's wrong: a refactor applied to 4 of 5 call sites,
a fix whose mirror bug still lives elsewhere, a behavior change with no test update, an error
swallowed silently.
- A hunk is not enough context to judge a hunk. Read the enclosing function for anything
correctness-relevant, and grep call sites when a signature, config field, or parameter changes.
A finding that needs a look outside the diff is the one no other reviewer will make.
Step 5: Check the diff against the issue it claims to fix
Keep this separate from Step 6: a PR can follow every convention and still implement the wrong
thing. Read the linked issue (gh issue view <n> --repo googleapis/mcp-toolbox --comments), then
ask three questions:
- Missing: What the issue asked for that the diff doesn't do. A partial fix that closes the
issue is worse than none, since the remainder becomes invisible.
- Extra: Unrelated changes bundled in. Ask for a split (
CONTRIBUTING.md, keep PRs small).
- Wrong: Implemented, but not what the issue described. Quote the issue line beside the
file:line.
With no linked issue the PR description is the spec: same three questions, and note that the
intent is self-declared.
Step 6: Work the review dimensions
Skip a dimension when it doesn't apply: say so, don't invent a finding.
- Title & description. Conventional Commits with the right
type(scope) per
CONTRIBUTING.md, plus !/BREAKING CHANGE for breaking
changes. Body follows .github/PULL_REQUEST_TEMPLATE.md: what, why, completed checklist,
Fixes #<n>. Note a missing issue link; don't block on it alone.
- Correctness. Cite
file:line and name the failure case, never
"looks risky".
- Bugs CI won't catch: Unhandled error returns, nil/empty input, off-by-one and boundary
conditions, concurrency, behavior contradicting stated intent.
- Type conversion at the MCP boundary: Drivers return native types
that don't serialize (MySQL
[]byte for decimals, nulls as nil/None). Require explicit
handling that maps to the tool's JSON schema; reject implicit casts and missing type switches.
- Error taxonomy on any new or changed error path:
AgentError for
input/execution errors the agent can fix itself (HTTP 200, isError: true) versus
ClientServerError for infrastructure failures it can't.
- Breaking changes. Changed config field names/YAML shape, tool names, removed or renamed
exported symbols, altered defaults. Without
! in the title and a justification in the body,
blocking.
- Refactor purity. A
refactor: PR must not change behavior. A bundled fix or default change
gets split into its own fix:/feat: PR so it's reviewable and revertable.
- Source reuse (new sources).: No new
internal/sources/<db>/ for a database wire-compatible
with an existing source. Same for a tool duplicating an existing tool under a new name.
- Architecture (no boilerplate). New tools embed
tools.BaseTool[Config], new sources follow
the registration pattern; reject re-declared interface methods (GetName, Manifest).
DEVELOPER.md lists what BaseTool provides.
- Tool and parameter descriptions. Each
description: is an LLM prompt, not developer
documentation: could an agent pick this tool and fill its parameters from that text alone, at a
token cost worth paying? Flag ones that restate the field name, omit units/format/allowed
values, or run long without adding information.
- Evals measure exactly this. For a PR editing
internal/prebuiltconfigs/tools/<config>.yaml,
note that the next step is a maintainer applying the evals: run label, which scopes the run
to the configs that PR touched. Like integration tests, un-run evals aren't a blocker.
- Tests. New logic or a bug fix needs tests; missing them is usually request-changes.
- Coverage: happy path, edge cases, and for a fix, a test that fails without it. A new
source/tool follows the unit + integration pattern and is wired into
.ci/integration.cloudbuild.yaml.
- Placement, reviewed as closely as coverage: source-specific helpers stay unexported in
tests/<db>/<db>_integration_test.go, never in the shared tests/common.go.
- Flakiness: tests run against a shared live instance, so ask for the four fixes by name:
- UUID-scoped resource names, so concurrent runs can't collide.
t.Cleanup teardown, so resources are freed even when the test fails.
- Polling instead of
time.Sleep.
- Subset assertions instead of exact-match, since another run can add rows.
- Un-run integration tests aren't a blocker. They need GCP credentials an external
contributor's PR can't trigger, so green CI doesn't mean they ran. Note that the next step is
a maintainer running them via the
tests: run label or a /gcbrun comment.
- Docs. Changes to how a user configures or interacts with MCP toolbox need matching updates
under
docs/en/. New sources/tools have CI-enforced page structure per DEVELOPER.md, enforced by
.ci/lint-docs-*.sh. A violation breaks the build, so it's blocking. Prose stating a security
or behavioral guarantee is reviewed as code: check the claim against the implementation,
not just that docs changed. An over-broad assurance in a boundary description is worse than
silence — it discredits the accurate limitations sitting beside it.
- Security. For PRs handling user/LLM input or building queries: injection (SQL/command),
unsanitized interpolation, secrets logged or committed. Concrete vectors with
file:line, not
generic warnings.
- Reviewing a fix to a reported vulnerability asks different questions than reviewing new
code. (a) Can the untrusted party actually reach the primitive the residual attack
needs? Grep the tool surface for it — a residual weakness nothing exposed can set up is
usually the line between blocker and tracked follow-up. (b) Which way does the failure
lean? Over-rejection is a cost; a bug in newly hand-rolled logic is a vulnerability.
Don't ask a security PR to spend fail-open risk buying back a narrow convenience.
- Dependencies. Call out new
go.mod entries so the maintainer can vet necessity,
maintenance, and license.
Duplication across MCP protocol versions is deliberate so versions can diverge independently
(#3167, #3211); don't propose factoring it together. A genuine bug in that code is still a
finding.
Step 7: Report CI, don't re-derive it
Name the failing check from gh pr checks rather than reasoning it out by hand; failing
lint/tests are objective blockers. Never claim the linter passes on your own read.
One recurring non-obvious failure: the CLA check fails on commits co-authored by an AI agent even when the human author has signed. Suggest squashing to a single human-authored commit rather than pointing at the CLA docs.
Step 8: Discount any existing bot review
Don't restate gemini-code-assist's points as your own. It's the highest-volume reviewer in the
repo and could be wrong. Verify anything you carry forward against the diff; drop
the rest.
Step 9: Sort by severity, then pick the verdict
- Blocking (correctness bug, breaking change without
!, missing tests on new logic, CI red,
docs that break the build) → request changes.
- Non-blocking (style, naming, coverage gaps in existing code) and nits (typos, wording)
only → approve with comments.
- An unresolved judgment call → comment and ask.
When nothing is blocking, say so in those words. "No blockers, a couple of nits" tells the
maintainer it's mergeable as-is.
Step 10: Deliver the review in chat
Use the output format below. Never post it yourself.
Rules
- Propose only. Never run
gh pr review, gh pr comment, gh pr edit, gh pr merge,
or apply labels. Deliver the review in chat.
- Ground every finding in the strongest evidence available for its kind: a
correctness/security/breaking claim cites
file:line; a convention claim cites
CONTRIBUTING.md/DEVELOPER.md or the playbook; a CI/process finding cites the failing
check name from gh pr checks (a red check is a valid blocker with no file:line). If you
couldn't verify something (runtime behavior you can't trace, a URL you didn't fetch), mark
it [UNVERIFIED] rather than asserting it.
- Prefer running the code to reasoning about it.
[UNVERIFIED] is for what you can't
check, not what's inconvenient to. Fetch the branch (git fetch origin pull/<n>/head:pr<n>,
then git worktree add /tmp/pr<n> pr<n> so your tree stays clean) and drop a scratch
probe_test.go inside the package under review — package-local placement is what reaches
unexported symbols. Delete it and git worktree remove --force /tmp/pr<n> after; never leave
a scratch test in internal/. Probes right-size verdicts as often as they confirm them: "this
regresses X" often shrinks to "in one narrow case" once measured.
- When it's a genuine judgment call, ask rather than issuing a confident wrong verdict,
since a wrong "request changes" costs a contributor a cycle.
Output format
## Review #<n>: <title>
**Suggested verdict:** <approve / request changes / comment>: <one-line reason>
**Title & issue:** <conventional-commit check; linked issue or "none, suggest linking">
**Spec (vs issue #<n>):** <implements it / what's missing, extra, or wrong; or "no issue linked">
**CI:** <passing / which checks failing, per gh pr checks>
**Blocking:**
- `file:line`: <finding + the failure case> [cite]
**Non-blocking:**
- `file:line`: <finding> [cite]
**Nits:**
- <typo/wording>
**Tests:** <added & adequate / what's missing>
**Docs:** <updated / what's missing, or n/a>
**Dependencies:** <new deps to vet, or none>
**release candidate:** <suggest label / not needed>
**Draft comment:**
<paste-ready summary the maintainer can post>
- Empty sections: omit them rather than writing "none".
- Except the Spec line: keep it even when the PR matches its issue. The maintainer wants
"does what the issue asked" stated, not inferred from silence.
- Batches: review each PR in its own subagent so the diffs don't bleed together, since a
finding attributed to the wrong PR is worse than a missed one. Present one block per PR, plus a
summary table (PR, verdict, blocker count).
1---2name: review-prs3description: Review a GitHub pull request in the googleapis/mcp-toolbox repo against the team's reviewer checklist: PR title/description conventions, linked issue, logic errors and unhandled edge cases, breaking changes, test coverage, docs updates, security (input handling), and new dependencies. Use whenever a maintainer asks you to review, look over, "take a look at", or check whether something is ready to merge in mcp-toolbox, e.g. "review #3703", "can you look at this PR", "is this good to merge", or when they paste an mcp-toolbox PR link. PROPOSE-ONLY: delivers the review in chat for the maintainer to post; never approves, requests changes, comments, labels, or merges on its own.4---56# Review PRs (mcp-toolbox)78A review here is a proposal the maintainer edits and posts, not a rubber stamp. The value is9a fast, grounded read of the diff against the team's conventions.1011## Goal1213Given a PR number or link, deliver a review the maintainer can post in seconds: a suggested14verdict (approve / request changes / comment), the findings that back it grouped by severity15so the important things aren't buried, and a paste-ready summary comment.1617## Prerequisites1819- `gh` authenticated for `googleapis/mcp-toolbox`, plus the PR number(s). A GitHub MCP20 server substitutes for `gh` if it isn't available: the `gh` commands below map to its21 read/list tools.2223## Workflow2425### Step 1: Read the source of truth2627Read these live, not from memory. All three are symlinks to the repo-root28files, so they track `main`; cite them by their root names.2930- [references/maintainer-playbook.md](references/maintainer-playbook.md): Reviewer's Checklist,31 SLO/release context, `release candidate` labeling.32- [references/CONTRIBUTING.md](references/CONTRIBUTING.md): title/scope format (Conventional33 Commits, with the `type` table), keep-PRs-small, link-an-issue. Cite for title, description,34 and process findings.35- [references/DEVELOPER.md](references/DEVELOPER.md): tool/source naming, error taxonomy, the36 patterns for adding a source/tool/integration test, CI-enforced docs structure, local37 test/lint commands. Cite for code, test, and docs findings. Prefer it over `GEMINI.md`38 (`CLAUDE.md`/`AGENTS.md` symlink to it), which only summarizes.3940### Step 2: Fetch the PR, its diff, and its checks4142```bash43gh pr view <n> --repo googleapis/mcp-toolbox --json number,title,body,author,labels,files,additions,deletions,commits,baseRefName,headRefName,state,isDraft,reviewDecision44gh pr diff <n> --repo googleapis/mcp-toolbox45gh pr checks <n> --repo googleapis/mcp-toolbox46```4748### Step 3: Triage before reviewing4950Three shapes end the review early or change its bar:5152- **Auto-generated (`renovate`, `release-please`):** the only question is whether checks are53 green. If so, propose merge and stop.54- **Draft (`isDraft`):** review lightly and say so; the author isn't asking for a final pass.55- **Non-code / policy** (third-party badge, backlink, promotional README line, often a drive-by56 contributor): acceptance is a maintainer policy call, not a code question. Say that plainly57 instead of manufacturing code findings, and still check title convention and CI. Mark any URL58 you haven't fetched `[UNVERIFIED]`.5960### Step 4: Read the whole diff, including what the title doesn't mention6162Skim for the shape, then dive into hunks. Three failure modes:6364- **A docs-shaped title never lowers the read bar.** PR #2473, "docs: fix typo in getting started65 guide", added an npm `preinstall` hook that hijacked `git` via `GITHUB_PATH` to exfiltrate an66 RSA-encrypted `GITHUB_TOKEN`. Read every file in any PR touching `.hugo/`, `package.json`67 lifecycle scripts, `.github/workflows/`, or `.ci/`. A file the title and description don't68 account for is itself blocking.69- **Look for what's *missing*, not just what's wrong:** a refactor applied to 4 of 5 call sites,70 a fix whose mirror bug still lives elsewhere, a behavior change with no test update, an error71 swallowed silently.72- **A hunk is not enough context to judge a hunk.** Read the enclosing function for anything73 correctness-relevant, and grep call sites when a signature, config field, or parameter changes.74 A finding that needs a look outside the diff is the one no other reviewer will make.7576### Step 5: Check the diff against the issue it claims to fix7778Keep this separate from Step 6: a PR can follow every convention and still implement the wrong79thing. Read the linked issue (`gh issue view <n> --repo googleapis/mcp-toolbox --comments`), then80ask three questions:8182- **Missing:** What the issue asked for that the diff doesn't do. A partial fix that closes the83 issue is worse than none, since the remainder becomes invisible.84- **Extra:** Unrelated changes bundled in. Ask for a split (`CONTRIBUTING.md`, keep PRs small).85- **Wrong:** Implemented, but not what the issue described. Quote the issue line beside the86 `file:line`.8788With no linked issue the PR description is the spec: same three questions, and note that the89intent is self-declared.9091### Step 6: Work the review dimensions9293Skip a dimension when it doesn't apply: say so, don't invent a finding.9495- **Title & description.** Conventional Commits with the right `type(scope)` per96 `CONTRIBUTING.md`, plus `!`/`BREAKING CHANGE` for breaking97 changes. Body follows [`.github/PULL_REQUEST_TEMPLATE.md`](https://github.com/googleapis/mcp-toolbox/blob/main/.github/PULL_REQUEST_TEMPLATE.md): what, why, completed checklist,98 `Fixes #<n>`. Note a missing issue link; don't block on it alone.99- **Correctness.** Cite `file:line` and name the failure case, never100 "looks risky".101 - *Bugs CI won't catch:* Unhandled error returns, nil/empty input, off-by-one and boundary102 conditions, concurrency, behavior contradicting stated intent.103 - *Type conversion at the MCP boundary*: Drivers return native types104 that don't serialize (MySQL `[]byte` for decimals, nulls as `nil`/`None`). Require explicit105 handling that maps to the tool's JSON schema; reject implicit casts and missing type switches.106 - *Error taxonomy* on any new or changed error path: `AgentError` for107 input/execution errors the agent can fix itself (HTTP 200, `isError: true`) versus108 `ClientServerError` for infrastructure failures it can't.109- **Breaking changes.** Changed config field names/YAML shape, tool names, removed or renamed110 exported symbols, altered defaults. Without `!` in the title and a justification in the body,111 blocking.112- **Refactor purity.** A `refactor:` PR must not change behavior. A bundled fix or default change113 gets split into its own `fix:`/`feat:` PR so it's reviewable and revertable.114- **Source reuse (new sources).**: No new `internal/sources/<db>/` for a database wire-compatible 115 with an existing source. Same for a tool duplicating an existing tool under a new name.116- **Architecture (no boilerplate).** New tools embed `tools.BaseTool[Config]`, new sources follow117 the registration pattern; reject re-declared interface methods (`GetName`, `Manifest`).118 `DEVELOPER.md` lists what `BaseTool` provides.119- **Tool and parameter descriptions.** Each `description:` is an LLM prompt, not developer120 documentation: could an agent pick this tool and fill its parameters from that text alone, at a121 token cost worth paying? Flag ones that restate the field name, omit units/format/allowed122 values, or run long without adding information.123 - *Evals measure exactly this.* For a PR editing `internal/prebuiltconfigs/tools/<config>.yaml`,124 note that the next step is a maintainer applying the `evals: run` label, which scopes the run125 to the configs that PR touched. Like integration tests, un-run evals aren't a blocker.126- **Tests.** New logic or a bug fix needs tests; missing them is usually request-changes.127 - *Coverage:* happy path, edge cases, and for a fix, a test that fails without it. A new128 source/tool follows the unit + integration pattern and is wired into129 `.ci/integration.cloudbuild.yaml`.130 - *Placement,* reviewed as closely as coverage: source-specific helpers stay unexported in131 `tests/<db>/<db>_integration_test.go`, never in the shared `tests/common.go`.132 - *Flakiness:* tests run against a shared live instance, so ask for the four fixes by name:133 - UUID-scoped resource names, so concurrent runs can't collide.134 - `t.Cleanup` teardown, so resources are freed even when the test fails.135 - Polling instead of `time.Sleep`.136 - Subset assertions instead of exact-match, since another run can add rows.137 - *Un-run integration tests aren't a blocker.* They need GCP credentials an external138 contributor's PR can't trigger, so green CI doesn't mean they ran. Note that the next step is139 a maintainer running them via the `tests: run` label or a `/gcbrun` comment.140- **Docs.** Changes to how a user configures or interacts with MCP toolbox need matching updates141 under `docs/en/`. New sources/tools have CI-enforced page structure per `DEVELOPER.md`, enforced by142 `.ci/lint-docs-*.sh`. A violation breaks the build, so it's blocking. Prose stating a security143 or behavioral *guarantee* is reviewed as code: check the claim against the implementation,144 not just that docs changed. An over-broad assurance in a boundary description is worse than145 silence — it discredits the accurate limitations sitting beside it.146- **Security.** For PRs handling user/LLM input or building queries: injection (SQL/command),147 unsanitized interpolation, secrets logged or committed. Concrete vectors with `file:line`, not148 generic warnings.149 - *Reviewing a fix to a reported vulnerability* asks different questions than reviewing new150 code. (a) **Can the untrusted party actually reach the primitive the residual attack151 needs?** Grep the tool surface for it — a residual weakness nothing exposed can set up is152 usually the line between blocker and tracked follow-up. (b) **Which way does the failure153 lean?** Over-rejection is a cost; a bug in newly hand-rolled logic is a vulnerability.154 Don't ask a security PR to spend fail-open risk buying back a narrow convenience.155- **Dependencies.** Call out new `go.mod` entries so the maintainer can vet necessity,156 maintenance, and license.157158Duplication across MCP protocol versions is deliberate so versions can diverge independently159(#3167, #3211); don't propose factoring it together. A genuine bug in that code is still a160finding.161162### Step 7: Report CI, don't re-derive it163164Name the failing check from `gh pr checks` rather than reasoning it out by hand; failing165lint/tests are objective blockers. Never claim the linter passes on your own read.166167One recurring non-obvious failure: the CLA check fails on commits co-authored by an AI agent even when the human author has signed. Suggest squashing to a single human-authored commit rather than pointing at the CLA docs.168169### Step 8: Discount any existing bot review170171Don't restate `gemini-code-assist`'s points as your own. It's the highest-volume reviewer in the172repo and could be wrong. Verify anything you carry forward against the diff; drop173the rest.174175### Step 9: Sort by severity, then pick the verdict176177- **Blocking** (correctness bug, breaking change without `!`, missing tests on new logic, CI red,178 docs that break the build) → request changes.179- **Non-blocking** (style, naming, coverage gaps in existing code) and **nits** (typos, wording)180 only → approve with comments.181- An unresolved judgment call → comment and ask.182183When nothing is blocking, say so in those words. "No blockers, a couple of nits" tells the184maintainer it's mergeable as-is.185186### Step 10: Deliver the review in chat187188Use the output format below. Never post it yourself.189190## Rules191192- **Propose only.** Never run `gh pr review`, `gh pr comment`, `gh pr edit`, `gh pr merge`,193 or apply labels. Deliver the review in chat.194- **Ground every finding** in the strongest evidence available for its kind: a195 correctness/security/breaking claim cites `file:line`; a convention claim cites196 `CONTRIBUTING.md`/`DEVELOPER.md` or the playbook; a CI/process finding cites the failing197 check name from `gh pr checks` (a red check is a valid blocker with no `file:line`). If you198 couldn't verify something (runtime behavior you can't trace, a URL you didn't fetch), mark199 it `[UNVERIFIED]` rather than asserting it.200- **Prefer running the code to reasoning about it.** `[UNVERIFIED]` is for what you *can't*201 check, not what's inconvenient to. Fetch the branch (`git fetch origin pull/<n>/head:pr<n>`,202 then `git worktree add /tmp/pr<n> pr<n>` so your tree stays clean) and drop a scratch203 `probe_test.go` *inside* the package under review — package-local placement is what reaches204 unexported symbols. Delete it and `git worktree remove --force /tmp/pr<n>` after; never leave205 a scratch test in `internal/`. Probes right-size verdicts as often as they confirm them: "this206 regresses X" often shrinks to "in one narrow case" once measured.207- **When it's a genuine judgment call, ask** rather than issuing a confident wrong verdict,208 since a wrong "request changes" costs a contributor a cycle.209210## Output format211212```213## Review #<n>: <title>214215**Suggested verdict:** <approve / request changes / comment>: <one-line reason>216217**Title & issue:** <conventional-commit check; linked issue or "none, suggest linking">218**Spec (vs issue #<n>):** <implements it / what's missing, extra, or wrong; or "no issue linked">219**CI:** <passing / which checks failing, per gh pr checks>220221**Blocking:**222- `file:line`: <finding + the failure case> [cite]223224**Non-blocking:**225- `file:line`: <finding> [cite]226227**Nits:**228- <typo/wording>229230**Tests:** <added & adequate / what's missing>231**Docs:** <updated / what's missing, or n/a>232**Dependencies:** <new deps to vet, or none>233**release candidate:** <suggest label / not needed>234235**Draft comment:**236<paste-ready summary the maintainer can post>237```238239- **Empty sections:** omit them rather than writing "none".240- **Except the Spec line:** keep it even when the PR matches its issue. The maintainer wants241 "does what the issue asked" stated, not inferred from silence.242- **Batches:** review each PR in its own subagent so the diffs don't bleed together, since a243 finding attributed to the wrong PR is worse than a missed one. Present one block per PR, plus a244 summary table (PR, verdict, blocker count).