self-review
Pre-PR self-review checklist to catch recurring Copilot review comment patterns before pushing. Use when asked to self-review, run pre-PR review, or before creating a PR to reduce review back-and-forth. Walks through the diff against PATTERNS.md.
Install
mkdir -p .claude/skills/self-review && curl -L -o skill.zip "https://agentskills.codes/api/skills/download/15312" && unzip -o skill.zip -d .claude/skills/self-review && rm skill.zipInstalls to .claude/skills/self-review
Activation
This is the description your AI agent reads to decide when to run this skill — the better it matches your request, the more reliably it fires.
Pre-PR self-review checklist to catch recurring Copilot review comment patterns before pushing. Use when asked to self-review, run pre-PR review, or before creating a PR to reduce review back-and-forth. Walks through the diff against PATTERNS.md.About this skill
Self-Review
Run this skill before creating any PR. It walks the diff against the known Copilot comment patterns in PATTERNS.md to catch issues before review.
When to Use
- As required by the
create-prskill's Step 0 gate - When asked to "self-review", "run pre-PR review", or "check for review issues"
Procedure
1. Get the diff
git diff $(git merge-base HEAD origin/main) HEAD -- . ':(exclude)agent-workspace' ':(exclude)*.png' ':(exclude)*.jpg' ':(exclude)*.jpeg' ':(exclude)*.gif' ':(exclude)*.webp' ':(exclude)*.svg' ':(exclude)*.ico'
git diff --stat $(git merge-base HEAD origin/main) HEAD -- . ':(exclude)agent-workspace' ':(exclude)*.png' ':(exclude)*.jpg' ':(exclude)*.jpeg' ':(exclude)*.gif' ':(exclude)*.webp' ':(exclude)*.svg' ':(exclude)*.ico'
Read the stat output to understand which file types changed.
2. For each changed TypeScript / TSX file — apply these patterns
P1 — Comment/Implementation Mismatch
- Every block comment above a condition or calculation describes what the code actually does.
- Every JSDoc
@param/@returns/ field description matches the current implementation. - Test
it(...)/describe(...)descriptions accurately reflect what is being asserted. - After a rename, search for the old name in comments (for example,
git grep -n '<old_identifier>'). - JSDoc
@returnsprecision: qualitative terms like "snapped to nearest" or column names like "URI column" match the actual implementation semantics.
P5 — Wrong Variable / Wrong Denominator
- In any percentage/ratio calculation: is the denominator the concept it claims to measure?
- After adding a new data path (e.g. continuation lines in a parser), re-read every variable whose length or count the new data can change.
P8 — Floating Promises / Missing Error Handling
- Every
.then(...).catch(...)chain is either returned, awaited, or prefixed withvoid. navigator.clipboard, fetch, and storage calls havetry/catch.navigate()(react-router) is neverawaited.URL.revokeObjectURLis deferred tosetTimeout(..., 0), not called synchronously aftera.click().localStorage.getItem/setItem/removeIteminuseEffector startup paths are wrapped intry/catch(can throw aDOMException, e.g.SecurityError/QuotaExceededError, when storage access is blocked or quota is zero).- New file-processing paths apply the same validation gates (file-size limit, type guard) as existing paths.
P9 — ARIA Role / Keyboard Interaction Gaps
- No element carries
role="menu"/role="menuitem"without full arrow-key + Escape keyboard handling. - New interactive list rows use
tabIndex={-1}(roving tabindex), nottabIndex={0}on every item. - Every symbol-only
<button>hasaria-label.
P10 — Algorithm Complexity
- No
.find()/.filter()inside an outer loop over requests or log lines (pre-build a Map). - No Map or index rebuilt on every call that could be computed once.
- Binary search used where available; linear scan only for small inputs.
Math.max(...array)/Math.min(...array)on large arrays → useforloop or.reduce(); large spreads can hit engine-specific maximum argument limits.- New
Uint8Arraycopies via.buffer.slice()→ prefer.subarray()(zero-copy) or passUint8Arraydirectly toBlob.
P11 — State Update / Close-Handler Edge Cases
- Close callbacks use functional state updates (
prev => prev === thisItem ? null : prev). - No
onCloseunconditionally sets state tonullthat could clobber a concurrent open. - A
useEffectthat re-fetches on a reactive key change (e.g.userId) clears the prior result at effect start to prevent stale data showing during the new request.
P12 — Type Mutability
- All new domain type properties (in
src/types/) arereadonly. - Shared empty/default constants return fresh objects, not shared mutable references.
- Read-only parameters typed as
ReadonlyArray<T>where applicable.
P13 — Code Duplication
- Before writing a new helper or regex, search the codebase for an existing one (for example with
git greporrg). - No new
formatBytes, timestamp-strip regex, or log-line matcher that already exists insrc/utils/.
P14 — Regex Over- or Under-Matching
- HTTP status code regexes use
\d{3}(exactly 3), not\d{3,}. - Timestamp-strip regexes accept the same variation as
extractISOTimestampinlogParser.ts(with/without fractional seconds, with/withoutZ). - Truthy checks (
if (x.field)) not used where0or''are valid non-missing values. - Format detection and format parser operate on the same string form (trimmed vs raw); detecting on trimmed but parsing raw causes all-UNKNOWN output.
- Regex character classes for enum-like token types enumerate all members (e.g. logcat priorities:
V D I W E F A— not missingA).
P17 — useCallback / useMemo Stale Dependency Array
- Every
useCallbackanduseMemodep array includes all closed-over state, props, and store-selector results. - Check for
// eslint-disable-next-line react-hooks/exhaustive-depssuppressions that could be hiding a stale dep. - For stable callbacks that intentionally omit deps, ensure the omitted value is read via
useReforuseLogStore.getState()at call time.
P18 — Keyboard Event code vs key for Character Shortcuts
e.code === 'KeyX'for character-intention shortcuts (wrap, print, save) → replace withe.key.toLowerCase() === 'x'.e.codeis correct only for layout-independent physical keys ('Escape','Enter','Space', arrow keys, etc.).
3. For each changed CSS file — apply these patterns
P2 — CSS Magic Numbers / Duplicated Computed Values
- Any pixel value that is a sum of column widths or other layout values → define CSS custom properties, use
calc(). - Hard-coded colors → use CSS variable tokens from
foundation.css.
P3 — CSS Whitespace / Overflow Interaction Bugs
- Elements in "wrap" mode use
white-space: pre-wrap; "nowrap" variants override topre. overflow: hiddendoes not silently clip content that should scroll in nowrap mode.
P4 — CSS Accessibility / Pointer-Events
pointer-events: noneon a container: verify no interactive child needs hover/click. If so, addpointer-events: autoon that child.aria-labelon an element → element must have a matchingroleor be a native interactive element.- Check color contrast for any new text-on-background combination, especially in the dark log viewer (
--text-secondaryon dark bg).
4. For each changed test file — apply these patterns
P6 — Test Fixture Incompleteness
- Log-line fixtures set
isoTimestamp,displayTime, andmessageto values matching real parser output (full first physical line with timestamp+level prefix). - Filter tests that say a request "should appear" actually include the filter keyword in the fixture's
rawText. - Test comments accurately describe the fixture structure (line counts, field values).
- Virtualizer mocks (
getVirtualItems) includeend(=start + size) matching the real TanStack virtualizer shape. - When a utility gains a new side-effect call (e.g.
setLogFileName), the happy-path test adds a matching assertion. - Inline test literals typed as domain interfaces include all required fields; tsc excludes test files so gaps compile silently.
P7 — Test Isolation / Mock Leakage
- Any
beforeEachthat overwrites a global (navigator.clipboard,URL.createObjectURL, etc.) has a matchingafterEachthat restores the original (captured in aletbefore overwriting —vi.restoreAllMocks()does NOT restore property assignments). - Fake timer tests flush pending timers before switching back to real timers.
- Zustand store state is reset between tests.
- Interactive element tests use
userEvent.hoverbeforeuserEvent.clickwhen a trigger is only visible on hover. HTMLElement.prototypeproperty restores inafterEachuseObject.getOwnPropertyDescriptor+Object.defineProperty, not assignment to a fixed value.
P16 — Test Spec Coherence
- For UI tests that act as specification, the title describes a user-observable scenario. For integration tests, the title describes the public contract at that boundary.
- For hook tests, the title describes the hook interface contract or side-effect, not listener bookkeeping or branch-coverage intent.
- The fixture/setup actually creates the scenario the title claims (for example, matching URL params, filter text, or rendered labels).
- The assertions verify that same scenario rather than drifting into unrelated helper internals or store plumbing.
- A specific title needs a specific assertion: if the test says a formatted label, count, or state transition should appear,
expect(...).toBeInTheDocument()on a generic container/button is not enough. - Querying by role, label, or
data-testidis fine when those are part of the contract; drilling into CSS classes or container structure just to prove existence is usually too indirect. - Pure utility/algorithm tests may stay implementation-oriented, but their title, setup, and assertions still need to describe the same case.
- Branch-coverage language (
covers ...,idx=1, line numbers) is a smell in behavior tests; prefer naming the actual scenario. - P16 complements P1, P6, and P7: use it for title/setup/assertion drift, not wording-only mismatches, incomplete fixtures, or leaking mocks.
5. For each changed Markdown / docs / skill file — apply this pattern
P15 — Documentation / Skill Internal Consistency
- Sequential dependencies: if step N uses an artifact (e.g.
pr-body.md, a built file), confirm that artifact exists at the point step N runs — not only in a later step. - Command / tool names: every shell command referenced in prose must be real and executable. Verify with
which <cmd>orgit grepin the repo scripts if unsure. - Repo-specific syntax: CSS selectors, naming conventions,
Content truncated.