PR Checklist
This checklist is mandatory self-review before requesting a code review. CI runs most of it, but a human must read it first — otherwise reviewers wait for CI to go red and the loop wastes everyone's time.
Three layers
- Machine-verifiable — auto-run (typecheck, lint, test, bench).
- Human cognition — scope, naming, readability, design.
- Architectural discipline — layering, anti-corruption, undo path. Pass all three before requesting review.
Automated checks
pnpm typecheck # tsc + tsc -p tsconfig.electron.json
pnpm lint # ESLint
pnpm format:check # Prettier
pnpm test # Vitest run
pnpm bench # Vitest bench
node scripts/check-bench-budget.mjs bench-results.json
pnpm build:web # production build sanity
pnpm docs:build # if docs changed2
3
4
5
6
7
8
pnpm typecheck runs two tsc invocations (web and Electron). Forgotten Electron-side type slips are common — keep both green.
Scope discipline
One PR = one thing
- Bug fix: don't drive-by refactor.
- Feature: don't smuggle a dep upgrade.
- 50-file rename: standalone PR.
Cross-scope "cleanups"
See ugly code? File an issue and leave it alone in this PR. Reasons:
- Review focus shatters.
- Rollback drags innocent code along.
- Authorship is muddy (does the test cover the feature or the cleanup?).
PR size guidance
| Size | Impact |
|---|---|
| ≤ 200 lines | review feedback within an hour |
| 200–500 lines | half a day to a day |
| 500–1000 lines | split, or progress slips |
| > 1000 lines | must split (rename / upgrade aside) |
Commit messages
Every commit must follow Commit Conventions:
- type + scope + subject.
- body explains why.
- one commit = one thing.
- no
Co-Authored-By. - husky
commit-msgpasses.
Layering rule
components/ ← UI
↓
hooks/
↓
store/
↓
lib/
↓
core/2
3
4
5
6
7
8
9
No reverse imports. Audit:
grep -R "from '@/components/" src/core/ src/lib/ src/store/ src/hooks/
grep -R "from '@/hooks/" src/core/ src/lib/ src/store/
grep -R "from '@/store/" src/core/ src/lib/
grep -R "from '@/lib/" src/core/
# All MUST be empty.2
3
4
5
Anti-corruption audit
Anything touching Apollo proto must go through entityOps, never import @/core/geometry/apolloCompile directly.
git grep "from '@/core/geometry/apolloCompile'" -- 'src/components/**' 'src/hooks/**'
# Empty.2
A non-empty result = you introduced a new leak. Fix before merging. See Architecture: Anti-corruption Layer.
Undo path (R1)
Any code that mutates mapStore entities:
See State Management R1.
Performance
Tests
New feature:
Bug fix:
UI changes
Screenshot tools
- macOS:
Cmd+Shift+4for region. - Linux:
gnome-screenshot -aorflameshot. - Recording:
peek(Linux) /Cmd+Shift+5(macOS).
Documentation
Bilingual drift
zh and en must stay in lockstep. Updating one but not the other earns a complaint within a week. If you can only do one side, prefix the PR title with [zh-only] / [en-only] and open a follow-up issue.
Licensing
CI red — what now?
In order:
- Type errors — fix types, don't
as any. - Lint errors —
pnpm lint:fix, then manual. - Format errors —
pnpm format. - Test failures — read stderr, reproduce locally, fix.
- Bench regression — improve algorithm, or justify and adjust the budget.
- Build errors — usually cross-platform (paths, line endings).
Never --no-verify
Bypassing husky or force-pushing to main destroys team trust. Fix the problem and re-push.
PR description template
## Summary
- One-sentence goal
- Key change 1
- Key change 2
## Motivation
- Background or issue link
## Implementation notes
- Why this approach
- Comparison with alternatives
- Known trade-offs
## Screenshots / capture
(Mandatory for UI changes)
## Test plan
- [ ] pnpm test
- [ ] pnpm bench guard
- [ ] Manual X / Y / Z
- [ ] Cross-platform (if applicable)
## Checklist
- [ ] Bilingual docs synced (if applicable)
- [ ] New dep < 100 KB (if applicable)
- [ ] anti-corruption audit clean
- [ ] Undo path manually verified2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
Self-review
Before pushing, read your own diff end-to-end:
One habit
git diff main and read top to bottom. If you can't, the diff is too big or the logic too tangled — split or simplify first.
Common rejection reasons
| Reason | Fix |
|---|---|
| PR changes too many things | Split |
| No undo regression test | Add undoCancel-style test |
| Direct apolloCompile import | Route through entityOps |
| Function > 80 lines | Decompose |
| File > 400 lines | Sibling-module split |
| Tests only happy path | Add at least one edge case |
as unknown as | Use a type guard |
wip / fix typo commit | Rewrite conventional |
| Bilingual docs drift | Sync the other side |
Source links
Don't pass review for review's sake
If you address a comment cosmetically just to merge, the same bug will return in 6 months. Treat reviews as learning — understand before fixing.