.agents/skills/deep-review/references/scoping.md
Determine what to review, produce the scope summary, and decide whether to inline the diff or pass fetch commands. Light mode uses the same scope rules (steps 1–4), skipping the background hunt when conversation context already explains the change.
gh pr view <num> --json title,body,files,baseRefName,headRefNamegit diff <base>...HEAD --statgit diff HEAD --stat + git status --shortgit diff is always three-dot (<base>...HEAD), never two-dot. Two-dot diff against a base that has moved (origin/main..HEAD) injects other people's freshly merged commits as reverse changes. Three-dot diffs from the merge-base, yielding what this branch introduced. (git log is the opposite — see the sanity check below.)
Three-dot alone is not enough — the base ref must not lag the branch's real fork point. If the branch was rebased onto a newer remote default while the local default still points at an older commit, that local ref is now an ancestor of HEAD, so <local-default>...HEAD has its merge-base at the stale commit and hands you every upstream commit the rebase pulled in. Pick the base in this order:
baseRefName at its merge-base; gh pr diff <num> already scopes correctly, prefer it over any hand-built range.git fetch first, then origin/<default>...HEAD — the fetched remote ref is the one that cannot lag, and three-dot makes it safe in both cases (rebased branch → merge-base is the rebase base; never-rebased branch → merge-base is the original fork point).<default>...HEAD only after confirming local is not behind (git rev-list --count <local-default>..origin/<default> is 0, or there is no remote).Sanity-check whichever you pick before reviewing: git log --oneline <base>..HEAD — two dots — must list only this branch's commits. Someone else's commit in that list means the base is wrong; fix the base, do not review around it.
Note the asymmetry, it is the easiest mistake here: log wants two dots where diff wants three. git log <base>..HEAD and git diff <base>...HEAD describe the same set of commits (merge-base → HEAD). git log <base>...HEAD is a symmetric difference and additionally lists everything the base gained after the fork — run that one and a perfectly correct base looks broken.
gh pr diff <num>. Also fetch gh pr view <num> --json mergeable,isDraft,reviewDecision,statusCheckRollup and append those fields to the scope summary (feeds the merge-verdict table). URL only — bare #123 does not trigger PR mode.abc123..def456) → review exactly that object: git show <sha> --stat then git show <sha> for a single commit, git diff <a>..<b> for a range. The named object IS the scope — ignore branch/worktree state and do not fall through to the rules below.git diff HEAD + untracked files read separately), committed branch work (git diff <base>...HEAD), or both (git diff $(git merge-base <base> HEAD) — worktree against the merge-base; the plain one-commit form git diff <base> would re-import default-branch advances as reverse diffs). Gitlink-only entries (M <submodule> where git status shows (new commits) and nothing else changed) do NOT count as uncommitted changes — a superproject tracking an in-flight submodule branch shows this permanently; route them through §4 instead of triggering this question.git diff HEAD; list untracked via git ls-files --others --exclude-standard (§3 defines how their contents join {changes} — git diff HEAD alone misses them entirely).git diff <base>...HEADFilter lockfiles (pnpm-lock.yaml, package-lock.json, yarn.lock, bun.lockb, ...), snapshots (*.snap), generated files (*.generated.*, *.gen.ts), and build output (dist/, build/, .next/) from both stat and full-diff commands:
git diff "$BASE"...HEAD --stat -- . \
':(exclude)pnpm-lock.yaml' ':(exclude)*.snap' ':(exclude)dist/**'
Then judge with filtered numbers, checking in this order (very large first, so a few-files-but-huge diff never counts as small):
{changes}.{changes}, subagents run it themselves.Untracked files in an uncommitted scope are part of the review, not just a name list: count their line counts toward the size judgment; on the small-diff path append each untracked file's full content to {changes} (one fenced block per file, path as header); on the large-diff path list their paths next to the fetch commands so subagents read them.
Excluded files are out of scope; reviewing a lockfile on request is a separate task, not this flow.
One change often spans the main repo and submodules — review them together by default.
--submodule=log to it (git diff <base>...HEAD --submodule=log, git show <sha> --submodule=log, git diff <a>..<b> --submodule=log, ...). git status showing modified: <path> (new commits) is an extra signal only when the scope includes the worktree (§2 rules 3–4); for a named commit/range the gitlink pair comes from that object, never from current branch/worktree state.git -C <path> diff <old>..<new>), which merges into {changes} alongside the main-repo command; sizes add up for the small/large judgment.lobehub/src/x.ts:42).gh issue view).gh pr list --head $(git branch --show-current) → gh pr view <num> --json title,body.git log <base>..HEAD --oneline (commit messages are thin; last resort).Condense changed-file list + requirement/acceptance criteria into ≤ 200 words. Every subagent prompt carries it — it is the primary yardstick for "does this change violate the requirement".