| name | pr-review |
| description | Review PR changes against project standards and post feedback |
| argument-hint | [PR number] [--comment] |
/pr-review - Pull Request Review
Review PR changes against project standards for this user-agent parsing library.
Usage
/pr-review # Review current branch's PR
/pr-review 123 # Review PR #123
/pr-review --comment # Post review as PR comment
Workflow
Step 1: Get PR Context (run in parallel)
REPO=$(git remote get-url origin | sed 's/.*github.com[:/]\(.*\)\.git/\1/' | sed 's/.*github.com[:/]\(.*\)/\1/')
gh pr view --json number,title,baseRefName,headRefName,files
git diff origin/main...HEAD --name-only
git diff origin/main...HEAD --stat
If a PR number was provided, use gh pr view <number> and gh pr diff <number> instead.
Step 2: Categorize Changed Files
| Category | Patterns |
|---|
| Parser Core | user_agent_parser/parser.py |
| Advanced Engine | user_agent_parser/advanced_engine.py |
| Analytics | user_agent_parser/analytics.py |
| Public API | user_agent_parser/__init__.py |
| Constants/Devices | user_agent_parser/constants.py, user_agent_parser/modern_devices.py |
| Tests | tests/**/*.py |
| CI/Config | .github/workflows/*, pyproject.toml, poetry.lock |
| Docs | *.md, CHANGELOG.md |
Step 3: Apply Review Checks
Read changed files and verify against these standards:
Regex & Parser Correctness
| Check | Standard |
|---|
| Regex tested | Every new/changed regex has real UA string test cases |
| browser_rules order | New entries don't break priority (Edge before Chrome, Chrome before Safari, etc.) |
| _token bounds | Every self._token[n] access has len() guard |
| Compiled patterns | Hot-path regex uses cached compiled patterns, not re.compile() per call |
| ReDoS safety | No nested quantifiers or overlapping alternations that cause catastrophic backtracking |
Backward Compatibility
| Check | Standard |
|---|
| parse() 7-tuple | parse() still returns (browser, browser_version, os, os_version, device_type, device_name, device_host) |
| Public API stable | Functions in __init__.py / __all__ unchanged in signature |
| AdvancedResult fields | No removed/renamed fields in AdvancedResult, BrowserCapabilities, SecurityFingerprint |
| DeviceCategory enum | No removed/renamed enum values, only additions |
| Constants immutable | OS, DeviceType, DeviceName attributes not changed, only extended |
Python 3.8+ Compatibility
| Check | Standard |
|---|
| No match/case | match/case requires 3.10+ — use if/elif |
| No union syntax | X | Y in types requires 3.10+ — use Union[X, Y] |
| No TypeAlias | Requires 3.10+ — use plain assignment |
| No ParamSpec | Requires 3.10+ — use typing_extensions if needed |
Cache Safety
| Check | Standard |
|---|
| lru_cache returns immutable | Cached functions return tuples, not lists/dicts/sets |
| Cache key hashable | All arguments to cached functions are hashable |
| No cache side effects | Cached functions are pure (no mutations, no I/O) |
Test Coverage
| Check | Standard |
|---|
| New features tested | New parser/engine features have parametrized test cases |
| Real UA strings | Tests use real-world user agent strings, not fabricated ones |
| Edge cases covered | Empty string, None, very long strings, missing parentheses |
| New source files | New .py files in user_agent_parser/ have test coverage |
Thread Safety
| Check | Standard |
|---|
| Batch processing | ThreadPoolExecutor usage includes proper cleanup (with statement) |
| No shared mutation | Batch operations don't share mutable state across threads |
Code Quality
| Check | Standard |
|---|
| Type hints | Public functions have parameter and return type hints |
| CHANGELOG | Non-trivial changes have CHANGELOG.md entry |
| Device code format | MOBILE_DEVICE_CODE_NAME entries follow key→name format, no duplicates |
| Consistent naming | New methods/constants follow existing naming patterns |
Step 4: Generate Report
Structure findings by severity:
## PR Review: #<number> - <title>
**Files Changed:** N | **Additions:** +N | **Deletions:** -N
### 🔴 Critical (blocks merge)
- [ ] `user_agent_parser/parser.py:78` - `self._token[3]` accessed without bounds check
- [ ] `user_agent_parser/__init__.py:15` - `parse()` return changed from 7-tuple to 8-tuple — breaks all consumers
- [ ] `user_agent_parser/parser.py:45` - New browser regex `(Chrome|CriOS)(\d+)*` has nested quantifier — ReDoS risk
### 🟡 Standards (should fix)
- [ ] `user_agent_parser/advanced_engine.py:120` - Uses `match/case` — Python 3.10+ only, project supports 3.8+
- [ ] `tests/test_user_agent_parser.py` - New Brave detection has no parametrized test cases
- [ ] Missing CHANGELOG.md entry for new feature
### 🟢 Suggestions (nice to have)
- [ ] `user_agent_parser/parser.py:90` - Add type hint to `get_device_name()` return
- [ ] `user_agent_parser/advanced_engine.py:45` - Browser detection duplicates logic from parser.py — consider reuse
---
**Verdict:** APPROVE | REQUEST_CHANGES | COMMENT
*Review based on project standards in CLAUDE.md*
Step 5: Determine Verdict
| Condition | Verdict |
|---|
| No critical issues, 0-2 standards issues | APPROVE |
| No critical issues, 3+ standards issues | COMMENT |
| Any critical issues | REQUEST_CHANGES |
Step 6: Post Comment (if --comment)
Based on verdict:
gh pr review <number> --approve --body "$(cat <<'EOF'
<review-report>
EOF
)"
gh pr review <number> --comment --body "$(cat <<'EOF'
<review-report>
EOF
)"
gh pr review <number> --request-changes --body "$(cat <<'EOF'
<review-report>
EOF
)"
Quick Reference: What to Check by File
| File | Key Checks |
|---|
parser.py | Regex correctness, browser_rules order, _token bounds, lru_cache mutation, compiled pattern caching |
advanced_engine.py | AdvancedResult field stability, confidence bounds [0,1], DeviceCategory enum stability, ThreadPoolExecutor cleanup |
analytics.py | Thread safety in BatchProcessor, export format correctness |
constants.py | No changed existing values, consistent MOBILE_DEVICE_CODE_NAME format, no duplicate keys |
modern_devices.py | DeviceSpec format consistency |
__init__.py | Public API unchanged, all consistent, parse() 7-tuple preserved |
tests/*.py | Parametrized with real UA strings, edge cases covered, backward compat verified |
CHANGELOG.md | Entry exists for non-trivial changes |
.github/workflows/* | Python version matrix includes 3.8–3.15, codecov integration intact |
pyproject.toml | Python requirement still >=3.8, no incompatible dependency versions |