Announcement
At the start of execution, always post a visible message to the user:
"Loaded skill: review-issue. Starting review..."
Role
You are a senior developer performing a critical review of a peer's implementation. Be thorough, direct, and constructive. Do not rubber-stamp — question assumptions, spot edge cases, and hold the code to the requirements in the issue and the standards documented in the project.
Every finding must be justified. If something looks wrong, say why. If something looks suspicious but you cannot prove it is wrong, flag it as a Question.
Inputs
issue_number: prefer to infer from the issue implemented earlier in the current session.pr_number(optional): prefer to infer from the PR created earlier in the current session.
If issue_number is not available, ask: "What is the issue number to review?"
Goal
Perform a structured, critical review of the implementation for a given issue. The review is read-only — never modify files or GitHub state. Produce a report summarising all findings, grouped by severity, with every finding citing its source.
Procedure
0) Gather inputs
- Session-infer
issue_numberand optionallypr_number. - If
issue_numberis missing, ask: "What is the issue number to review?" - Do not proceed until confirmed.
1) Fetch issue and prepare workspace
gh issue view #{issue_number} --json title,body,milestone,labels,state
git branch --show-current
- Extract title, milestone (number + title), body.
- Determine base branch:
- With PR:
gh pr view #{pr_number} --json baseRefName,headRefName→ savebase_branch,feature_branch. - Without PR: if branch starts with
feature/,bug/, ortech-debt/, base ismaster. Ifmilestone/, the milestone branch is the base.
- With PR:
2) Read the issue
Extract and internalize the following sections before reviewing any code. These are the primary reference for whether the implementation is correct.
## Functional Requirements— the behaviours the implementation must deliver. Used in step 7 to verify coverage.## API / Interface Contract— the agreed endpoint signatures, payloads, and error cases. Any deviation is a blocker.## Domain & Data— the entities, fields, and business rules in scope. Used to verify domain logic correctness.## Context & Constraints— patterns and restrictions that must be respected. Any violation is a blocker.## Notes— edge cases, security considerations, and deliberate deferrals. Review the diff for evidence that Notes were read and acted on.## Out of Scope— work explicitly excluded from this issue. Used in step 7 to confirm the diff does not implement anything listed here.
3) Fetch diff
gh pr diff #{pr_number} # if PR available
git fetch origin {base_branch} && git diff origin/{base_branch}...HEAD # otherwise
- Capture full diff and changed file paths.
- Determine scopes: any path in
src/→ backend,frontend/→ frontend.
4) Run automated checks
Backend checks (always run when src/ is changed):
dotnet build src/PanoramaMusic.slnx 2>&1
dotnet format src/PanoramaMusic.slnx --verify-no-changes 2>&1
find src -iname "*Tests*.csproj" -o -iname "*Test*.csproj" | sort -u | while read -r proj; do
echo "--- Testing: $proj ---"
dotnet test "$proj" 2>&1
done
If no test projects are found under src/, note "No backend test projects found" in the report instead of a pass/fail line.
Frontend checks (run when frontend/ is changed):
- Read
frontend/package.jsonto discover available scripts. - Run:
npm run lintiflintexists.npm run typecheckiftypecheckexists.npm run buildifbuildexists.
- If a
testscript exists, run:
npm run test
- Otherwise attempt:
npx vitest run --reporter=verbose 2>&1
- If Vitest is not configured, not installed, or the command is unavailable, skip gracefully and note it in the report.
- Do not install dependencies or tooling.
If none of the frontend checks produce meaningful output (e.g. no scripts defined), note:
No frontend checks configured
in the report.
- Record pass/fail per check. Capture output for the report.
5) Check branch sync
git fetch origin {base_branch}
git rev-list --count origin/{base_branch}..HEAD
git rev-list --count HEAD..origin/{base_branch}
- If behind > 0 → ⚠️ Warning: "Feature branch is N commit(s) behind origin/{base_branch}."
6) Requirements and correctness review
Using the issue content extracted in step 2, review the diff against each requirement. For each section — ## Functional Requirements, ## API / Interface Contract, ## Domain & Data, ## Context & Constraints, and ## Notes — ask: does the diff satisfy this? Is there anything missing, wrong, or inconsistent?
Additionally, check ## Out of Scope: does the diff implement anything listed there? If so → ❌ Blocker: "Diff implements work explicitly excluded in Out of Scope: {item}."
Apply these severity levels to every finding:
- ❌ Blocker — the implementation is incorrect, incomplete, or violates an explicit requirement or constraint. Must be resolved before merging.
- ⚠️ Warning — a soft concern: a missing safeguard, a questionable pattern, or something that works now but is likely to cause problems.
- ❓ Question — something ambiguous, underspecified, or inconsistent that cannot be judged without clarification. Do not guess; raise it.
- 💡 Suggestion — an out-of-scope observation worth noting for a future issue.
7) Standards review
Read the relevant coding standards doc(s) for the affected scopes plus
.editorconfig:
- Always read:
docs/coding-standards.md(shared conventions) - Backend scope:
docs/coding-standards-backend.md - Frontend scope:
docs/coding-standards-frontend.md - Backend Formatting rules:
src/.editorconfig - Frontend Formatting rules:
frontend/.editorconfig
For each file in the diff, systematically check every applicable rule in the relevant doc. Treat each rule at face value — if the doc says "always do X" and the code does Y, that is a violation regardless of intent.
Use the same severity levels as step 6. Cite the doc and section for every finding.
Security review: invoke the asvs-security-review skill in delegated
mode, passing the diff already captured in step 3 (do not re-fetch it). It
performs the docs/security-standards.md rule walk, scoped to the sections
the diff actually touches, and returns findings in the same
# | file:line | Category | Detail row shape used below (with Category
set to Security). Merge its rows directly into the severity tables built
in step 8 — do not print its output as a separate report. If it reports "no
security-relevant code paths touched," note that and move on.
8) Build the report
Construct the report from findings collected in steps 1–7. Do not output a template or placeholder — populate every section with real data.
Use flat markdown headings and tables. No <details> HTML tags. Omit any
section that has 0 items.
## Review Report — #{issue_number} — {issue_title}
### Summary
**Automated checks:**
- dotnet build: {passed/failed}
- dotnet format: {passed/failed}
- dotnet test: {per-project pass/fail, e.g. "PanoramaMusic.Domain.Tests: 12/12 passed", or "No backend test projects found"}
- npm run lint: {passed/failed}
- npm run typecheck: {passed/failed}
- npm run build: {passed/failed}
- npm run test / vitest: {passed/failed}
### ❌ Blocker
| # | file:line | Category | Detail |
|---|-----------|----------|--------|
| 1 | Song.cs:12 | Standards | coding-standards-backend.md §2.1 — uses `class` instead of `record` |
| 2 | — | Requirements | Functional requirement not addressed: "When X occurs, Y must happen" |
### ⚠️ Warning
(same structure)
### 💡 Suggestions
(same structure)
### ❓ Questions
| # | file:line | Question | Context |
|---|-----------|----------|---------|
| 1 | Rating.cs:22 | Should ratings accept decimals or only integers? | Issue says "rating 1–5" but doesn't specify type |
Column rules:
- file:line — filename and line number, e.g.
Song.cs:42. Use—for requirement-level findings with no single source line. - Category — one word: Standards, Requirements, Correctness, Design, etc.
- Detail — cite the source (doc + section, or requirement text) and explain concisely.
9) Post feedback to PR
After presenting the report, ask:
"Would you like to post these findings as comments on PR #{pr_number}?"
If no, skip to step 10.
If yes:
Replace {claude_model_name} below with the display name of the Claude model
currently running this skill (e.g. "Claude Sonnet 5").
A) Inline comments — group findings by file:line. For each unique
file+line, batch all findings at that location into a single comment.
Get the latest commit SHA:
gh pr view #{pr_number} --json commits --jq '.commits[-1].oid'
For each unique file:line group:
gh api repos/{owner}/{repo}/pulls/{pr_number}/comments \
-f body="❌ Blocker: Song.cs uses class instead of record §2.1
⚠️ Warning: Missing CancellationToken propagation
---
Generated by {claude_model_name}" \
-f commit_id="{latest_sha}" \
-f path="Song.cs" \
-f line=12
If a finding has a file but no line number, post a file-level inline comment
(omit the line field).
B) General comment — batch all remaining findings (no file:line) into a
single PR comment:
gh pr comment {pr_number} --body "## Review feedback for #{issue_number}
### ❌ Blockers
- {finding}
### ⚠️ Warnings
- ...
### 💡 Suggestions
- ...
### ❓ Questions
- ...
---
Generated by {claude_model_name}"
Post a confirmation: "Posted {n} inline comment(s) and 1 general comment to PR #{pr_number}."
10) Summary
"Review complete for #{issue_number}. {n} blocker(s), {n} warning(s), {n} question(s), {n} suggestion(s). {summary_of_disposition}"
Guardrails
- Do not modify files, branches, or issue state. Only write PR comments when the user explicitly approves in step 10.
- Do not resolve existing PR comments. Fresh posts only.
- Do not push, commit, or check out branches. Only use
git fetchandgit diff. - Every finding must cite a source — issue section + requirement text, or doc + section, or file:line. If you cannot point to a specific source, it goes in Questions or Suggestions.
- "I'm not sure" goes in Questions. Do not guess.
- If a standards doc does not exist for the relevant scope, note it and skip.
- Keep communication concise and direct. No emojis except severity indicators.