# pr-review Deep, critical PR review with auto-fix. This skill guides the agent through a thorough review of a pull request, posting inline comments for each issue found, auto-fixing them, resolving the discussion threads, and marking the PR as ready-to-merge when no blocking issues remain. ## When to Invoke Invoke this skill when asked to review a PR, or when a PR is open and needs review before merge. Do NOT invoke automatically on every PR — this is an on-demand deep review, not a CI gate. ## Prerequisites - The PR must be open in a Gitea repo - The agent needs Gitea MCP access (gitea server) - The agent needs git push access to the PR's head branch - The PR should have passed CI (validate job) before deep review ## Review Categories Review every PR against these 8 categories. For each issue found, post an inline comment on the specific line, then auto-fix it. ### 1. Functional Correctness - Does the code actually do what the spec/PR title claims? - Are edge cases handled? (empty input, null, boundary values, concurrent access) - Are error paths tested? Not just happy path. - Does the code handle all return values? (ignored errors, unchecked None) - Are there off-by-one errors, wrong comparisons, inverted conditions? - Do loops terminate correctly? (no infinite loops, correct break/continue) - Are regex patterns correct? (anchored, escaped, non-greedy where needed) - Are API responses validated before use? (status codes, response shape) ### 2. Completeness - Are all requirements from the spec implemented? (check each REQ-ID) - Are all acceptance criteria in the spec checked off? - Are tests written for all new code paths? - Are error messages user-facing (wrapped in `_()`)? - Are new CLI commands documented in `docs/user/cli-commands.md`? - Are new modules added to architecture docs? - Are CHANGELOG entries added for user-facing changes? - Are translations added for new user-facing strings? ### 3. Architecture - Does the code follow the repo's layer separation? (no business logic in CLI, no direct subprocess in CLI) - Are new dependencies justified? (no unnecessary new packages) - Is configuration via env vars / config.py, not hardcoded? - Are new modules placed in the correct directory? (ci/ vs tools/ vs molecule/) - Does the code reuse existing utilities? (no reimplemented helpers) - Are imports circular? (check import chains) - Is the code testable? (injectable dependencies, no hidden global state) - Does the code follow existing patterns in the codebase? ### 4. Reliability - Are external API calls retried with backoff? - Are timeouts set on all network operations? - Are file operations atomic? (write to temp, rename) - Are database operations transactional where needed? - Are there race conditions? (check shared mutable state) - Are resources cleaned up in all paths? (finally blocks, context managers) - Can the code handle partial failures? (one service down, others up) - Are idempotency guarantees maintained? (safe to retry) ### 5. Robustness - Does the code fail gracefully? (meaningful error messages, not stack traces) - Are unexpected inputs handled? (type checking, validation) - Are there any crash-on-bad-input paths? - Does the code degrade under load? (backpressure, queue limits) - Are there resource leaks? (file handles, connections, memory) - Does the code survive network partitions? (retry, circuit breaker) - Are there any unhandled exceptions that could crash the process? - Is logging sufficient to diagnose production issues? ### 6. Security - Are there hardcoded secrets, tokens, or passwords? - Is `shell=True` used with user input? (command injection) - Is `eval()` or `exec()` used? (code injection) - Are SQL queries parameterized? (no string concatenation) - Are file paths validated? (no path traversal) - Are user inputs sanitized before display? (XSS in web contexts) - Are SSL/TLS verifications disabled without justification? - Are secrets logged in error messages or debug output? - Are permissions checked before privileged operations? - Is sensitive data in memory longer than necessary? ### 7. Technical Excellence - Are functions under 50 lines? (refactor if longer) - Is cyclomatic complexity reasonable? (no deeply nested if/else chains) - Are names meaningful? (no single-letter vars, no misleading names) - Is dead code removed? (no commented-out blocks, no unused imports) - Are comments explaining WHY, not WHAT? - Is the code DRY? (no copy-pasted blocks that should be shared) - Is the code SOLID? (single responsibility, open/closed) - Are magic numbers extracted to named constants? - Is the code formatted per the repo's linter config? - Are type hints present on all function signatures? ### 8. Test Quality - Do tests actually test the behavior? (not just that code runs) - Are tests independent? (no shared mutable state, no order dependency) - Are tests fast? (no real sleeps, no real network calls, mocked) - Are edge cases tested? (empty, None, boundary, error paths) - Are test names descriptive? (test_what_condition_expected_result) - Are mocks set up correctly? (mocking the right object, not too broad) - Is coverage 100% for new code? (every branch, every line) - Are integration tests added for cross-module changes? - Do tests clean up after themselves? (tmp_path, fixtures) ## Review Procedure ### Step 1: Gather Context ``` 1. Read the PR spec (if exists): docs/specs/.md 2. Fetch PR details via Gitea MCP: pull_request_read (get_pr, list_pr_files) 3. Read the full diff: git diff origin/master...HEAD 4. Read the PR description and any existing review comments 5. Identify the repo's task prefix (OBL-INFRA, GRM, SSO, DEVX) ``` ### Step 2: Review Each File For each changed file in the PR: 1. Read the full file (not just the diff) to understand context 2. Go through all 8 review categories 3. For each issue found, note: file path, line number, category, severity, description, suggested fix ### Step 3: Post Inline Comments For each issue found, post an inline review comment using the Gitea MCP: ``` mcp_call_tool: gitea / pull_request_review_write method: create owner: repo: pull_number: state: PENDING (accumulate comments before submitting) body: "" (empty for now, summary added on submit) comments: [ { path: "", new_line_num: , body: "**[] []** \n\n**Suggested fix:**\n```\n\n```" } ] ``` Comment format: ``` **[Security] [error]** `shell=True` used with user input — command injection risk. **Suggested fix:** ```python subprocess.run(["git", "log", commit], check=True) ``` ``` Severity levels: - `error` — must fix before merge (security, correctness, crash) - `warning` — should fix before merge (reliability, best practice) - `info` — consider fixing (style, minor improvement) ### Step 4: Auto-Fix Issues For each issue that can be safely auto-fixed: 1. Edit the file using the `edit` tool 2. Commit with message: `fix: address review comment — ` 3. Push to the PR's head branch: `git push origin HEAD` 4. Wait for CI to re-run on the push Auto-fix ALL issues unless: - The fix requires an architectural decision (ask the user) - The fix changes public API behavior (ask the user) - The fix is ambiguous (multiple valid approaches, ask the user) ### Step 5: Resolve Discussion Threads After auto-fixing an issue and CI passes: 1. Find the review comment thread for that issue 2. Post a reply: `Fixed in . Closing this thread.` 3. Resolve the discussion (if Gitea supports it via API) 4. If resolving via API is not available, the reply comment serves as resolution ### Step 6: Submit Final Review After all issues are addressed (fixed or discussed): ``` mcp_call_tool: gitea / pull_request_review_write method: submit owner: repo: pull_number: review_id: state: COMMENT (or APPROVED if no blocking issues remain) body: ``` ### Step 7: Post Summary Post a brief summary as a PR comment (via `issue_write / add_comment`): ``` ## Deep Review Summary - **Files reviewed:** N - **Issues found:** N (N auto-fixed, N require attention) - **Categories:** security (N), correctness (N), architecture (N), ... **Outcome:** ✅ Ready to merge — all issues addressed. **OR** **Outcome:** ⚠️ N blocking issue(s) remain — see inline comments. ``` Keep the summary to 5-10 bullet points. Do not paste the full review. ### Step 8: Mark PR Ready If all issues are addressed and no blocking issues remain: ``` mcp_call_tool: gitea / issue_write method: add_labels owner: repo: issue_number: labels: [] ``` If blocking issues remain, do NOT add the label. Post a comment explaining what needs to be resolved before the PR can merge. ## Gitea MCP Tools Reference | Action | MCP tool | Method | |--------|----------|--------| | Get PR details | `pull_request_read` | `get_pr` | | List PR files | `pull_request_read` | `list_pr_files` | | Get PR diff | `pull_request_read` | `get_pr_diff` | | Create review (pending) | `pull_request_review_write` | `create` (state: PENDING) | | Submit review | `pull_request_review_write` | `submit` (state: APPROVED/COMMENT/REQUEST_CHANGES) | | Post PR comment | `issue_write` | `add_comment` | | Add label | `issue_write` | `add_labels` | | List labels | `label_read` | `list_repo_labels` | | Merge PR | `pull_request_write` | `merge` (do NOT use — auto-merge handles this) | ## Important Rules - **Never merge the PR yourself.** Add the `ready-to-merge` label and let the auto-merge workflow handle it. This ensures CI passes and the commit message follows the `-N: ` format. - **Never approve your own PR.** If the agent created the PR, post COMMENT state, not APPROVED. - **Always push fixes to the PR branch**, not directly to master. - **Wait for CI after each push** before resolving the discussion thread. - **Post one review with all comments**, not multiple reviews. - **The summary must be brief** — 5-10 bullet points max. - **Severity matters**: only `error` severity blocks the `ready-to-merge` label.