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
275 changes: 0 additions & 275 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 ===
Loading