@olegkoval/agent-skills 1.26.0 → 1.28.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/.claude-plugin/plugin.json +2 -1
- package/README.md +7 -3
- package/catalog/skills.json +18 -0
- package/package.json +5 -3
- package/packages/software-development/lekker-review/SKILL.md +519 -0
- package/packages/software-development/lekker-review/adapters/claude/plugin.json +5 -0
- package/packages/software-development/lekker-review/adapters/claude/skills/lekker-review/SKILL.md +520 -0
- package/packages/software-development/lekker-review/adapters/claude/skills/lekker-review/references/agents/completeness-critic.md +21 -0
- package/packages/software-development/lekker-review/adapters/claude/skills/lekker-review/references/agents/conventions.md +124 -0
- package/packages/software-development/lekker-review/adapters/claude/skills/lekker-review/references/agents/fix-verifier.md +84 -0
- package/packages/software-development/lekker-review/adapters/claude/skills/lekker-review/references/agents/fixer.md +120 -0
- package/packages/software-development/lekker-review/adapters/claude/skills/lekker-review/references/agents/implementation.md +53 -0
- package/packages/software-development/lekker-review/adapters/claude/skills/lekker-review/references/agents/prover.md +135 -0
- package/packages/software-development/lekker-review/adapters/claude/skills/lekker-review/references/agents/quality.md +72 -0
- package/packages/software-development/lekker-review/adapters/claude/skills/lekker-review/references/agents/simplification.md +45 -0
- package/packages/software-development/lekker-review/adapters/claude/skills/lekker-review/references/agents/test-quality.md +170 -0
- package/packages/software-development/lekker-review/adapters/claude/skills/lekker-review/references/agents/triage-logic.md +27 -0
- package/packages/software-development/lekker-review/adapters/claude/skills/lekker-review/references/agents/triage-quality.md +41 -0
- package/packages/software-development/lekker-review/adapters/claude/skills/lekker-review/references/agents/verifier.md +295 -0
- package/packages/software-development/lekker-review/adapters/claude/skills/lekker-review/references/artifact-page.md +143 -0
- package/packages/software-development/lekker-review/adapters/claude/skills/lekker-review/references/context-gathering.md +162 -0
- package/packages/software-development/lekker-review/adapters/claude/skills/lekker-review/references/fix-mode.md +329 -0
- package/packages/software-development/lekker-review/adapters/claude/skills/lekker-review/references/github-post.md +205 -0
- package/packages/software-development/lekker-review/adapters/claude/skills/lekker-review/references/house-rules.md +76 -0
- package/packages/software-development/lekker-review/adapters/claude/skills/lekker-review/references/output-format.md +232 -0
- package/packages/software-development/lekker-review/adapters/claude/skills/lekker-review/scripts/changed-files.sh +77 -0
- package/packages/software-development/lekker-review/adapters/claude/skills/lekker-review/scripts/setup-worktree.sh +337 -0
- package/packages/software-development/lekker-review/adapters/claude/skills/lekker-review/scripts/verify-fixes.sh +231 -0
- package/packages/software-development/lekker-review/fix-workflow.js +273 -0
- package/packages/software-development/lekker-review/references/agents/completeness-critic.md +21 -0
- package/packages/software-development/lekker-review/references/agents/conventions.md +124 -0
- package/packages/software-development/lekker-review/references/agents/fix-verifier.md +84 -0
- package/packages/software-development/lekker-review/references/agents/fixer.md +120 -0
- package/packages/software-development/lekker-review/references/agents/implementation.md +53 -0
- package/packages/software-development/lekker-review/references/agents/prover.md +135 -0
- package/packages/software-development/lekker-review/references/agents/quality.md +72 -0
- package/packages/software-development/lekker-review/references/agents/simplification.md +45 -0
- package/packages/software-development/lekker-review/references/agents/test-quality.md +170 -0
- package/packages/software-development/lekker-review/references/agents/triage-logic.md +27 -0
- package/packages/software-development/lekker-review/references/agents/triage-quality.md +41 -0
- package/packages/software-development/lekker-review/references/agents/verifier.md +295 -0
- package/packages/software-development/lekker-review/references/artifact-page.md +143 -0
- package/packages/software-development/lekker-review/references/context-gathering.md +162 -0
- package/packages/software-development/lekker-review/references/fix-mode.md +329 -0
- package/packages/software-development/lekker-review/references/github-post.md +205 -0
- package/packages/software-development/lekker-review/references/house-rules.md +76 -0
- package/packages/software-development/lekker-review/references/output-format.md +232 -0
- package/packages/software-development/lekker-review/scripts/changed-files.sh +77 -0
- package/packages/software-development/lekker-review/scripts/setup-worktree.sh +337 -0
- package/packages/software-development/lekker-review/scripts/verify-fixes.sh +231 -0
- package/packages/software-development/lekker-review/workflow.js +602 -0
- package/site/assets/paperbag.css +707 -0
- package/site/assets/paperbag.js +218 -0
- package/site/build.mjs +380 -0
|
@@ -0,0 +1,205 @@
|
|
|
1
|
+
# github-post.md -- lekker-review --post flag procedure
|
|
2
|
+
|
|
3
|
+
Execute this procedure AFTER the review file has been saved to `~/code-reviews/`
|
|
4
|
+
and ONLY when the user passed `--post`.
|
|
5
|
+
|
|
6
|
+
---
|
|
7
|
+
|
|
8
|
+
## Step 1 -- Build the payload
|
|
9
|
+
|
|
10
|
+
Construct a JSON payload at `/tmp/lekker-post-$$.json` with the structure:
|
|
11
|
+
|
|
12
|
+
```json
|
|
13
|
+
{
|
|
14
|
+
"body": "<summary section>",
|
|
15
|
+
"comments": [
|
|
16
|
+
{
|
|
17
|
+
"path": "<relative file path>",
|
|
18
|
+
"line": <line number>,
|
|
19
|
+
"side": "RIGHT",
|
|
20
|
+
"body": "<finding title + why + fix in GitHub markdown>"
|
|
21
|
+
}
|
|
22
|
+
]
|
|
23
|
+
}
|
|
24
|
+
```
|
|
25
|
+
|
|
26
|
+
Rules:
|
|
27
|
+
|
|
28
|
+
- **Do NOT include an `event` field.** Omitting it creates a PENDING review,
|
|
29
|
+
visible only to the requesting user until they submit it. NEVER submit the
|
|
30
|
+
review programmatically.
|
|
31
|
+
- Include one comment entry for every Critical and Important finding whose
|
|
32
|
+
`file:line` falls within the diff hunks of this PR (see Step 2 for how to
|
|
33
|
+
determine commentability).
|
|
34
|
+
- **Keep every comment body to 2-4 sentences and under ~700 characters**
|
|
35
|
+
(excluding any suggestion block). Inline comments are read one at a time in a
|
|
36
|
+
narrow column; a long one does not get read, so length actively costs you the
|
|
37
|
+
fix. The detail belongs only in the saved review file (`~/code-reviews/*.md`).
|
|
38
|
+
Do NOT reproduce the file's full Critical/Important write-up inline.
|
|
39
|
+
|
|
40
|
+
- **Open with the ask, in the imperative.** The first clause must be the action
|
|
41
|
+
the author takes ("Return early here", "Extract one shared winner-picker",
|
|
42
|
+
"Raise to 250", "Add a double with `session`"). Evidence comes after, and only
|
|
43
|
+
the evidence that makes the ask credible. Never open with a bolded severity
|
|
44
|
+
label, a restated finding title, or a preamble — the author already knows they
|
|
45
|
+
are reading a review comment.
|
|
46
|
+
|
|
47
|
+
```
|
|
48
|
+
✗ **Important — two implementations of "largest fulfillment order" with
|
|
49
|
+
different tie-break keys.** This ranks by value → units → id; `x.ts:104`
|
|
50
|
+
ranks by shipped qty → id. Diverging input: one shared line referenced by
|
|
51
|
+
FO-A (qty 1, one $100 item) and FO-B (qty 3, three $10 items) — fallback
|
|
52
|
+
picks FO-A, exact picks FO-B. Because `existingCreatedLines` idempotency is
|
|
53
|
+
keyed per `fulfillmentOrderGid` with no cross-FO check, a transient
|
|
54
|
+
exact-API failure on FO-A (fallback wins, line written) followed by a
|
|
55
|
+
successful retry on FO-B (exact wins, line written) posts the shared charge
|
|
56
|
+
twice. Please extract one `pickSharedChargeWinner(candidates, size, id)`…
|
|
57
|
+
|
|
58
|
+
✓ Please extract one shared winner-picker used by both files, keyed on FO
|
|
59
|
+
value. This ranks value → units → id; `x.ts:104` ranks shipped-qty → id, so
|
|
60
|
+
FO-A (qty 1, one $100 item) vs FO-B (qty 3, three $10 items) gives A here
|
|
61
|
+
and B there. Idempotency is keyed per `fulfillmentOrderGid` with no cross-FO
|
|
62
|
+
check, so a fallback run that writes A's line followed by an exact-path
|
|
63
|
+
retry on B writes the same charge twice.
|
|
64
|
+
```
|
|
65
|
+
|
|
66
|
+
- **Cut every clause that does not change what the author does.** In particular:
|
|
67
|
+
no severity prefix (the review body already states the counts), no
|
|
68
|
+
"Why it's wrong:" / "Fix:" headers (that is the saved-file format, not the
|
|
69
|
+
inline format), no verifier reasoning, no restating what the PR does, no
|
|
70
|
+
second worked example once the first lands, and no sentence whose content is
|
|
71
|
+
already visible on the commented line.
|
|
72
|
+
- **Use a GitHub suggestion block for the fix whenever it's a direct code change**
|
|
73
|
+
anchored to the commented line(s) — a reviewer can apply it with one click:
|
|
74
|
+
```suggestion
|
|
75
|
+
<replacement line(s), exact drop-in for the line(s) the comment is anchored to>
|
|
76
|
+
```
|
|
77
|
+
Only use a suggestion block when it exactly replaces the commented line(s) —
|
|
78
|
+
never for fixes spanning multiple files or requiring a new function/extraction
|
|
79
|
+
elsewhere. For those, describe the fix in one sentence instead and point to
|
|
80
|
+
the saved review for detail; do not paste a plain fenced code block as a
|
|
81
|
+
substitute for a real suggestion.
|
|
82
|
+
- **Every inline comment must be ACTIONABLE** — it must ask for a concrete change
|
|
83
|
+
(fix X, add a test for Y, regenerate Z). Do NOT post informational-only or
|
|
84
|
+
FYI comments ("behaviour change, intentional", "note that…", "just flagging").
|
|
85
|
+
If there's nothing to do, there's no comment — put context like that in the
|
|
86
|
+
review body or the saved review file, never as an inline PR comment.
|
|
87
|
+
- The review-level `body` field must contain, in this order: the finding counts
|
|
88
|
+
("0 Critical / 5 Important / 6 Observations / 1 Idiomatic"), one or two
|
|
89
|
+
sentences of risk framing, then **a numbered list of the asks — one line each,
|
|
90
|
+
imperative, matching the inline comments in order**. That list is what the
|
|
91
|
+
author reads first and works from; it must be scannable in ten seconds. Then
|
|
92
|
+
any Production Signals, then a short flat list of Observations marked "no
|
|
93
|
+
action required", then the saved review file path.
|
|
94
|
+
|
|
95
|
+
Keep the body itself under ~2,500 characters. If it is longer, the asks are
|
|
96
|
+
buried — cut prose, never cut the numbered asks.
|
|
97
|
+
- Do NOT prefix the body with a banner like "## Lekker review". Do NOT praise the
|
|
98
|
+
PR or describe what it does well — no "solid", "handled well", "clean", "nice".
|
|
99
|
+
State the risk and the asks only.
|
|
100
|
+
- We use **Linear**, not Jira. Never write "Jira" in any comment or body; refer
|
|
101
|
+
to Linear ticket IDs (e.g. DUBO-201) directly.
|
|
102
|
+
|
|
103
|
+
---
|
|
104
|
+
|
|
105
|
+
## Step 2 -- Determine commentability
|
|
106
|
+
|
|
107
|
+
A line is commentable only if it appears in the diff hunks for the file. To
|
|
108
|
+
check, scan `DIFF_FILE` for the relevant hunk headers and added lines:
|
|
109
|
+
|
|
110
|
+
```bash
|
|
111
|
+
grep -n "^@@\|^+" "$DIFF_FILE" | grep -A20 "^.*+.*<relative-file-path>" | head -60
|
|
112
|
+
```
|
|
113
|
+
|
|
114
|
+
If the finding's `line` number does not correspond to a `+` line in the diff
|
|
115
|
+
for that file, the finding is NOT commentable -- fold it into the review body
|
|
116
|
+
under an "Additional findings" section instead.
|
|
117
|
+
|
|
118
|
+
Observation and Idiomatic findings go into the body only; never as inline
|
|
119
|
+
comments.
|
|
120
|
+
|
|
121
|
+
---
|
|
122
|
+
|
|
123
|
+
## Step 3 -- POST the review
|
|
124
|
+
|
|
125
|
+
```bash
|
|
126
|
+
gh api "repos/<REPO_SLUG>/pulls/<PR_NUMBER>/reviews" \
|
|
127
|
+
--method POST \
|
|
128
|
+
--input /tmp/lekker-post-$$.json
|
|
129
|
+
```
|
|
130
|
+
|
|
131
|
+
---
|
|
132
|
+
|
|
133
|
+
## Step 4 -- Handle 422 errors
|
|
134
|
+
|
|
135
|
+
If the API returns HTTP 422 (line not in diff):
|
|
136
|
+
|
|
137
|
+
1. Remove the offending comment object from the payload (identify it from the
|
|
138
|
+
error response body, which names the path and line).
|
|
139
|
+
2. Add its content to the review-level `body` under "Additional findings".
|
|
140
|
+
3. Retry the POST once with the updated payload.
|
|
141
|
+
|
|
142
|
+
If the same failure shape occurs a second time: stop, report the error message
|
|
143
|
+
to the user, and fall back to "paste manually" -- do not loop further.
|
|
144
|
+
|
|
145
|
+
---
|
|
146
|
+
|
|
147
|
+
## Step 5 -- Verify (fresh post-condition)
|
|
148
|
+
|
|
149
|
+
After a successful POST, immediately fetch the current review list:
|
|
150
|
+
|
|
151
|
+
```bash
|
|
152
|
+
gh api "repos/<REPO_SLUG>/pulls/<PR_NUMBER>/reviews"
|
|
153
|
+
```
|
|
154
|
+
|
|
155
|
+
Confirm:
|
|
156
|
+
- A review with `state: "PENDING"` by the current authenticated user exists.
|
|
157
|
+
- The `body` field contains the expected summary text.
|
|
158
|
+
- The comment count matches what was submitted.
|
|
159
|
+
|
|
160
|
+
Print the following to the terminal:
|
|
161
|
+
|
|
162
|
+
```
|
|
163
|
+
Posted PENDING review on <PR_URL>
|
|
164
|
+
- <N> inline comments
|
|
165
|
+
- Review ID: <id>
|
|
166
|
+
|
|
167
|
+
ACTION REQUIRED: Open GitHub in your browser to review and submit the
|
|
168
|
+
pending review. Pending reviews are only visible to you until submitted.
|
|
169
|
+
```
|
|
170
|
+
|
|
171
|
+
Clean up the temporary payload file:
|
|
172
|
+
|
|
173
|
+
```bash
|
|
174
|
+
rm -f /tmp/lekker-post-$$.json
|
|
175
|
+
```
|
|
176
|
+
|
|
177
|
+
---
|
|
178
|
+
|
|
179
|
+
## Step 6 -- Revising an already-posted PENDING review
|
|
180
|
+
|
|
181
|
+
If the user asks to shorten, reword, or re-scope the comments after posting:
|
|
182
|
+
|
|
183
|
+
- The review-level `body` alone can be edited in place:
|
|
184
|
+
`gh api repos/<REPO_SLUG>/pulls/<PR_NUMBER>/reviews/<REVIEW_ID> --method PUT --input <json with {"body": ...}>`
|
|
185
|
+
Inline comments survive this untouched.
|
|
186
|
+
- **Inline comment bodies cannot be reliably edited on a pending review** --
|
|
187
|
+
`PATCH /pulls/comments/{id}` targets submitted comments. To change them,
|
|
188
|
+
DELETE the pending review and POST a fresh one:
|
|
189
|
+
`gh api repos/<REPO_SLUG>/pulls/<PR_NUMBER>/reviews/<REVIEW_ID> --method DELETE`
|
|
190
|
+
This is safe only because a pending review is visible to nobody else. Capture
|
|
191
|
+
the existing bodies first (`--jq '.body'` and `/reviews/<id>/comments`) so
|
|
192
|
+
nothing is lost if the re-POST fails.
|
|
193
|
+
- Verify by re-fetching the pending review and its comment count. Note that
|
|
194
|
+
`line`, `original_line`, and `side` come back `null` for comments on a pending
|
|
195
|
+
review -- that is expected, not a lost anchor. A successful POST (no 422) is
|
|
196
|
+
the receipt that the anchors were accepted.
|
|
197
|
+
|
|
198
|
+
---
|
|
199
|
+
|
|
200
|
+
## Notes
|
|
201
|
+
|
|
202
|
+
- Never add an `event` field to the payload (not even `"COMMENT"`) -- that
|
|
203
|
+
would publish the review immediately to all participants.
|
|
204
|
+
- The current authenticated user is whoever `gh auth status` reports.
|
|
205
|
+
- If `gh api` is not authenticated, stop and tell the user to run `gh auth login`.
|
|
@@ -0,0 +1,76 @@
|
|
|
1
|
+
# House rules (customize for your org)
|
|
2
|
+
|
|
3
|
+
This file is a template. lekker-review reads it as `PROJECT_RULES` and feeds
|
|
4
|
+
it to every review agent. Replace the example rules below with your own
|
|
5
|
+
team's non-negotiable conventions — the kind of thing that should always be a
|
|
6
|
+
**Critical** finding regardless of review depth, not a matter of taste.
|
|
7
|
+
|
|
8
|
+
A hard rule in this file should be:
|
|
9
|
+
- **Unambiguous** — a reviewer agent can check it mechanically against a diff.
|
|
10
|
+
- **Non-negotiable** — violating it is always wrong, not "usually" wrong.
|
|
11
|
+
- **Cheap to verify** — the review agent shouldn't need deep domain judgment.
|
|
12
|
+
|
|
13
|
+
If you have no hard rules yet, leave this file mostly empty (just the Stack
|
|
14
|
+
context section below) and let the 5 specialist agents rely on their own
|
|
15
|
+
judgment plus the repo's own CLAUDE.md / linter config.
|
|
16
|
+
|
|
17
|
+
---
|
|
18
|
+
|
|
19
|
+
## Example hard rules (replace with your own)
|
|
20
|
+
|
|
21
|
+
### EXAMPLE-1 — Type safety (TypeScript projects)
|
|
22
|
+
- No type casts (`as X`, `<X>expr`) outside test files.
|
|
23
|
+
- No `any` outside test files; even in tests, a blatantly untyped `any[]` on a
|
|
24
|
+
known-shaped list should still be flagged.
|
|
25
|
+
|
|
26
|
+
### EXAMPLE-2 — No generated files hand-edited
|
|
27
|
+
- Files under a `generated/` directory (codegen output, ORM types, GraphQL
|
|
28
|
+
types) must never be hand-edited in a diff — they should be regenerated
|
|
29
|
+
from source and the regen step re-run.
|
|
30
|
+
|
|
31
|
+
### EXAMPLE-3 — Pagination must be complete
|
|
32
|
+
- Any paginated API call (GraphQL `nodes` connections, REST cursor pagination)
|
|
33
|
+
must fetch every page, not just the first, unless a comment explains why a
|
|
34
|
+
partial fetch is intentional.
|
|
35
|
+
|
|
36
|
+
### EXAMPLE-4 — PR title must reference its ticket
|
|
37
|
+
- PR title must start with the ticket ID in brackets (e.g. `[PROJ-123]`),
|
|
38
|
+
covering every ticket referenced in the PR's commit history.
|
|
39
|
+
- Treat a missing/incomplete prefix as **blocking**: surface a prominent
|
|
40
|
+
`⛔ CANNOT MERGE` warning and the recommended title. This is a process rule,
|
|
41
|
+
not a code-quality signal, so it should not affect a confidence score.
|
|
42
|
+
|
|
43
|
+
---
|
|
44
|
+
|
|
45
|
+
## Repo placement check (multi-repo projects only)
|
|
46
|
+
|
|
47
|
+
If your org splits related concerns across sibling repos (e.g. a "backend
|
|
48
|
+
sync" repo and a separate "storefront/app" repo), add your own repo taxonomy
|
|
49
|
+
table here so the review agent can flag code landing in the wrong repo:
|
|
50
|
+
|
|
51
|
+
```
|
|
52
|
+
| Repo pattern | Purpose |
|
|
53
|
+
|--------------------|-----------------------------------------|
|
|
54
|
+
| `<pattern-a>` | <what belongs here> |
|
|
55
|
+
| `<pattern-b>` | <what belongs here> |
|
|
56
|
+
```
|
|
57
|
+
|
|
58
|
+
Note any exceptions (a repo that looks like pattern A but is actually a full
|
|
59
|
+
app, a legacy folder that shouldn't be used for new code, etc.) — placement
|
|
60
|
+
checks are only useful when they account for the real exceptions in your repo
|
|
61
|
+
layout, not the naming convention alone.
|
|
62
|
+
|
|
63
|
+
---
|
|
64
|
+
|
|
65
|
+
## Stack context (fill in for your project)
|
|
66
|
+
|
|
67
|
+
Give the review agents a one-paragraph map of your stack so they don't have
|
|
68
|
+
to rediscover it from the diff every time:
|
|
69
|
+
|
|
70
|
+
- **Backend:** <languages, frameworks, ORM, database>
|
|
71
|
+
- **Frontend:** <framework, UI library, build tool>
|
|
72
|
+
- **External APIs:** <third-party integrations worth knowing about, especially
|
|
73
|
+
ones with quirks: rate limits, OAuth flows, unusual pagination>
|
|
74
|
+
- **Infra:** <how the app runs locally and in CI>
|
|
75
|
+
- **Type/codegen pipeline:** <any source → generated-type steps that need to
|
|
76
|
+
stay in sync — flag stale generated output as a finding>
|
|
@@ -0,0 +1,232 @@
|
|
|
1
|
+
# Output format (Step 4)
|
|
2
|
+
|
|
3
|
+
## Step 4 — Format Output
|
|
4
|
+
|
|
5
|
+
Output is **one unified markdown document** — detailed enough to stand on its
|
|
6
|
+
own, clean enough to paste directly into GitHub. No ANSI split, no stripped
|
|
7
|
+
copy-paste block. Every finding includes location, the bad code, the reason,
|
|
8
|
+
and the fix — all in standard GitHub markdown.
|
|
9
|
+
|
|
10
|
+
Output the review as a markdown response (not via printf). No ANSI escapes.
|
|
11
|
+
|
|
12
|
+
---
|
|
13
|
+
|
|
14
|
+
### Output format
|
|
15
|
+
|
|
16
|
+
```
|
|
17
|
+
## Review — [PR #<PR_NUMBER> — <title>](<PR_URL>)
|
|
18
|
+
|
|
19
|
+
**Author:** <author> · **Branch:** `<headRefName>` → `<baseRefName>`
|
|
20
|
+
**Size:** +<additions>/-<deletions> across <changedFiles> files
|
|
21
|
+
**Head:** `<headRefOid short sha>`
|
|
22
|
+
**Linear:** [<ticket-id>](<linear-url>) — <ticket title>
|
|
23
|
+
**Findings:** <X Critical / Y Important / Z Observations / W Idiomatic>
|
|
24
|
+
**Proofs:** <M proven / N attempted> *(include only when N > 0)*
|
|
25
|
+
**CI:** <✅ All passing | ⚠️ N failing: check-name | ⏳ Pending | N/A>
|
|
26
|
+
**Depth:** <⚡ scan | 🔍 medium | 🔬 deep>
|
|
27
|
+
|
|
28
|
+
---
|
|
29
|
+
|
|
30
|
+
*(If PR_TITLE_ISSUE = true, insert this block here — before the Summary. Omit entirely if PR_TITLE_ISSUE = false.)*
|
|
31
|
+
|
|
32
|
+
> ⛔ **CANNOT MERGE — PR title missing Linear ticket prefix**
|
|
33
|
+
>
|
|
34
|
+
> The PR title must start with the Linear ticket(s) in square brackets.
|
|
35
|
+
> Recommended title prefix: **`<RECOMMENDED_PREFIX>`**
|
|
36
|
+
>
|
|
37
|
+
> How to fix: edit the PR title on GitHub to start with `<RECOMMENDED_PREFIX> <rest of current title>`.
|
|
38
|
+
|
|
39
|
+
---
|
|
40
|
+
|
|
41
|
+
## 🔁 Since last review
|
|
42
|
+
|
|
43
|
+
*(Re-review mode only — include when PREV_SHA was found. Omit entirely on first review.)*
|
|
44
|
+
|
|
45
|
+
Reviewed delta: `<PREV_SHA short>..<head short>`
|
|
46
|
+
|
|
47
|
+
- ✅ Fixed: <prior finding title> (`file:line`)
|
|
48
|
+
- ⚠️ Still open: <prior finding title> (`file:line`) — <one line on current state>
|
|
49
|
+
|
|
50
|
+
---
|
|
51
|
+
|
|
52
|
+
### Summary
|
|
53
|
+
|
|
54
|
+
A substantive 2–3 paragraph narrative — NOT a one-line recap. A reader who
|
|
55
|
+
hasn't seen the ticket or the diff should finish the Summary understanding
|
|
56
|
+
*why this work exists* and *what it buys the business/team*, before any finding.
|
|
57
|
+
Cover, in roughly this order:
|
|
58
|
+
|
|
59
|
+
- **The problem / goal — why this PR exists.** What was broken, missing, or
|
|
60
|
+
needed? Pull this from the Linear ticket (the AC_LIST and ticket summary),
|
|
61
|
+
not just the diff. State the user-facing or business outcome the change is
|
|
62
|
+
reaching for ("RSL can create P21 contacts automatically from Shopify instead
|
|
63
|
+
of hand-keying them", "unblocks the PUT/update flow that depends on the
|
|
64
|
+
metafield being populated").
|
|
65
|
+
- **What it does — the mechanism, in plain terms.** The shape of the solution:
|
|
66
|
+
the key entry points, the data flow, the gating/safety mechanisms, and how the
|
|
67
|
+
pieces fit. Name the design choices and *why each one was made* — kill switch
|
|
68
|
+
(so it can ship dark and be flipped per-environment), idempotency gate (so
|
|
69
|
+
re-deliveries don't duplicate), validation (so bad payloads fail fast and
|
|
70
|
+
non-retryably), stacking/deferral (so concurrency lands in a reviewable second
|
|
71
|
+
PR). The reader should learn the rationale, not just the inventory.
|
|
72
|
+
- **Risk level + recommendation.** Land on the overall risk and what you advise:
|
|
73
|
+
ship as-is, ship after the Important fixes, or hold. If the headline risk is a
|
|
74
|
+
single finding, name it here in one sentence and point forward to it.
|
|
75
|
+
|
|
76
|
+
Lead with the goal and the mechanism; keep the risk framing honest. This section
|
|
77
|
+
sets the altitude for everything below — a risky PR should read as risky. Do NOT
|
|
78
|
+
editorialize about what the PR does *well*: no praise, no "the win", no
|
|
79
|
+
"cleanly/nicely implemented", no complimenting the design. State what it does and
|
|
80
|
+
what the risks are — nothing about how good it is.
|
|
81
|
+
|
|
82
|
+
---
|
|
83
|
+
|
|
84
|
+
**Verdict: <✅ LGTM — ship it | ⚠️ LGTM with changes | 🚫 Needs work>**
|
|
85
|
+
|
|
86
|
+
---
|
|
87
|
+
|
|
88
|
+
## 🔥 Production Signals
|
|
89
|
+
|
|
90
|
+
*(Include only when SENTRY_SIGNALS has entries. Omit section entirely if empty.)*
|
|
91
|
+
|
|
92
|
+
- [<issue title>](<sentry-url>) — <N> events / <M> users (7d) · first seen <date>
|
|
93
|
+
Files: <relevant files from stack trace>
|
|
94
|
+
Note: <does this PR fix, worsen, or not affect this error?>
|
|
95
|
+
|
|
96
|
+
---
|
|
97
|
+
|
|
98
|
+
## 🚨 Critical — must fix before merge
|
|
99
|
+
|
|
100
|
+
### #1 — <short label>
|
|
101
|
+
|
|
102
|
+
**File:** `<path/to/file.ts>:<line>` · **Risk:** <one sentence — what breaks and when>
|
|
103
|
+
|
|
104
|
+
**Current code:**
|
|
105
|
+
\```ts
|
|
106
|
+
<the actual bad lines from the diff, verbatim>
|
|
107
|
+
\```
|
|
108
|
+
|
|
109
|
+
**Why it's wrong:** <explanation — what the code does vs what it should do.
|
|
110
|
+
Include the concrete failure: "lookup always returns undefined because the key
|
|
111
|
+
is triple-wrapped", "crashes with TypeError on Node 20 because Map.groupBy
|
|
112
|
+
does not exist", etc. If the author might not believe it, include a short
|
|
113
|
+
proof inline.>
|
|
114
|
+
|
|
115
|
+
**Fix:**
|
|
116
|
+
\```ts
|
|
117
|
+
<corrected version — exact drop-in replacement or minimal diff>
|
|
118
|
+
\```
|
|
119
|
+
|
|
120
|
+
**Proof — ran in the worktree:** *(include only when the finding carries a `proof` with `proven: true`)*
|
|
121
|
+
\```
|
|
122
|
+
<redOutput, verbatim>
|
|
123
|
+
\```
|
|
124
|
+
*Test asserts the correct behavior and fails because of this bug. It flips green when fixed.*
|
|
125
|
+
|
|
126
|
+
---
|
|
127
|
+
|
|
128
|
+
### #N — <label>
|
|
129
|
+
...
|
|
130
|
+
|
|
131
|
+
*(None.)* ← only if section is empty
|
|
132
|
+
|
|
133
|
+
---
|
|
134
|
+
|
|
135
|
+
## ⚠️ Important — should fix
|
|
136
|
+
|
|
137
|
+
(same per-finding format, continuing the numbering sequence)
|
|
138
|
+
|
|
139
|
+
*(None.)* ← only if section is empty
|
|
140
|
+
|
|
141
|
+
---
|
|
142
|
+
|
|
143
|
+
## 📝 Observations
|
|
144
|
+
|
|
145
|
+
- <note — tradeoff, risk to watch, or design question worth raising>
|
|
146
|
+
|
|
147
|
+
*(Omit section entirely if empty.)*
|
|
148
|
+
|
|
149
|
+
## 🧪 Test Quality
|
|
150
|
+
|
|
151
|
+
**Coverage verdict:** <✅ Well tested | ⚠️ Partially tested | ❌ Under-tested | N/A — no logic changes>
|
|
152
|
+
|
|
153
|
+
<One paragraph: overall assessment — what is tested, what is missing, and
|
|
154
|
+
whether the test suite would catch a regressing change to this code.>
|
|
155
|
+
|
|
156
|
+
**Gaps:**
|
|
157
|
+
- `test-file:line` — <gap or weakness>
|
|
158
|
+
- `test-file:line` — <implementation-coupled test: IO mocked to reach logic,
|
|
159
|
+
call-shape spy, component mocked for its props, query hook mocked, or an
|
|
160
|
+
implementation-detail assertion>
|
|
161
|
+
→ **Fix:** <no-mock refactor — usually "extract a pure function over plain
|
|
162
|
+
data and test that" or "inject a simple fake and assert the output">
|
|
163
|
+
|
|
164
|
+
*(Omit if no mocking issues. Do not flag legitimate mocks — error paths,
|
|
165
|
+
pinned non-determinism, un-runnable dependencies.)*
|
|
166
|
+
|
|
167
|
+
**Mutation-slip risk:** <paragraph — which mutation classes would go undetected,
|
|
168
|
+
if any. "No obvious gaps found." if clean.>
|
|
169
|
+
|
|
170
|
+
*(Omit section entirely if no test changes and no business logic changes.)*
|
|
171
|
+
|
|
172
|
+
---
|
|
173
|
+
|
|
174
|
+
## 💡 Idiomatic & Consistency
|
|
175
|
+
|
|
176
|
+
- **<deviation>** (`<file>:<line>`) — <the idiomatic alternative in one line>.
|
|
177
|
+
Precedent: `<file>:<line>` where the established pattern already lives.
|
|
178
|
+
|
|
179
|
+
*(Non-blocking suggestions — do NOT affect the verdict. Omit section entirely
|
|
180
|
+
if empty.)*
|
|
181
|
+
|
|
182
|
+
---
|
|
183
|
+
|
|
184
|
+
## 💰 Review Cost
|
|
185
|
+
|
|
186
|
+
```
|
|
187
|
+
Depth: <⚡ scan | 🔍 medium | 🔬 deep>
|
|
188
|
+
Diff size: ~<N> lines (~<N> tokens)
|
|
189
|
+
Agents run: <N total> — <breakdown, e.g. "5 reviewers (sonnet) + 6 verifiers (sonnet) + 2 provers (sonnet) + 1 critic (sonnet)">
|
|
190
|
+
Verify skipped: <N> hard-rule finding(s) exempt from adversarial verification (omit the line when 0)
|
|
191
|
+
Context sources: <the subset of issue-tracker / chat / docs / framework-docs / monitoring / CI / prior-review-memory actually used>
|
|
192
|
+
|
|
193
|
+
Output tokens: <N> ← ACTUAL workflow spend, from the workflow's outputTokens return value
|
|
194
|
+
Turn total: <N> ← whole-turn shared pool (turnTokensTotal), main loop included
|
|
195
|
+
Input tokens: ~<N> ← estimated: diff tokens × agent passes + context files + prompt files
|
|
196
|
+
|
|
197
|
+
Cost: ~$<X.XX> (output actual, input estimated; blended across model tiers below)
|
|
198
|
+
```
|
|
199
|
+
|
|
200
|
+
Per-MTok pricing (input/output) — verified 2026-07-07 from the claude-api reference; re-check there if models changed:
|
|
201
|
+
- claude-fable-5: $10 / $50
|
|
202
|
+
- claude-opus-4-8: $5 / $25
|
|
203
|
+
- claude-sonnet-4-6 / claude-sonnet-5: $3 / $15
|
|
204
|
+
- claude-haiku-4-5: $1 / $5
|
|
205
|
+
|
|
206
|
+
Reviewer agents, verifiers, provers, and the critic all run on sonnet; triage and housekeeping on haiku. Only the main loop (context gathering + this synthesis) runs on the session model — use the session model's actual ID for that tier.
|
|
207
|
+
|
|
208
|
+
---
|
|
209
|
+
|
|
210
|
+
### Finding format rules
|
|
211
|
+
|
|
212
|
+
- **File + Risk** on one line — the reader knows instantly what breaks and why
|
|
213
|
+
it matters before reading the proof.
|
|
214
|
+
- **Current code** block: verbatim lines from the diff, enough context to find
|
|
215
|
+
the spot (3–10 lines). Never paraphrase — paste the actual code.
|
|
216
|
+
- **Why it's wrong**: lead with the failure mode ("this always returns false
|
|
217
|
+
because…"), then the mechanism. Keep to 3–6 sentences. If a comparison or
|
|
218
|
+
counter-example makes it clearer, include it.
|
|
219
|
+
- **Fix** block: show the corrected version as a drop-in replacement. When the
|
|
220
|
+
fix is architectural (extract helper, add index), describe it concisely then
|
|
221
|
+
show a minimal skeleton if useful. If the fix touches consumers outside the
|
|
222
|
+
changed file, call that out explicitly — never show a partial fix that looks
|
|
223
|
+
self-contained but silently breaks callers.
|
|
224
|
+
- Blank line between findings. No double blank lines.
|
|
225
|
+
- No trailing whitespace, no HTML tags, no ANSI escapes.
|
|
226
|
+
- **Proof counter-evidence rule**: when `proof.attempted` is true but `proven`
|
|
227
|
+
is false because the code behaved correctly for the tested input, the
|
|
228
|
+
synthesis MUST treat that as counter-evidence — either downgrade the finding
|
|
229
|
+
or state in the finding body why the proof attempt doesn't exonerate it
|
|
230
|
+
(e.g. the tested input wasn't the one that actually breaks). A finding whose
|
|
231
|
+
proof came back green cannot silently stay Critical. When `attempted` is
|
|
232
|
+
false, say nothing — untestable is not evidence either way.
|
|
@@ -0,0 +1,77 @@
|
|
|
1
|
+
#!/bin/bash
|
|
2
|
+
# changed-files.sh -- lekker-review helper
|
|
3
|
+
# Determines the base ref for the branch checked out in WORKTREE_PATH and
|
|
4
|
+
# prints, one path per line on stdout, the files this branch has changed
|
|
5
|
+
# relative to that base. Prints the base ref actually used to stderr,
|
|
6
|
+
# prefixed "base-ref: ", so callers can capture it separately from the file
|
|
7
|
+
# list.
|
|
8
|
+
#
|
|
9
|
+
# Usage: changed-files.sh WORKTREE_PATH [--include-uncommitted]
|
|
10
|
+
# --include-uncommitted: also union in the worktree's uncommitted (working
|
|
11
|
+
# tree + staged) changes -- what a fix agent just wrote, even if it wasn't
|
|
12
|
+
# part of the original PR diff.
|
|
13
|
+
#
|
|
14
|
+
# Never fails: if no base ref can be resolved (or merge-base fails), prints
|
|
15
|
+
# NOTHING to stdout, "base-ref: unknown" to stderr, and exits 0. Callers
|
|
16
|
+
# should treat empty stdout as "could not scope -- fall back to repo-wide".
|
|
17
|
+
|
|
18
|
+
set -uo pipefail
|
|
19
|
+
|
|
20
|
+
WORKTREE_PATH="${1:?WORKTREE_PATH required}"
|
|
21
|
+
INCLUDE_UNCOMMITTED=false
|
|
22
|
+
[[ "${2:-}" == "--include-uncommitted" ]] && INCLUDE_UNCOMMITTED=true
|
|
23
|
+
|
|
24
|
+
# ---------------------------------------------------------------------------
|
|
25
|
+
# 1. Resolve a base ref: origin's default branch first, then a fixed
|
|
26
|
+
# fallback order.
|
|
27
|
+
# ---------------------------------------------------------------------------
|
|
28
|
+
BASE_REF=""
|
|
29
|
+
|
|
30
|
+
SYM_REF="$(git -C "$WORKTREE_PATH" symbolic-ref refs/remotes/origin/HEAD 2>/dev/null || true)"
|
|
31
|
+
if [[ -n "$SYM_REF" ]]; then
|
|
32
|
+
candidate="origin/${SYM_REF#refs/remotes/origin/}"
|
|
33
|
+
if git -C "$WORKTREE_PATH" rev-parse --verify --quiet "$candidate" >/dev/null 2>&1; then
|
|
34
|
+
BASE_REF="$candidate"
|
|
35
|
+
fi
|
|
36
|
+
fi
|
|
37
|
+
|
|
38
|
+
if [[ -z "$BASE_REF" ]]; then
|
|
39
|
+
for candidate in origin/staging origin/main origin/master; do
|
|
40
|
+
if git -C "$WORKTREE_PATH" rev-parse --verify --quiet "$candidate" >/dev/null 2>&1; then
|
|
41
|
+
BASE_REF="$candidate"
|
|
42
|
+
break
|
|
43
|
+
fi
|
|
44
|
+
done
|
|
45
|
+
fi
|
|
46
|
+
|
|
47
|
+
if [[ -z "$BASE_REF" ]]; then
|
|
48
|
+
printf 'base-ref: unknown\n' >&2
|
|
49
|
+
exit 0
|
|
50
|
+
fi
|
|
51
|
+
|
|
52
|
+
# ---------------------------------------------------------------------------
|
|
53
|
+
# 2. Merge-base + diff.
|
|
54
|
+
# ---------------------------------------------------------------------------
|
|
55
|
+
MERGE_BASE="$(git -C "$WORKTREE_PATH" merge-base HEAD "$BASE_REF" 2>/dev/null || true)"
|
|
56
|
+
if [[ -z "$MERGE_BASE" ]]; then
|
|
57
|
+
printf 'base-ref: unknown\n' >&2
|
|
58
|
+
exit 0
|
|
59
|
+
fi
|
|
60
|
+
|
|
61
|
+
printf 'base-ref: %s\n' "$BASE_REF" >&2
|
|
62
|
+
|
|
63
|
+
CHANGED_TMP="/tmp/lekker-changed-files-tmp-$$.txt"
|
|
64
|
+
git -C "$WORKTREE_PATH" diff --name-only "$MERGE_BASE" HEAD > "$CHANGED_TMP" 2>/dev/null || true
|
|
65
|
+
|
|
66
|
+
if [[ "$INCLUDE_UNCOMMITTED" == "true" ]]; then
|
|
67
|
+
git -C "$WORKTREE_PATH" diff --name-only HEAD >> "$CHANGED_TMP" 2>/dev/null || true
|
|
68
|
+
git -C "$WORKTREE_PATH" diff --name-only --cached >> "$CHANGED_TMP" 2>/dev/null || true
|
|
69
|
+
# Untracked-but-not-ignored files too: a fix agent that creates a new file
|
|
70
|
+
# (extracted helper, new test) and does not stage it is invisible to both
|
|
71
|
+
# diffs above, so its type/lint errors would escape attribution entirely.
|
|
72
|
+
git -C "$WORKTREE_PATH" ls-files --others --exclude-standard >> "$CHANGED_TMP" 2>/dev/null || true
|
|
73
|
+
sort -u "$CHANGED_TMP" -o "$CHANGED_TMP" 2>/dev/null || true
|
|
74
|
+
fi
|
|
75
|
+
|
|
76
|
+
cat "$CHANGED_TMP"
|
|
77
|
+
rm -f "$CHANGED_TMP"
|