@clipboard-health/ai-rules 2.25.1 → 2.26.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/package.json +1 -1
- package/rules/common/coreLibraries.md +0 -1
- package/skills/babysit-pr/SKILL.md +4 -4
- package/skills/babysit-pr/scripts/_sentinel.sh +1 -1
- package/skills/commit-push-pr/SKILL.md +2 -2
- package/skills/in-depth-review/SKILL.md +491 -0
- package/skills/in-depth-review/references/cross-repo-evidence.md +37 -0
- package/skills/in-depth-review/references/posting-pr-review.md +105 -0
- package/skills/simple-review/SKILL.md +472 -0
- package/skills/simple-review/references/cross-repo-evidence.md +64 -0
- package/skills/simple-review/references/posting-pr-review.md +100 -0
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
# Cross-repo evidence policy (binding for all agents)
|
|
2
|
+
|
|
3
|
+
Read this before raising or finalizing any finding whose evidence may live outside the repo containing the diff. Referenced from `SKILL.md`.
|
|
4
|
+
|
|
5
|
+
A finding's evidence is "cross-repo" when it depends on code in any repo other than the one containing the diff. Examples: the diff is in `clipboard-health` but the finding claims that `cbh-admin-frontend`, `payment-service`, or `worker-service-backend` still calls a deprecated endpoint.
|
|
6
|
+
|
|
7
|
+
**Subagents must NOT silently read external repos.** Doing so risks (a) reading a stale local checkout and fabricating evidence (see "Freshness preflight"), or (b) citing a path the user has no checkout of, which the moderator can't verify.
|
|
8
|
+
|
|
9
|
+
Subagent rule: if a finding's load-bearing evidence is in another repo, the subagent must emit the finding with the additional field:
|
|
10
|
+
|
|
11
|
+
```json
|
|
12
|
+
"evidence_required": {
|
|
13
|
+
"repos": ["cbh-admin-frontend", "payment-service"],
|
|
14
|
+
"what_to_verify": "concrete grep / file path / question the moderator should answer to confirm or kill the finding"
|
|
15
|
+
}
|
|
16
|
+
```
|
|
17
|
+
|
|
18
|
+
…and cap the finding's severity at **MAJOR**. Findings marked `evidence_required` cannot be CRITICAL until the moderator has confirmed the cross-repo evidence on a verified-fresh ref.
|
|
19
|
+
|
|
20
|
+
Moderator rule: after Round 1, collect every `evidence_required` block across all subagents and ask the user **before Round 2**:
|
|
21
|
+
|
|
22
|
+
> Some findings depend on code outside `<primary-repo>`. To verify, I need access to:
|
|
23
|
+
>
|
|
24
|
+
> - `<repo-1>` — to check `<what_to_verify>` (raised by agent <X>)
|
|
25
|
+
> - `<repo-2>` — to check `<what_to_verify>` (raised by agent <Y>)
|
|
26
|
+
>
|
|
27
|
+
> For each repo, reply with one of:
|
|
28
|
+
>
|
|
29
|
+
> - a local path (e.g. `/Users/you/repos/cbh/<repo>`) — I will run the freshness preflight on it before reading
|
|
30
|
+
> - `gh:<owner>/<repo>` — I will fetch the file content via `gh api repos/<owner>/<repo>/contents/<path>?ref=main` instead of cloning
|
|
31
|
+
> - `skip` — the finding will be downgraded to "speculative — cross-repo evidence not verified" and capped at MINOR
|
|
32
|
+
>
|
|
33
|
+
> Or reply `skip all` to downgrade every cross-repo finding.
|
|
34
|
+
|
|
35
|
+
For each user-provided local path, run the **same freshness preflight** as on the primary repo (fetch, check ahead/behind, check working-tree cleanliness). If the external repo is stale or on a non-default branch, warn with the same template and require explicit user acknowledgement before reading. Always read external code via `git show "${external_context_ref}:<path>"` / `git grep ... "${external_context_ref}" -- <paths>`, never via the worktree filesystem.
|
|
36
|
+
|
|
37
|
+
After verification, re-dispatch only the affected subagents (one agent per repo group) with the verified evidence (or its absence) inlined, so they can finalize severity for Round 2. Findings whose cross-repo evidence the user `skip`s are kept but capped at MINOR with a "speculative" prefix in the title.
|
|
@@ -0,0 +1,105 @@
|
|
|
1
|
+
# Posting an anchored PR review (both modes)
|
|
2
|
+
|
|
3
|
+
Read this once the user approves items to post. Referenced from `SKILL.md`.
|
|
4
|
+
|
|
5
|
+
## Contents
|
|
6
|
+
|
|
7
|
+
- API call and payload shape
|
|
8
|
+
- Review body (top-level comment): attribution line, synthesis summary, apply-all prompt
|
|
9
|
+
- Each comment body: budget, template, formatting rules
|
|
10
|
+
|
|
11
|
+
## API call and payload
|
|
12
|
+
|
|
13
|
+
Always post via the GitHub Reviews API as a **single** review, with all selected actionable items as inline review comments anchored to specific diff lines. **Never** loose issue comments.
|
|
14
|
+
|
|
15
|
+
Build the payload as JSON and pipe it through `gh api --input`:
|
|
16
|
+
|
|
17
|
+
```bash
|
|
18
|
+
# /tmp/in-depth-review-payload.json contains: {event, commit_id, body, comments: [...]}
|
|
19
|
+
gh api -X POST "repos/<owner>/<repo>/pulls/<N>/reviews" --input /tmp/in-depth-review-payload.json
|
|
20
|
+
```
|
|
21
|
+
|
|
22
|
+
Payload shape:
|
|
23
|
+
|
|
24
|
+
```json
|
|
25
|
+
{
|
|
26
|
+
"event": "COMMENT",
|
|
27
|
+
"commit_id": "<head_sha>",
|
|
28
|
+
"body": "<summary>",
|
|
29
|
+
"comments": [
|
|
30
|
+
{ "path": "src/foo.ts", "line": 42, "side": "RIGHT", "body": "..." },
|
|
31
|
+
{
|
|
32
|
+
"path": "src/bar.ts",
|
|
33
|
+
"start_line": 10,
|
|
34
|
+
"line": 14,
|
|
35
|
+
"start_side": "RIGHT",
|
|
36
|
+
"side": "RIGHT",
|
|
37
|
+
"body": "..."
|
|
38
|
+
}
|
|
39
|
+
]
|
|
40
|
+
}
|
|
41
|
+
```
|
|
42
|
+
|
|
43
|
+
Rules for posting:
|
|
44
|
+
|
|
45
|
+
- `event` is **always `COMMENT`** — never `APPROVE` or `REQUEST_CHANGES`. Approval / blocking is a human decision, not the skill's.
|
|
46
|
+
- For multi-line ranges, set `start_line`, `line`, `start_side: "RIGHT"`, `side: "RIGHT"`.
|
|
47
|
+
- For findings without a clean line anchor (rare), pick the first changed line of the most relevant file rather than dropping the comment or going loose.
|
|
48
|
+
- If literally nothing is anchorable for a given finding, fold it into the review `body` as a labeled "general note" and flag this in the post-confirmation summary so the user knows.
|
|
49
|
+
- Use `commit_id` from `pr.headRefOid` so comments anchor to the reviewed commit.
|
|
50
|
+
- Resolve `<owner>/<repo>` once via `gh repo view --json nameWithOwner --jq .nameWithOwner` and stash it in `/tmp/in-depth-review-meta.json` alongside `head_sha` so permalinks below can be built without re-querying.
|
|
51
|
+
|
|
52
|
+
## Review body (top-level comment)
|
|
53
|
+
|
|
54
|
+
The `body` field on the review (not the inline comment bodies) must contain three blocks, in order:
|
|
55
|
+
|
|
56
|
+
**1. Attribution line.** A single sentence disclosing that the review was generated by Claude Code. Use exactly:
|
|
57
|
+
|
|
58
|
+
> _These comments were generated by @\<viewer-login\> using Claude Code._
|
|
59
|
+
|
|
60
|
+
Substitute `<viewer-login>` from `gh api user --jq .login`. Italicize the line so it renders as muted text. This is non-negotiable — collaborators must be able to tell at a glance that the review is AI-assisted. Do **not** mention the In-Depth Review skill by name; it's a local skill the PR author can't see or use.
|
|
61
|
+
|
|
62
|
+
**2. Synthesis Summary.** The same one-paragraph summary printed in the in-chat synthesis: what the change does and your recommendation. Do not include mode, per-agent headline verdicts, or which agents ran — that's methodology noise.
|
|
63
|
+
|
|
64
|
+
**3. "Apply all comments at once" prompt.** A fenced block containing a self-contained Claude Code prompt the PR author (or any agent operator) can copy-paste into a Claude Code session on a checkout of this branch to address every inline comment in one shot. Template (substitute the `<…>` placeholders before posting):
|
|
65
|
+
|
|
66
|
+
````markdown
|
|
67
|
+
**Apply all comments at once** — paste this into Claude Code on a checkout of this branch:
|
|
68
|
+
|
|
69
|
+
```
|
|
70
|
+
Fetch the most recent review by @<viewer-login> on PR <PR_URL>. For every inline comment in that review, address the issue: when the comment includes a `suggestion` block, apply it verbatim; otherwise implement an equivalent fix that satisfies the comment's "Why it matters" rationale. After resolving each thread, post a reply on that thread with a one-line summary of what you changed. When all comments are handled, run the project's tests, commit the changes with a message that references the review, and report back any threads you could not resolve and why.
|
|
71
|
+
```
|
|
72
|
+
````
|
|
73
|
+
|
|
74
|
+
Build the body in `/tmp/in-depth-review-payload.json` with literal newlines (use `jq -n --arg body "$BODY" '{body: $body, ...}'` or build the JSON via a small heredoc-fed `python -c` so newlines are real `\n` in the JSON string, not the two characters `\` `n`).
|
|
75
|
+
|
|
76
|
+
## Each comment body
|
|
77
|
+
|
|
78
|
+
**Budget:** ≤60 words of prose total + the code block. The hard caps below are binding — if a section won't fit, the finding is probably two findings; split or drop one.
|
|
79
|
+
|
|
80
|
+
````markdown
|
|
81
|
+
**[SEVERITY] Title** <!-- ≤8 words -->
|
|
82
|
+
|
|
83
|
+
<Point — 1 sentence, ≤25 words. Any reference to a specific file/line elsewhere in the codebase must be a GitHub permalink pinned to head_sha, not a bare `file:lines` string. The line(s) the comment is already anchored to do not need to be relinked.>
|
|
84
|
+
|
|
85
|
+
**Why it matters:** <failure_mode — 1 sentence, ≤20 words. **Drop this line entirely** when it would only rephrase the Point.>
|
|
86
|
+
|
|
87
|
+
**Suggested fix:**
|
|
88
|
+
|
|
89
|
+
```suggestion
|
|
90
|
+
<suggested_fix.after — replaces the anchored line(s); GitHub renders the diff vs. the anchored line(s) AND an "Apply suggestion" button>
|
|
91
|
+
```
|
|
92
|
+
````
|
|
93
|
+
|
|
94
|
+
Rules for code and links inside the comment body:
|
|
95
|
+
|
|
96
|
+
- **No bulleted lists in the comment body.** Bullets fragment reasoning; either the prose fits in one sentence or it doesn't belong on the PR.
|
|
97
|
+
- **No prose preamble on the suggested fix.** The code block speaks for itself — don't write "Suggested fix — route Rate the same way as Pay" before the block; just show the block.
|
|
98
|
+
- **No trailing addenda.** "If feature X isn't shipped yet…", "Note that this also affects…", "While you're here…" — these belong in the in-chat synthesis, not on the posted comment. The reviewee can ask follow-ups on the thread.
|
|
99
|
+
- **Include a `suggestion` block whenever it makes the fix concrete.** Skip it only when the issue is purely structural or when prose alone says everything.
|
|
100
|
+
- **`suggestion` block stands alone on the PR.** GitHub already renders the diff vs. the anchored line(s) inside the suggestion block (red `-` lines + green `+` lines + one-click apply). Do **NOT** also include a `// Before` fenced block — it duplicates what GitHub already shows and makes the comment twice as long. This is different from the in-chat **Actionable** section, which DOES render `// Before` + `// After` pairs so the user can review the change before approving the post (the user has no GitHub renderer in their terminal).
|
|
101
|
+
- **When to skip the `suggestion` block:** the fix is structural with no clean drop-in (e.g. "move this file"), OR `suggested_fix.after` is empty (pure deletion — write "_Delete the anchored line(s)._" instead), OR `suggested_fix.before` is empty (pure addition — the `suggestion` block still works, but prefix `suggested_fix.after` with a `// Add after line <N>` comment so the intent reads cleanly).
|
|
102
|
+
- **Optional Example/context fenced block is opt-out by default.** Include a non-`suggestion` code block only when prose-plus-`suggestion` is genuinely ambiguous — e.g. you're flagging a pattern violation and the offending pattern is not in the anchored lines. Render it under an **Example / context:** heading as a regular language-tagged fenced block, with a permalink in the prose above pointing to where it lives in the tree. If you're tempted to paste the anchored lines as "context," you're rebuilding the `// Before` block GitHub already renders — drop it. Default: skip.
|
|
103
|
+
- **Permalinks for in-prose line references.** Build them as `https://github.com/<owner>/<repo>/blob/<head_sha>/<path>#L<start>-L<end>` (single line: `#L<n>`). Always pin to `head_sha`, never `main` or a branch name — branch links break as soon as the branch moves. Use Markdown link syntax with a short, meaningful label (e.g. `[the existing ServiceResult pattern](https://github.com/...#L88-L104)`), not the raw URL.
|
|
104
|
+
|
|
105
|
+
After posting, print the review `html_url` and a one-line summary of how many comments were posted (and how many fell back to general notes, if any).
|
|
@@ -0,0 +1,472 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: simple-review
|
|
3
|
+
description: Single-pass code review of the current branch or a PR using the in-depth review rubric without subagents, posted as anchored PR comments. Use when the user asks to review a small or medium diff, wants a fast or low-budget review, or runs /simple-review [PR-number-or-URL]. For large or high-stakes diffs that benefit from multiple debating reviewers, use in-depth-review instead.
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# Simple Review
|
|
7
|
+
|
|
8
|
+
Single-pass code review you (the main agent) perform yourself — **no subagents**. Condenses the rules from `/in-depth-review` into one checklist you walk through directly. Use this for small/medium PRs and when budget matters. Use `/in-depth-review` instead when the diff is large, high-stakes, or benefits from independent perspectives that can debate.
|
|
9
|
+
|
|
10
|
+
## Invocation
|
|
11
|
+
|
|
12
|
+
- **`/simple-review`** — review the current branch (resolves the open PR for the branch if any, otherwise diffs against the default branch).
|
|
13
|
+
- **`/simple-review <PR-number-or-URL>`** — fast path for reviewing someone else's PR while sitting on `main` (typical entry from a worktree). Skips local branch checkout, fetches diff/metadata via `gh`, forces **reviewer mode**, skips the plan/execute path. Accepts a bare number (current repo) or full GitHub URL (identifies owner/repo).
|
|
14
|
+
|
|
15
|
+
## Scope
|
|
16
|
+
|
|
17
|
+
### Path A — PR-argument fast path (argument provided)
|
|
18
|
+
|
|
19
|
+
- Parse the argument: bare integer → `gh repo view --json nameWithOwner --jq .nameWithOwner`; URL → extract `<owner>/<repo>` and `<N>`.
|
|
20
|
+
- Do **not** check out the PR branch.
|
|
21
|
+
- Mode is **locked to reviewer**.
|
|
22
|
+
|
|
23
|
+
Gather in parallel:
|
|
24
|
+
|
|
25
|
+
```bash
|
|
26
|
+
gh pr view <N> --repo <owner>/<repo> --json number,url,title,body,baseRefName,author,headRefOid,files
|
|
27
|
+
gh pr diff <N> --repo <owner>/<repo>
|
|
28
|
+
gh api user --jq .login
|
|
29
|
+
```
|
|
30
|
+
|
|
31
|
+
If `pr.author.login == viewer.login`, still proceed in reviewer mode but flag this in Summary so the user can switch to a manual `/simple-review` run on their checkout if they meant to implement.
|
|
32
|
+
|
|
33
|
+
### Path B — current-branch path (no argument)
|
|
34
|
+
|
|
35
|
+
- Open PR for current branch → review that PR. Base = `baseRefName`, diff = `git diff $base...HEAD`. Context = PR title + body.
|
|
36
|
+
- No PR → diff vs default branch (`main`, fall back to `master`). Context = `git log --format='%h %s%n%n%b' $base..HEAD`.
|
|
37
|
+
- **Never** review uncommitted working-tree changes. Empty diff → stop and report.
|
|
38
|
+
|
|
39
|
+
Determine **mode**:
|
|
40
|
+
|
|
41
|
+
- PR exists and `pr.author.login == viewer.login` → **author mode**.
|
|
42
|
+
- PR exists and authors differ → **reviewer mode**.
|
|
43
|
+
- No PR → **author mode**.
|
|
44
|
+
|
|
45
|
+
You hold everything in-context — no `/tmp/*` persistence needed.
|
|
46
|
+
|
|
47
|
+
## Freshness preflight (mandatory before reading code)
|
|
48
|
+
|
|
49
|
+
Stale local state produces false-positive findings. Before reviewing, verify the ref you'll read for context is current.
|
|
50
|
+
|
|
51
|
+
Run on the **primary repo** (the one containing the diff):
|
|
52
|
+
|
|
53
|
+
```bash
|
|
54
|
+
git fetch origin "$base" --quiet
|
|
55
|
+
git rev-parse --abbrev-ref HEAD
|
|
56
|
+
git status --porcelain
|
|
57
|
+
git rev-list --left-right --count "HEAD...origin/${base}"
|
|
58
|
+
git log -1 --format='%h %ci' "origin/${base}"
|
|
59
|
+
```
|
|
60
|
+
|
|
61
|
+
Decide `context_ref`:
|
|
62
|
+
|
|
63
|
+
- **Path A (reviewer):** `context_ref = origin/${base}` (usually `main`). Worktree may be used only when `HEAD == origin/${base}` AND clean AND fetch succeeded.
|
|
64
|
+
- **Path B (author):** `context_ref = origin/${base}`. The local feature branch IS the diff; pre-PR context comes from `origin/${base}`.
|
|
65
|
+
|
|
66
|
+
Stop and ask the user when:
|
|
67
|
+
|
|
68
|
+
1. `git fetch` failed (offline, auth).
|
|
69
|
+
2. `HEAD` differs from `origin/${base}` on Path A.
|
|
70
|
+
3. Working tree is dirty AND dirty paths overlap the diff's changed-file list or anything you'll need to read.
|
|
71
|
+
4. `HEAD` is behind `origin/${base}` (any non-zero "behind").
|
|
72
|
+
5. `HEAD` is more than a small number of commits ahead of `origin/${base}` on Path A.
|
|
73
|
+
|
|
74
|
+
Warn template (substitute verified state):
|
|
75
|
+
|
|
76
|
+
> Freshness check for `<owner>/<repo>` at `<worktree-path>`:
|
|
77
|
+
>
|
|
78
|
+
> - on branch `<HEAD-branch>` (expected `<base>` for Path A)
|
|
79
|
+
> - `<N>` ahead, `<M>` behind `origin/<base>` (last: `<short-sha> <iso-date>`)
|
|
80
|
+
> - working tree: `<clean | dirty: N file(s)>`
|
|
81
|
+
>
|
|
82
|
+
> Reading from this worktree may surface findings based on stale state.
|
|
83
|
+
> Reply: `proceed` (use worktree, accept the risk), `use-origin` (read context via `git show origin/<base>:<path>` — recommended), or `stop`.
|
|
84
|
+
|
|
85
|
+
**Never** run `git checkout`, `stash`, `reset`, or other state-modifying git on the user's behalf. The skill warns and asks; the user resolves local state. `git fetch` is allowed (read-only).
|
|
86
|
+
|
|
87
|
+
For Path A PR review when the worktree is dirty or on a non-base branch, the practical workaround is to fetch the PR head to a local ref:
|
|
88
|
+
|
|
89
|
+
```bash
|
|
90
|
+
git fetch origin "pull/<N>/head:refs/remotes/origin/pr-<N>" --quiet
|
|
91
|
+
```
|
|
92
|
+
|
|
93
|
+
Then read PR-head content via `git show origin/pr-<N>:<path>` and base context via `git show origin/<base>:<path>`. No checkout needed.
|
|
94
|
+
|
|
95
|
+
### Reading code
|
|
96
|
+
|
|
97
|
+
When `context_ref = origin/<base>` (or `origin/pr-<N>` for PR head):
|
|
98
|
+
|
|
99
|
+
- Read via `git show "${context_ref}:<path>"` (whole files) or `git grep -n <pattern> "${context_ref}" -- <paths>` (search).
|
|
100
|
+
- Avoid the Read tool on the worktree filesystem for tracked content — it may be stale.
|
|
101
|
+
- Worktree Read is OK only for files brand-new in the diff (untracked at `context_ref`); note "verified against: worktree" in the finding.
|
|
102
|
+
|
|
103
|
+
When `context_ref = worktree (stale, user accepted risk)`:
|
|
104
|
+
|
|
105
|
+
- Read tool is OK but every CRITICAL/MAJOR finding is downgraded to MINOR unless evidence is internal to the diff itself. Tag each finding with "verified against: worktree-stale".
|
|
106
|
+
|
|
107
|
+
## Cross-repo evidence policy
|
|
108
|
+
|
|
109
|
+
A finding's evidence is "cross-repo" when its load-bearing claim depends on code in any repo other than the one containing the diff — most commonly a consumer, producer, or downstream parser of something the diff changes. **Never silently read external repos and never claim a downstream impact you have not verified** — speculating that "the FE will break" without reading the consumer is a top source of false-positive findings. Cap any cross-repo finding at **MAJOR** until verified.
|
|
110
|
+
|
|
111
|
+
Read [references/cross-repo-evidence.md](references/cross-repo-evidence.md) before raising or finalizing any cross-repo finding — it has when the policy fires, the verify-or-downgrade procedure, the access-request template, and what "verify" means for contract/schema vs API-response changes.
|
|
112
|
+
|
|
113
|
+
## Diff classification (pick which lenses apply)
|
|
114
|
+
|
|
115
|
+
Walk the changed-file list. Activate lenses that match:
|
|
116
|
+
|
|
117
|
+
- **Security lens** triggers on: `routes/`, `controllers/`, `middleware*/`, files matching `auth*`/`*permission*`/`*acl*`/`*token*`/`*session*`, response serializers, OpenAPI/contract definitions, new API endpoint files.
|
|
118
|
+
- **Database lens** triggers on: `migrations/`, `*.sql`, files matching `schema*`, Mongoose/Prisma model files (`models/`, `*.model.ts`, `*.schema.ts`), repository/DAL files, query builders.
|
|
119
|
+
- **Frontend lens** triggers on: `*.tsx`, `*.jsx`, `*.css`, `*.scss`, `pages/`, `components/`, `hooks/`, or anything importing from `react`, `@tanstack/react-query`, or a design-system package.
|
|
120
|
+
|
|
121
|
+
Always-on lenses: **Engineering**, **Minimalism**, **Conventions**, **AntiSlop**.
|
|
122
|
+
|
|
123
|
+
## Severity rubric (binding)
|
|
124
|
+
|
|
125
|
+
- **CRITICAL** — realistic input causes incorrect behavior, data loss, security regression, broken contract, or a paging incident.
|
|
126
|
+
- **MAJOR** — meaningful degradation of correctness/UX/observability under realistic conditions; OR a documented-convention violation with concrete downstream impact.
|
|
127
|
+
- **MINOR** — cheap, concrete improvement with a named benefit.
|
|
128
|
+
- **NIT** — only admissible if (a) repeats ≥2× in the diff, (b) conflicts with a documented convention, or (c) is a one-line trivial fix.
|
|
129
|
+
|
|
130
|
+
Every finding **must** include a `failure_mode`: one sentence on the concrete user-, oncall-, or maintainer-visible bad outcome that would occur if not fixed. Hypotheticals like "a future caller might…" do **NOT** satisfy this — drop the finding.
|
|
131
|
+
|
|
132
|
+
### Do-not-raise list (binding)
|
|
133
|
+
|
|
134
|
+
- Speculative defensiveness at trusted internal boundaries.
|
|
135
|
+
- Restating the obvious ("consider a comment explaining what this does").
|
|
136
|
+
- Hypothetical future-caller scenarios with no current caller.
|
|
137
|
+
- Style/formatting a linter or formatter covers.
|
|
138
|
+
- Test-coverage demands on trivially-verifiable code.
|
|
139
|
+
- "Add observability" without naming a concrete failure mode it would help debug.
|
|
140
|
+
- Abstract SOLID-style "consider extracting…" without a concrete failure mode.
|
|
141
|
+
- Aesthetic naming preferences — only raise names that mislead about behavior.
|
|
142
|
+
|
|
143
|
+
## Review checklist
|
|
144
|
+
|
|
145
|
+
Walk the diff once. For each lens, you're looking for _the smallest number of high-signal findings_, not exhaustive coverage. Cap **6 actionable items** (CRITICAL/MAJOR/MINOR) plus **8 nits** retained internally; anything beyond is "N additional items omitted; ask for the full list."
|
|
146
|
+
|
|
147
|
+
For every candidate finding, run the litmus test before keeping it: _"What is the concrete, current, product-visible cost of leaving this code in?"_ If you can't answer in one sentence, drop it.
|
|
148
|
+
|
|
149
|
+
### Engineering (always)
|
|
150
|
+
|
|
151
|
+
For each change name a realistic input or condition that would expose a bug. If you cannot, do not raise it.
|
|
152
|
+
|
|
153
|
+
- Edge cases, error paths, observability of real failure modes.
|
|
154
|
+
- Tests cover real risk, not lines.
|
|
155
|
+
- Concurrency, performance at real scale, data integrity.
|
|
156
|
+
- Backward compatibility, on-call implications, degraded-mode behavior.
|
|
157
|
+
- Async/await ordering matches actual data dependencies.
|
|
158
|
+
- Timezone correctness in date code; currency variables explicitly in minor units.
|
|
159
|
+
- API surface changed → AuthN/AuthZ/PII (deep dive under Security).
|
|
160
|
+
- Migration → rollback, rolling-deploy compat, ETL/downstream impact (deep dive under Database).
|
|
161
|
+
- Schema/query changed → indexes for new patterns, N+1, cascade semantics, type fit (deep dive under Database).
|
|
162
|
+
- Telemetry covers business/product value, not only engineering surface metrics.
|
|
163
|
+
- Contract/backward-compat for any consumer-visible response shape change. **If you suspect a consumer break, the finding is cross-repo — follow the Cross-repo evidence policy before raising it. Do not raise speculative "the FE will fail to parse" findings without reading the FE.**
|
|
164
|
+
|
|
165
|
+
### Minimalism (always)
|
|
166
|
+
|
|
167
|
+
The smallest diff that ships the intent is the best diff.
|
|
168
|
+
|
|
169
|
+
- Unneeded abstractions, speculative generality, dead branches.
|
|
170
|
+
- Redundant validation, defensive code at trusted internal boundaries.
|
|
171
|
+
- Comments that restate code; new files/utilities that duplicate existing ones.
|
|
172
|
+
- Tests that exercise the framework, not behavior.
|
|
173
|
+
- Flags/config knobs without a concrete caller.
|
|
174
|
+
- Duplicated error handlers in the same scope.
|
|
175
|
+
- Commented-out code or dead branches.
|
|
176
|
+
|
|
177
|
+
For every "delete this" finding, `failure_mode` must state the **concrete cost of keeping the code**.
|
|
178
|
+
|
|
179
|
+
### Conventions (always)
|
|
180
|
+
|
|
181
|
+
You are the convention owner — read the repo's actual conventions before flagging anything. Consult, in order of priority:
|
|
182
|
+
|
|
183
|
+
- `git show ${context_ref}:AGENTS.md` and `CLAUDE.md` (if present)
|
|
184
|
+
- `git ls-tree -r --name-only ${context_ref} -- .rules` then read each rule file relevant to the diff
|
|
185
|
+
- Neighboring files in the same module/service for in-practice patterns
|
|
186
|
+
- Package READMEs in the touched paths
|
|
187
|
+
|
|
188
|
+
Check the diff for (only what's actually documented in the consulted sources):
|
|
189
|
+
|
|
190
|
+
- Preferred internal packages over third-party (`@clipboard-health/*`, internal `lib/*`).
|
|
191
|
+
- Terminology rules (worker/workplace, not HCP/facility).
|
|
192
|
+
- `lodash` removal preference.
|
|
193
|
+
- `@clipboard-health/datetime` over `date-fns`/`date-fns-tz`/`moment`/`luxon`.
|
|
194
|
+
- Internal `Money` package for currencies; explicit minor-units variable names.
|
|
195
|
+
- Logging conventions (`longContext`, `ObjectId.toString()`, no variables in log messages).
|
|
196
|
+
- Null/undefined checks via `isDefined`/`isNil` over truthy.
|
|
197
|
+
- 4+ argument functions → params object.
|
|
198
|
+
- Error-handling patterns in the same service (typed `ServiceResult` vs throw).
|
|
199
|
+
- Test conventions, naming, file location (service test structure, `createTestContext`/`tearDown`, `beforeAll/afterAll` for GET).
|
|
200
|
+
- Business-meaningful magic constants that should be named.
|
|
201
|
+
- ENV access via Configuration abstraction, not direct `process.env`.
|
|
202
|
+
- Logging library standard for the repo — derive from existing code, not hardcoded.
|
|
203
|
+
- Pinned dependencies; lock file in sync with `package.json`.
|
|
204
|
+
- RESTful route shape and uniform response format within a service.
|
|
205
|
+
- **Internal inconsistency within the diff itself** (e.g. half of imports from one package family, half from upstream; same persisted shape written three different ways across three call sites).
|
|
206
|
+
|
|
207
|
+
Frontend conventions are the Frontend lens's job when activated. If FE lens isn't active (no FE files), surface FE convention drift here only if it appears.
|
|
208
|
+
|
|
209
|
+
Tag every convention finding with `[CONVENTION]` in the title. Cap severity at MAJOR (only when behavior diverges as a result) or MINOR otherwise. In the Summary, list the convention sources you consulted.
|
|
210
|
+
|
|
211
|
+
### AntiSlop (always)
|
|
212
|
+
|
|
213
|
+
This PR may have been written or assisted by an LLM. For each addition, ask: _"Is this line earning its keep, or is it pattern-matching what code is supposed to look like?"_ Push back on what other lenses are too polite to flag. Apply to additions **inside the diff itself**.
|
|
214
|
+
|
|
215
|
+
- **Defensive code at trusted internal boundaries.** Null guards on private helpers whose callers' types guarantee non-null; `try`/`catch` wrapping a single non-throwing call, or that re-throws unchanged, or that "logs and swallows" without naming what to do next; optional-chaining through types that don't include optionality.
|
|
216
|
+
- **Defensiveness against unrealistic product scenarios.** Litmus: _"In the real product flow this code participates in, what user action / system event / upstream call could land us in this branch?"_ If the answer is "none" or "I had to invent one to justify the guard", it's slop. Concrete shapes:
|
|
217
|
+
- Null/undefined guard on an ID immediately after that ID was used to load (and find) the entity.
|
|
218
|
+
- A `null`/`undefined`/`""`/`0` branch on a field whose TypeScript or Zod/class-validator already rejects those.
|
|
219
|
+
- Re-validation of a value the request DTO already validated upstream in the same lifecycle.
|
|
220
|
+
- Consistency check (`if (a !== b) throw`) between two fields the data model forbids being unequal.
|
|
221
|
+
- Branch for a product-impossible state.
|
|
222
|
+
- Retry/fallback around an SDK call that already retries or returns a typed error.
|
|
223
|
+
- `catch` for an error class statically known not to throw, or that logs+swallows.
|
|
224
|
+
- "Future-proof" code path with no current `v2`.
|
|
225
|
+
- **Restating-the-code comments.** `// fetch the user`, JSDoc on private helpers that only restates the signature, `// Note: this is important`, section banners in short files.
|
|
226
|
+
- **Empty scaffolding.** `// TODO` with no owner/ticket; redundant pre-conditions; debug logs that survived to the PR; default `else { return undefined; }` after exhaustive branching; `_unused` prefixes that should be deletions.
|
|
227
|
+
- **Speculative generality.** Helper called once that wraps two trivial lines; `Map`/`Set`/config keyed by a single hardcoded value; "strategy"/"registry" pattern with one strategy; union types whose only second case is `never`/placeholder.
|
|
228
|
+
- **Unused parameters/overloads/fields.** Args destructured but never read; interface methods with empty implementations; new optional fields with no producer or consumer.
|
|
229
|
+
- **Tests that exercise the framework, not the code.** `jest.fn().mockReturnValue(x); expect(fn()).toBe(x)`; snapshot tests with no semantic assertion; tests that mock the unit under test; test names that describe the implementation (`it("calls foo.bar"…)`) instead of behavior.
|
|
230
|
+
- **Dead AI breadcrumbs.** Variables whose only use is logging or debug branches; `console.log`/`console.error` that should have been removed before commit; commented-out alternative implementations.
|
|
231
|
+
- **Tone/description mismatch.** PR description claims behavior the diff doesn't have; variable/function names that pattern-match engineering writing without naming the role (`data`, `result`, `processed`, `_handle`, `doStuff`).
|
|
232
|
+
|
|
233
|
+
Default `suggested_fix` is **delete** (empty `after`) or **simplify** (smaller `after`). Suggesting "add a justifying comment" is itself slop — do not propose it.
|
|
234
|
+
|
|
235
|
+
### Security lens (when triggered)
|
|
236
|
+
|
|
237
|
+
Where could this change leak data, bypass authorization, or expand the trust boundary?
|
|
238
|
+
|
|
239
|
+
- AuthN: every new/modified endpoint has authenticated identity unless explicitly public.
|
|
240
|
+
- AuthZ: per-endpoint AND per-resource permission checks; cross-tenant/cross-user access.
|
|
241
|
+
- Secrets in configuration — no hardcoded keys, no secrets in client bundles.
|
|
242
|
+
- No self-made or client-side cryptography.
|
|
243
|
+
- SQL/NoSQL injection: string-concatenated queries, unvalidated `$where`, raw aggregation pipelines from user input.
|
|
244
|
+
- Sensitive data in response payloads — over-fetching, over-serialization, internal IDs leaked.
|
|
245
|
+
- PII fields logged, cached, or sent to telemetry.
|
|
246
|
+
- Input validation at the boundary (Zod / class-validator) on every new endpoint.
|
|
247
|
+
- For numeric inputs: explicit `min`/`max` bounds. Verify what the JS engine does with `Number.MAX_SAFE_INTEGER + 1`, BigInt conversion, negative values, and whether the catch path returns a structured 400 or a 500 with stack log.
|
|
248
|
+
|
|
249
|
+
### Database lens (when triggered)
|
|
250
|
+
|
|
251
|
+
What breaks at production scale or during deploy?
|
|
252
|
+
|
|
253
|
+
- Index coverage for new query patterns; missing compound indexes.
|
|
254
|
+
- N+1 query shapes; loops issuing per-iteration queries.
|
|
255
|
+
- Schema normalization — denormalization that creates write-amplification or update anomalies.
|
|
256
|
+
- Data types — range, precision, locale (numeric, date, money). Mongoose `Number` is IEEE 754 double; safe for integers up to 2^53.
|
|
257
|
+
- Cascade-delete and FK-on-delete semantics; orphan risk.
|
|
258
|
+
- Migration rollback strategy; online without downtime.
|
|
259
|
+
- Backward compatibility during a rolling deploy (old code reads new schema; new code reads old schema).
|
|
260
|
+
- ETL / downstream consumer impact when schema or field semantics change.
|
|
261
|
+
- New collections / tables ship with the indexes their query patterns need on day one.
|
|
262
|
+
- **Dual-write fields** (storing both `amount` and `amountInMinorUnits`-style pairs): is canonicalization happening on write, or does the on-disk record encode two contradictory values?
|
|
263
|
+
- Backfill for new fields on existing records: present, deferred (with ticket), or missing?
|
|
264
|
+
|
|
265
|
+
### Frontend lens (when triggered)
|
|
266
|
+
|
|
267
|
+
Does this follow our FE conventions, and will it behave correctly under realistic user conditions?
|
|
268
|
+
|
|
269
|
+
- API calls through v2 / custom hooks, not raw `fetch`/`axios` in components.
|
|
270
|
+
- React Query: thin wrappers (`useGetQuery`, etc.), not raw `useQuery`/`useMutation`.
|
|
271
|
+
- Falsy checks via `isDefined()`/`isNil()`, not `!value`.
|
|
272
|
+
- Test actions wrapped in `act()`.
|
|
273
|
+
- Zod: `z.nativeEnum` when a TS enum already exists.
|
|
274
|
+
- Prop drilling — when a value passes through ≥2 layers, consider context.
|
|
275
|
+
- Feature flags via `useCbhFlag` (or repo equivalent), not direct config reads.
|
|
276
|
+
- New components/styles from the design-system library, not built from scratch.
|
|
277
|
+
- Loading / empty / error states for any new data-fetching surface.
|
|
278
|
+
- Accessibility: keyboard navigation, ARIA roles, labels on interactive controls.
|
|
279
|
+
|
|
280
|
+
## Self-filter (before synthesis)
|
|
281
|
+
|
|
282
|
+
After walking the checklist, apply these filters to your candidate findings:
|
|
283
|
+
|
|
284
|
+
1. **Drop findings with empty or hypothetical `failure_mode`.** "A future caller might…", "in case someone…" → drop.
|
|
285
|
+
2. **Self-audit for slop.** For every finding you wrote, ask: does it match a slop pattern (asks-for-defensive-guard on already-narrowed value; hypothetical future caller; restating-obvious comment request; abstract refactor with no concrete cost-of-keeping; observability without named failure mode; test for trivially-verifiable code; defends against a state the product cannot produce)? If yes and you can't write a concrete, product-specific cost in one sentence — drop it. Being your own AntiSlop reviewer is the main lever for keeping this skill honest.
|
|
286
|
+
3. **Cross-repo audit.** For every finding, ask: does the failure_mode reference a downstream actor (FE, mobile, consumer service, rolling deploy, external library user) or a contract/schema/public-artifact boundary? If yes, did you actually read the relevant external file(s) to confirm the claim, or are you reasoning from priors about "how FEs usually work"? If you didn't read it, the finding is cross-repo — route to the Cross-repo evidence policy (verify, ask for access, or downgrade to a clearly-labeled "speculative" MINOR). Do not ship a "consumer will break" finding sourced from imagination.
|
|
287
|
+
4. **Drop do-not-raise items** that slipped through.
|
|
288
|
+
5. **Apply the NIT gate.** NITs that don't meet (a)/(b)/(c) → drop. Kept internally but hidden by default in synthesis.
|
|
289
|
+
6. **Merge near-duplicates** under one finding (note which lens(es) surfaced it).
|
|
290
|
+
7. **Apply hard caps.** 6 actionable, 8 NITs retained, rest summarized as "N additional items omitted".
|
|
291
|
+
|
|
292
|
+
Track dropped items in a Withdrawn section (one-liner each) so the user can see what was filtered.
|
|
293
|
+
|
|
294
|
+
## suggested_fix schema (when present)
|
|
295
|
+
|
|
296
|
+
```json
|
|
297
|
+
"suggested_fix": {
|
|
298
|
+
"before": "<exact current code at file:lines>",
|
|
299
|
+
"after": "<replacement code at the same anchor>"
|
|
300
|
+
}
|
|
301
|
+
```
|
|
302
|
+
|
|
303
|
+
- Pure deletion: `after` is `""`.
|
|
304
|
+
- Pure addition at a new line: `before` is `""`, prefix `after` with `// add after line <N>`.
|
|
305
|
+
- Structural change with no clean drop-in: omit `suggested_fix`, describe in `point`/`failure_mode`.
|
|
306
|
+
- Both must be code (not prose), preserving the file's indentation. Don't elide with `// ...`.
|
|
307
|
+
|
|
308
|
+
## Synthesize
|
|
309
|
+
|
|
310
|
+
### Summary
|
|
311
|
+
|
|
312
|
+
One short paragraph: what the change does and your overall recommendation (ship / ship with changes / do not ship). Do not state the mode, list the lenses you applied, or list the convention sources you consulted — that metadata is noise for the user. Keep it to substance.
|
|
313
|
+
|
|
314
|
+
### Actionable
|
|
315
|
+
|
|
316
|
+
Up to 6 items. Format each:
|
|
317
|
+
|
|
318
|
+
- **[SEVERITY] Title** — `file:lines`
|
|
319
|
+
- **Point:** one sentence.
|
|
320
|
+
- **Why it matters:** the `failure_mode`.
|
|
321
|
+
- **Suggested fix (before → after):** two stacked fenced code blocks — first `// Before` (current code), then `// After` (replacement). Same language tag for both. For a pure deletion, show only `Before` and write "_Delete these lines._" For a pure addition, show only `After` prefixed with `// Add after line <N>`. Omit when structural; explain in prose.
|
|
322
|
+
- **Lens(es):** which lens(es) surfaced this (e.g. `Engineering, AntiSlop`).
|
|
323
|
+
|
|
324
|
+
Render template:
|
|
325
|
+
|
|
326
|
+
````markdown
|
|
327
|
+
**Suggested fix (before → after):**
|
|
328
|
+
|
|
329
|
+
```ts
|
|
330
|
+
// Before — src/foo/bar.ts:42-45
|
|
331
|
+
const x = doThing();
|
|
332
|
+
if (x !== null) {
|
|
333
|
+
return x;
|
|
334
|
+
}
|
|
335
|
+
```
|
|
336
|
+
|
|
337
|
+
```ts
|
|
338
|
+
// After
|
|
339
|
+
const x = doThing();
|
|
340
|
+
return isDefined(x) ? x : undefined;
|
|
341
|
+
```
|
|
342
|
+
````
|
|
343
|
+
|
|
344
|
+
Order by severity (CRITICAL → MAJOR → MINOR), then by file.
|
|
345
|
+
|
|
346
|
+
### Nits
|
|
347
|
+
|
|
348
|
+
Do **not** print by default. Print only: _"N nit(s) available (M from convention audit). Pick `Show the N NIT(s) first` in the picker below to see them."_ If N is 0, omit this entire section. Surface the "show nits" affordance as an option in the User gate 1 `AskUserQuestion` call (not as typed text). When selected, print one-liners with `file:lines` and `[CONVENTION]` tag where applicable, then re-call User gate 1.
|
|
349
|
+
|
|
350
|
+
### Withdrawn
|
|
351
|
+
|
|
352
|
+
Terse one-liners of items you dropped (do-not-raise, NIT gate, self-slop audit). Transparency only.
|
|
353
|
+
|
|
354
|
+
## User gate 1 — select items
|
|
355
|
+
|
|
356
|
+
Ask via **`AskUserQuestion`**, not as a text prompt. Render each actionable finding as an option, with a trailing "show the N NIT(s) first" option when `N > 0`. Set `multiSelect: true` so the user can pick any combination (including none). Do not proceed until the user answers.
|
|
357
|
+
|
|
358
|
+
**Template:**
|
|
359
|
+
|
|
360
|
+
```ts
|
|
361
|
+
AskUserQuestion({
|
|
362
|
+
questions: [
|
|
363
|
+
{
|
|
364
|
+
question: "Which findings should I <verb>?", // "post as inline comments on PR <N>" / "implement locally" / "act on"
|
|
365
|
+
header: "Findings",
|
|
366
|
+
multiSelect: true,
|
|
367
|
+
options: [
|
|
368
|
+
{ label: "1 - <short title> (<SEVERITY>)", description: "<one-sentence failure_mode>" },
|
|
369
|
+
{ label: "2 - …", description: "…" },
|
|
370
|
+
// …one entry per actionable finding (cap 6)
|
|
371
|
+
{ label: "Show the <N> NIT(s) first", description: "Print the NIT list before deciding." }, // omit when N == 0
|
|
372
|
+
],
|
|
373
|
+
},
|
|
374
|
+
],
|
|
375
|
+
});
|
|
376
|
+
```
|
|
377
|
+
|
|
378
|
+
Option-label format: `<id> - <short title> (<SEVERITY>)`. The id matches the in-chat numbering in the Actionable section above. The `description` is one short sentence — the failure_mode, not the fix. Do not pad with file paths; the user already has the full Actionable section in the chat.
|
|
379
|
+
|
|
380
|
+
Branching on the answer:
|
|
381
|
+
|
|
382
|
+
- **Zero findings selected** (user submitted no boxes / picked Skip) → end the skill with a one-line "no findings selected — nothing to do" reply.
|
|
383
|
+
- **Only "Show the N NIT(s) first"** selected → print the NITs (one-liners with `file:lines` and `[CONVENTION]` tag where applicable), then re-call `AskUserQuestion` for this same gate.
|
|
384
|
+
- **Findings selected (with or without the NIT toggle)** → proceed to gate 2. If the NIT toggle was also checked, print NITs once before gate 2.
|
|
385
|
+
|
|
386
|
+
## Branch on mode
|
|
387
|
+
|
|
388
|
+
### Author mode
|
|
389
|
+
|
|
390
|
+
**Plan.** For the selected ids only, produce an ordered implementation plan: steps, files touched per step, tests to add/update, verification commands. Do **not** edit files yet.
|
|
391
|
+
|
|
392
|
+
**User gate 2 (author)** — ask via **`AskUserQuestion`** (`multiSelect: false`):
|
|
393
|
+
|
|
394
|
+
```ts
|
|
395
|
+
AskUserQuestion({
|
|
396
|
+
questions: [
|
|
397
|
+
{
|
|
398
|
+
question: "What do you want to do with the selected findings?",
|
|
399
|
+
header: "Next step",
|
|
400
|
+
multiSelect: false,
|
|
401
|
+
options: [
|
|
402
|
+
{ label: "Implement locally", description: "Apply the plan against your checkout." },
|
|
403
|
+
{
|
|
404
|
+
label: "Post as review",
|
|
405
|
+
description: "Post anchored comments on your own PR for the team to see, then stop.",
|
|
406
|
+
},
|
|
407
|
+
{ label: "Both", description: "Post the review first, then execute the plan locally." },
|
|
408
|
+
{ label: "Edit the plan", description: "Revise the plan; I'll re-prompt this gate." },
|
|
409
|
+
{ label: "Cancel", description: "Stop." },
|
|
410
|
+
],
|
|
411
|
+
},
|
|
412
|
+
],
|
|
413
|
+
});
|
|
414
|
+
```
|
|
415
|
+
|
|
416
|
+
- `Implement locally` → execute the plan.
|
|
417
|
+
- `Post as review` → post anchored review (below); skill ends.
|
|
418
|
+
- `Both` → post review first, then execute.
|
|
419
|
+
- `Edit the plan` → revise, re-prompt this gate.
|
|
420
|
+
- `Cancel` → stop.
|
|
421
|
+
|
|
422
|
+
**Execute.** Use TodoWrite to track each step. Apply the plan, run verification, report results. If a step surfaces a new substantive issue not in the selected items, stop and ask before expanding scope.
|
|
423
|
+
|
|
424
|
+
### Reviewer mode
|
|
425
|
+
|
|
426
|
+
Skip the plan step — you are not implementing someone else's code.
|
|
427
|
+
|
|
428
|
+
**User gate 2 (reviewer)** — ask via **`AskUserQuestion`** (`multiSelect: false`):
|
|
429
|
+
|
|
430
|
+
```ts
|
|
431
|
+
AskUserQuestion({
|
|
432
|
+
questions: [
|
|
433
|
+
{
|
|
434
|
+
question: "Post these on the PR?",
|
|
435
|
+
header: "Post review",
|
|
436
|
+
multiSelect: false,
|
|
437
|
+
options: [
|
|
438
|
+
{
|
|
439
|
+
label: "Post",
|
|
440
|
+
description: "Submit a single COMMENT review with the selected anchored comments.",
|
|
441
|
+
},
|
|
442
|
+
{ label: "Edit", description: "Ask which to drop or refine, then re-prompt." },
|
|
443
|
+
{ label: "Cancel", description: "Stop." },
|
|
444
|
+
],
|
|
445
|
+
},
|
|
446
|
+
],
|
|
447
|
+
});
|
|
448
|
+
```
|
|
449
|
+
|
|
450
|
+
- `Post` → post anchored review.
|
|
451
|
+
- `Edit` → ask which to drop or refine, then re-prompt.
|
|
452
|
+
- `Cancel` → stop.
|
|
453
|
+
|
|
454
|
+
## Posting an anchored PR review (both modes)
|
|
455
|
+
|
|
456
|
+
When the user approves items to post, submit a **single** review via the GitHub Reviews API (`event: COMMENT` — never `APPROVE`/`REQUEST_CHANGES`), with every selected actionable item as an inline comment anchored to its diff line. Never use loose issue comments.
|
|
457
|
+
|
|
458
|
+
Follow [references/posting-pr-review.md](references/posting-pr-review.md) exactly — it has the `gh api` call, the payload shape, the three-block review body (attribution line, summary, apply-all prompt), and the per-comment body budget and format. After posting, print the review `html_url` and a one-line summary of how many comments were posted (and fallback general-notes count if any).
|
|
459
|
+
|
|
460
|
+
## Rules
|
|
461
|
+
|
|
462
|
+
- **No subagents.** This skill runs entirely in the main context. If a finding needs deeper independent investigation that you can't do confidently in-line, surface it as a flagged finding rather than guess.
|
|
463
|
+
- Issue parallel `gh`/`git` commands in a single message when independent (PR view, diff, files, viewer).
|
|
464
|
+
- If a finding has empty `failure_mode` → drop. NIT not meeting the gate → drop. Do-not-raise items → drop. Caps applied (6 actionable, 8 nits).
|
|
465
|
+
- Hide nits by default. Print only when the user selects `Show the N NIT(s) first` in the User gate 1 picker.
|
|
466
|
+
- Reviews are always `event: COMMENT`. Never approve or request changes on the user's behalf.
|
|
467
|
+
- Conditional lenses (Security/Database/Frontend) run only when classification matches.
|
|
468
|
+
- Freshness preflight is mandatory before reading code. Read repo context via `git show "<context_ref>:<path>"`, not the worktree filesystem, unless `context_ref = worktree (stale, user accepted risk)`.
|
|
469
|
+
- Never run state-modifying git commands on the user's behalf (`checkout`, `stash`, `reset`, `clean`, `pull` with merge). Warn and ask. `git fetch` is allowed.
|
|
470
|
+
- Cross-repo evidence is opt-in by the user. The policy fires whenever the diff touches a contract/schema/published-artifact boundary OR the finding's failure_mode references a downstream actor (FE, mobile, consumer service, rolling deploy). Identify the specific external file you'd need to read, search locally first, then ask the user using the access-request template. Cap at MAJOR until verified; `skip` → either drop or keep as MINOR with a visible "speculative — assumes `<X>`" prefix. **Never raise a "consumer will break" finding without reading the consumer.**
|
|
471
|
+
- `suggested_fix` is always a `{ before, after }` object of code (not prose). **In-chat Actionable:** render both halves as separate `// Before` then `// After` fenced blocks. **PR-review inline comments:** render only the `suggestion` block (GitHub already renders the diff). Empty `before` = pure addition; empty `after` = pure deletion (omit `suggestion`, write "_Delete the anchored line(s)._"); omit entirely for structural changes.
|
|
472
|
+
- Both user gates are mandatory and **must** be presented via `AskUserQuestion` (the structured picker), not as inline text questions. Do not auto-apply recommendations and do not auto-post reviews.
|