Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
13 changes: 8 additions & 5 deletions .github/cursor-review/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,7 @@ PR gets the `cursor-review` label
│ Google ▢ ▢ │
│ Moonshot ▢ ▢ │
│ │
│ each cell: build prompt → run cursor-agent → extract-findings.py
│ each cell: cursor-agent records findings through a stdio MCP tool
└───────────────────────────────┬───────────────────────────────────────┘
│ 8 findings artifacts
Expand Down Expand Up @@ -71,9 +71,12 @@ Each model runs **two review types**:
[`prompt-edge-case.md`](prompt-edge-case.md).

A single **judge** model ([`prompt-judge.md`](prompt-judge.md)) then adjudicates
all 8 cells' findings into the final review. If a cell fails (checkout, agent,
extraction), it still shows up in the panel summary tagged `error` rather than
silently vanishing — the review tells you what didn't run.
all 8 cells' findings and submits the final review through the same slim stdio
MCP server. Model prose is never parsed for results: tool schemas validate the
records before writing them, which removes formatting drift, markdown fences,
truncated JSON, and reformat retries from the result path. If a cell fails
(checkout, agent, or tool submission), it still shows up in the panel summary
tagged `error` rather than silently vanishing.

## What's in this directory

Expand All @@ -82,7 +85,7 @@ silently vanishing — the review tells you what didn't run.
| [`prompt-adversarial.md`](prompt-adversarial.md) | Prompt for the security/reliability review pass. |
| [`prompt-edge-case.md`](prompt-edge-case.md) | Prompt for the correctness/logic review pass. |
| [`prompt-judge.md`](prompt-judge.md) | Prompt the judge model uses to consolidate panel findings into one review. |
| [`extract-findings.py`](extract-findings.py) | Parses a cell's raw `cursor-agent` output into a normalized findings record. Always emits structured JSON — even on empty output or parse failure — so the consolidate step has uniform input. |
| [`review-output-mcp.py`](review-output-mcp.py) | Dependency-free stdio MCP server. Reviewers record individual findings and finish; the judge submits the final findings array. It validates and atomically writes the normalized records consumed by later jobs. |
| [`post-review.py`](post-review.py) | Reads the judge's consolidated findings and posts **one** PR review with line-anchored inline comments and severity badges. |
| [`gate-unresolved.py`](gate-unresolved.py) | The opt-in blocking gate (`blocking: true`). Queries the PR's review threads and exits non-zero while any cursor-review finding thread is unresolved. |
| [`slack-notify.sh`](slack-notify.sh) | Sends the start/complete Slack DMs to the triggerer (no-ops without a token). |
Expand Down
193 changes: 0 additions & 193 deletions .github/cursor-review/extract-findings.py

This file was deleted.

4 changes: 2 additions & 2 deletions .github/cursor-review/post-review.py
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@
...
],
"panel": [
{"model": str, "review_type": str, "status": "ok"|"empty"|"error"|"parse_error"},
{"model": str, "review_type": str, "status": "ok"|"error"},
...
]
}
Expand All @@ -28,7 +28,7 @@
import sys

# Severity scale, ordered most → least urgent. Drives sort order, the inline
# comment prefix, and the summary table. The judge is instructed to emit one
# comment prefix, and the summary table. The judge tool accepts one
# of these strings per finding (see prompt-judge.md); anything missing or
# unrecognized falls back to DEFAULT_SEVERITY so a malformed value can never
# drop a finding — it just lands in the middle bucket.
Expand Down
27 changes: 12 additions & 15 deletions .github/cursor-review/prompt-adversarial.md
Original file line number Diff line number Diff line change
Expand Up @@ -19,25 +19,22 @@ Do NOT flag:
- Performance micro-optimizations unless they create a DoS vector
- Issues in test files unless the test itself is masking a real bug

Review the following diff and report every finding. You MUST respond with ONLY a JSON
array — no prose, no markdown fences, no explanation outside the array.

Each element must be an object with exactly these keys:
- "file": string — the file path relative to the repo root
- "line": integer — the line number in the NEW side of the diff where the issue exists
- "side": "RIGHT" — always RIGHT since findings are on the new code
- "severity": string — one of "critical", "high", "medium", "low", "nit"
Review the following diff and record every finding with the
`cursor_review_record_finding` tool. Call it once per distinct issue using:
- `file`: the file path relative to the repo root
- `line`: the line number in the NEW side of the diff where the issue exists
- `side`: `RIGHT` since findings are on the new code
- `severity`: one of `critical`, `high`, `medium`, `low`, `nit`
("critical" = exploitable hole / data loss / crash on a normal path;
"high" = real bug on a plausible input; "medium" = bug on an edge path;
"low" = minor security/reliability concern; "nit" = very low-impact security/reliability concern)
- "body": string — a concise description of the issue (1-3 sentences)
- `body`: a concise description of the issue (1-3 sentences)

If you find no issues, return an empty array: []
After recording all findings, call `cursor_review_finish` exactly once. Call it
even if you found no issues. Do not put findings in your final response: only
tool calls are collected.

Example response:
[
{"file": "internal/api/handler.go", "line": 42, "side": "RIGHT", "severity": "critical", "body": "User-supplied `filename` is passed to `os.Open` without path-traversal validation. An attacker can read arbitrary files with `../../etc/passwd`."},
{"file": "internal/worker/upload.go", "line": 118, "side": "RIGHT", "severity": "high", "body": "The goroutine captures `ctx` from the outer scope but the parent function returns and cancels the context before the upload completes, causing silent data loss."}
]
Example `cursor_review_record_finding` arguments:
`{"file":"internal/api/handler.go","line":42,"side":"RIGHT","severity":"critical","body":"User-supplied filename is passed to os.Open without path-traversal validation."}`

=== BEGIN DIFF ===
27 changes: 12 additions & 15 deletions .github/cursor-review/prompt-edge-case.md
Original file line number Diff line number Diff line change
Expand Up @@ -21,25 +21,22 @@ Do NOT flag:
- Performance optimizations unless they cause correctness issues
- Issues in test files unless the test itself is masking a real bug

Review the following diff and report every finding. You MUST respond with ONLY a JSON
array — no prose, no markdown fences, no explanation outside the array.

Each element must be an object with exactly these keys:
- "file": string — the file path relative to the repo root
- "line": integer — the line number in the NEW side of the diff where the issue exists
- "side": "RIGHT" — always RIGHT since findings are on the new code
- "severity": string — one of "critical", "high", "medium", "low", "nit"
Review the following diff and record every finding with the
`cursor_review_record_finding` tool. Call it once per distinct issue using:
- `file`: the file path relative to the repo root
- `line`: the line number in the NEW side of the diff where the issue exists
- `side`: `RIGHT` since findings are on the new code
- `severity`: one of `critical`, `high`, `medium`, `low`, `nit`
("critical" = data loss / crash on a normal path; "high" = real bug on a
plausible input; "medium" = bug on an edge path; "low" = minor correctness issue;
"nit" = very low-impact correctness/clarity issue)
- "body": string — a concise description of the issue (1-3 sentences)
- `body`: a concise description of the issue (1-3 sentences)

If you find no issues, return an empty array: []
After recording all findings, call `cursor_review_finish` exactly once. Call it
even if you found no issues. Do not put findings in your final response: only
tool calls are collected.

Example response:
[
{"file": "pkg/retry/retrier.go", "line": 55, "side": "RIGHT", "severity": "high", "body": "When `maxRetries` is 0 the loop body never executes, so the function returns `nil` instead of running the operation once. The guard should be `i <= maxRetries`."},
{"file": "internal/router/router.go", "line": 203, "side": "RIGHT", "severity": "medium", "body": "The `default` branch of the select sends on `errCh` without checking if the channel is full. If two goroutines hit this path simultaneously the second send blocks forever, leaking the goroutine."}
]
Example `cursor_review_record_finding` arguments:
`{"file":"pkg/retry/retrier.go","line":55,"side":"RIGHT","severity":"high","body":"When maxRetries is 0 the loop never executes, so the operation is not attempted."}`

=== BEGIN DIFF ===
27 changes: 12 additions & 15 deletions .github/cursor-review/prompt-judge.md
Original file line number Diff line number Diff line change
@@ -1,13 +1,8 @@
RESPOND WITH ONLY A JSON ARRAY. Your entire response must be a single JSON
array of finding objects (or `[]` if none) — no prose, no preamble, no
explanation, no markdown code fences before or after it. Do not narrate your
reasoning. The exact element schema is specified at the end of this prompt.

You have NO shell, filesystem, or web/search tools in this environment. Do not
attempt to use them and do not narrate attempts to (e.g. "shell execution isn't
available here", "let me confirm via documentation", "verification changes my
adjudication"). Adjudicate solely from the panel findings and diff provided
below, and emit ONLY the JSON array — any prose preamble breaks the contract.
below, then submit the result through the final-review tool.

You are a senior software engineer adjudicating findings from a panel of AI
code reviewers. The panel ran a 4-lab × 2-review-type matrix (8 cells total):
Expand All @@ -34,17 +29,17 @@ Selection guidance:
- Cap the final list at 10 findings. Below 10 is fine if there genuinely
aren't more.

Output: a JSON array, no prose, no markdown fences. Each element is an
object with exactly:
- "file": string — repo-relative path
- "line": integer — a line number that appears on the RIGHT (new) side of
Submit the result exactly once with the `cursor_review_submit_final` tool. Its
`findings` argument contains each kept finding using:
- `file`: repo-relative path
- `line`: a line number that appears on the RIGHT (new) side of
one of the diff hunks below. Lines that aren't in any hunk cannot be
anchored as inline comments — GitHub will reject them. If a finding's
natural anchor isn't shown in the diff, RETARGET it to the nearest
RIGHT-side line that IS in a hunk, or DROP the finding.
- "side": "RIGHT" — always
- "severity": string — exactly one of "critical", "high", "medium", "low",
"nit". Use this rubric:
- `side`: `RIGHT` — always
- `severity`: exactly one of `critical`, `high`, `medium`, `low`, `nit`.
Use this rubric:
- "critical": exploitable security hole, data loss/corruption, or a crash
on a normal path. Ship-blocker.
- "high": a real bug that will misbehave on a plausible input, or a serious
Expand All @@ -53,11 +48,13 @@ object with exactly:
a blocker.
- "low": minor correctness or robustness issue with limited impact.
- "nit": style, naming, or polish — optional to address.
- "body": string — concise (1-3 sentences). Do NOT prefix the body with a
- `body`: concise (1-3 sentences). Do NOT prefix the body with a
severity word or emoji; the severity field drives the rendered badge. END
with attribution like
`_Raised by 3 of 8 reviewers (gpt-5.3-codex-xhigh adversarial, claude-opus-4-8-thinking-xhigh edge-case, gemini-3.1-pro adversarial)._`

Order the array most-severe first. If no findings rise to the bar, return [].
Order findings most-severe first. If no findings rise to the bar, submit an
empty `findings` array. Do not put the result in your final response: only the
tool call is collected.

=== BEGIN PANEL FINDINGS ===
Loading