@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.
Files changed (54) hide show
  1. package/.claude-plugin/plugin.json +2 -1
  2. package/README.md +7 -3
  3. package/catalog/skills.json +18 -0
  4. package/package.json +5 -3
  5. package/packages/software-development/lekker-review/SKILL.md +519 -0
  6. package/packages/software-development/lekker-review/adapters/claude/plugin.json +5 -0
  7. package/packages/software-development/lekker-review/adapters/claude/skills/lekker-review/SKILL.md +520 -0
  8. package/packages/software-development/lekker-review/adapters/claude/skills/lekker-review/references/agents/completeness-critic.md +21 -0
  9. package/packages/software-development/lekker-review/adapters/claude/skills/lekker-review/references/agents/conventions.md +124 -0
  10. package/packages/software-development/lekker-review/adapters/claude/skills/lekker-review/references/agents/fix-verifier.md +84 -0
  11. package/packages/software-development/lekker-review/adapters/claude/skills/lekker-review/references/agents/fixer.md +120 -0
  12. package/packages/software-development/lekker-review/adapters/claude/skills/lekker-review/references/agents/implementation.md +53 -0
  13. package/packages/software-development/lekker-review/adapters/claude/skills/lekker-review/references/agents/prover.md +135 -0
  14. package/packages/software-development/lekker-review/adapters/claude/skills/lekker-review/references/agents/quality.md +72 -0
  15. package/packages/software-development/lekker-review/adapters/claude/skills/lekker-review/references/agents/simplification.md +45 -0
  16. package/packages/software-development/lekker-review/adapters/claude/skills/lekker-review/references/agents/test-quality.md +170 -0
  17. package/packages/software-development/lekker-review/adapters/claude/skills/lekker-review/references/agents/triage-logic.md +27 -0
  18. package/packages/software-development/lekker-review/adapters/claude/skills/lekker-review/references/agents/triage-quality.md +41 -0
  19. package/packages/software-development/lekker-review/adapters/claude/skills/lekker-review/references/agents/verifier.md +295 -0
  20. package/packages/software-development/lekker-review/adapters/claude/skills/lekker-review/references/artifact-page.md +143 -0
  21. package/packages/software-development/lekker-review/adapters/claude/skills/lekker-review/references/context-gathering.md +162 -0
  22. package/packages/software-development/lekker-review/adapters/claude/skills/lekker-review/references/fix-mode.md +329 -0
  23. package/packages/software-development/lekker-review/adapters/claude/skills/lekker-review/references/github-post.md +205 -0
  24. package/packages/software-development/lekker-review/adapters/claude/skills/lekker-review/references/house-rules.md +76 -0
  25. package/packages/software-development/lekker-review/adapters/claude/skills/lekker-review/references/output-format.md +232 -0
  26. package/packages/software-development/lekker-review/adapters/claude/skills/lekker-review/scripts/changed-files.sh +77 -0
  27. package/packages/software-development/lekker-review/adapters/claude/skills/lekker-review/scripts/setup-worktree.sh +337 -0
  28. package/packages/software-development/lekker-review/adapters/claude/skills/lekker-review/scripts/verify-fixes.sh +231 -0
  29. package/packages/software-development/lekker-review/fix-workflow.js +273 -0
  30. package/packages/software-development/lekker-review/references/agents/completeness-critic.md +21 -0
  31. package/packages/software-development/lekker-review/references/agents/conventions.md +124 -0
  32. package/packages/software-development/lekker-review/references/agents/fix-verifier.md +84 -0
  33. package/packages/software-development/lekker-review/references/agents/fixer.md +120 -0
  34. package/packages/software-development/lekker-review/references/agents/implementation.md +53 -0
  35. package/packages/software-development/lekker-review/references/agents/prover.md +135 -0
  36. package/packages/software-development/lekker-review/references/agents/quality.md +72 -0
  37. package/packages/software-development/lekker-review/references/agents/simplification.md +45 -0
  38. package/packages/software-development/lekker-review/references/agents/test-quality.md +170 -0
  39. package/packages/software-development/lekker-review/references/agents/triage-logic.md +27 -0
  40. package/packages/software-development/lekker-review/references/agents/triage-quality.md +41 -0
  41. package/packages/software-development/lekker-review/references/agents/verifier.md +295 -0
  42. package/packages/software-development/lekker-review/references/artifact-page.md +143 -0
  43. package/packages/software-development/lekker-review/references/context-gathering.md +162 -0
  44. package/packages/software-development/lekker-review/references/fix-mode.md +329 -0
  45. package/packages/software-development/lekker-review/references/github-post.md +205 -0
  46. package/packages/software-development/lekker-review/references/house-rules.md +76 -0
  47. package/packages/software-development/lekker-review/references/output-format.md +232 -0
  48. package/packages/software-development/lekker-review/scripts/changed-files.sh +77 -0
  49. package/packages/software-development/lekker-review/scripts/setup-worktree.sh +337 -0
  50. package/packages/software-development/lekker-review/scripts/verify-fixes.sh +231 -0
  51. package/packages/software-development/lekker-review/workflow.js +602 -0
  52. package/site/assets/paperbag.css +707 -0
  53. package/site/assets/paperbag.js +218 -0
  54. 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"