skills / code

code-review-excellence

what it does

Master effective code review practices to provide constructive feedback, catch bugs early, and foster knowledge sharing while maintaining team morale. Use when reviewing pull requests, establishing review standards, or mentoring developers.

Verified Before and after: 2 models 1 try per case View source Download .zip

Compare the answers

Answers from Claude Sonnet 5.5 and GPT-6.1 Sol · try 1 of 1

Same request, same model, once with the skill and once without. Read both and judge for yourself.

“Can you review this PR? It adds order search to our internal admin API.”

Source material given with the request

PR #418 "Add order search endpoint" Description: Adds GET /orders/search?q=<name>&page=<n>. Page numbers are 1-based, matching the admin UI. 20 results per page. --- a/app/routes/orders.py +++ b/app/routes/orders.py @@ -1,6 +1,25 @@ from flask import Blueprint, request, jsonify from app.db import get_conn +from app.auth import login_required, current_user bp = Blueprint("orders", __name__) + +PAGE_SIZE = 20 + + +@bp.get("/orders/search") +@login_required +def search_orders(): + term = request.args.get("q", "")
Show the rest (12 more lines)
+ page = int(request.args.get("page", 1)) # pages are 1-based in the UI + offset = page * PAGE_SIZE + sql = ( + "SELECT id, customer_name, total FROM orders " + f"WHERE account_id = {current_user.account_id} " + f"AND customer_name ILIKE '%{term}%' " + f"ORDER BY created_at DESC LIMIT {PAGE_SIZE} OFFSET {offset}" + ) + with get_conn() as conn: + rows = conn.execute(sql).fetchall() + return jsonify([dict(r) for r in rows])
with the skill
## Verdict: 🔄 Request changes The account-scoping intent is good, but there are three issues to address before merging. ### Required changes 1. **[blocking · security] Parameterize the query.** `q` is interpolated directly into SQL. A crafted search term can change the query’s logic, potentially bypassing the `account_id` restriction and exposing other accounts’ orders. Even an ordinary name such as `O'Brien` can break the query. Bind the account ID, search pattern, limit, and offset using the database driver’s parameter API. Build the pattern as a parameter value—not as part of the SQL string. 2. **[blocking · correctness] Fix the 1-based page offset.** `offset = page * PAGE_SIZE` makes page 1 skip the first 20 orders. Use: ```python offset = (page - 1) * PAGE_SIZE ``` 3. **[important · input validation] Reject invalid page values with a 400 response.** `int(...)` raises an unhandled `ValueError` for values such as `page=abc`, producing a server error. Zero and negative pages are also accepted, leading to incorrect pagination or database errors. Catch conversion failures and require `page >= 1` before executing the query.
Show the rest (16 more lines)
### Additional feedback - **[important · pagination] Add a unique tie-breaker:** use `ORDER BY created_at DESC, id DESC`. Orders with identical timestamps otherwise have no guaranteed relative order, so page boundaries can produce duplicates or omissions even without data changes. - **[question · authorization] Does `login_required` also enforce admin access?** The snippet establishes authentication and intends account scoping, but doesn’t show an admin permission check. If admin access isn’t enforced elsewhere, add the appropriate authorization guard. - **[question · search semantics] Should `%` and `_` be literal characters?** Parameterization prevents SQL injection, but these characters still act as `ILIKE` wildcards. Escape them if the intended behavior is literal substring matching. ### Tests to add - Default page and explicit page 1 return the first 20 results; page 2 returns the next 20. - Invalid, zero, and negative pages return 400. - Names containing apostrophes work, and injection-like input cannot bypass account isolation. - Other accounts’ orders are excluded. - Equal timestamps have deterministic ordering. - Unauthenticated—and, if applicable, non-admin—requests are rejected. *Review based on the supplied diff; surrounding authorization, database-driver behavior, and CI results weren’t available.*
without
**Request changes:** there’s a SQL injection vulnerability and two pagination issues. ### 1. [P1] SQL injection can bypass account isolation **Location:** SQL construction, particularly `f"AND customer_name ILIKE '%{term}%' "` `q` is interpolated directly into SQL. A crafted search term can change the `WHERE` clause and bypass the `account_id` restriction, potentially exposing orders from other accounts. Even an ordinary name containing an apostrophe, such as `O'Brien`, will break the query. Use bound parameters for the account ID, search pattern, limit, and offset. Build the `%…%` pattern as a parameter value, not as SQL text. Use the placeholder syntax supported by your database driver. ### 2. [P2] Pagination skips the first 20 results **Location:** `offset = page * PAGE_SIZE` The endpoint uses 1-based page numbers, so page 1 currently starts at offset 20 rather than 0. The first 20 matching orders are inaccessible through valid page numbers. Change this to: ```python offset = (page - 1) * PAGE_SIZE ``` ### 3. [P2] Invalid page input produces server errors
Show the rest (11 more lines)
**Location:** `page = int(request.args.get("page", 1))` Values such as `page=abc` or `page=` raise an uncaught `ValueError`, resulting in a 500 response. Negative values can also produce invalid SQL offsets. Page zero is accepted despite the documented 1-based contract. Catch conversion errors, require `page >= 1`, and return a 400 response for invalid input. **Tests to add before merging:** - Searches containing apostrophes and SQL-like input remain literal searches and cannot return another account’s orders. - With at least 41 matching orders, pages 1–3 return the expected 20/20/1 results. - Missing `page` defaults to page 1; empty, nonnumeric, zero, and negative values return 400. - Consider `ORDER BY created_at DESC, id DESC` so timestamp ties have deterministic ordering across pages.

Answers are shown exactly as the model wrote them, from the first try, and nothing is picked by hand.

The models

2 models

Claude Sonnet 5.5

made by Anthropic

claude-sonnet-5-5 · revision not reported by the provider

1 try per case · tested 3 Nov 2026

GPT-6.1 Sol

made by OpenAI

gpt-6.1-sol · revision not reported by the provider

1 try per case · tested 3 Nov 2026

The tasks

written by Carte Blanche
py-chunked-clean-diff

“Quick review before I merge? Mostly want to know if anything blocks it.”

py-search-injection-pagination

“Can you review this PR? It adds order search to our internal admin API.”

py-wallet-withdraw-race

“Please review this change to our wallet service.”

ts-async-foreach-import

“Review this before I merge please. It's the CSV contact import we talked about.”

ts-file-delete-first-pr

“This is Priya's first PR since she joined the team last week. Can you review it? I'll paste your comments into GitHub.”

Install

Download the .zip and unzip it. Put its files, in a folder named code-review-excellence, here:

Claude Code~/.claude/skills/Every project. For one project only, use .claude/skills/ inside it.
Codex~/.agents/skills/Every project. For one repository only, use .agents/skills/ inside it.
Cursor~/.cursor/skills/Cursor also reads the Claude Code and Codex folders above.

Then start a new session and ask for what the skill does. Other agents that read SKILL.md have their own skills folder; check their docs.

Coming after launch: get skills from inside your agent, no download needed.