---
name: review-jev-comments
model_tier: light
description: |
  Use when: an ADDITIONAL, machine-scored pass is wanted over open PR review comments
  already in the existing ledger — never replacing any other reviewer, and never
  auto-replying or auto-resolving. Dispatched by review-orchestrator in Wave B, via the
  CLI (`keryx review jev-comments`), when `review.jev.comments: true` in
  .metaproject/tasks.config.json and a Jev/OpenRouter credential is resolvable. It is not
  an LLM sub-agent: there is nothing to dispatch through a platform-native agent
  mechanism, and no prose is generated by a model — Jev only answers a `choice` among
  resolved-by-fix/still-open/not-actionable/needs-escalation per open comment; keryx
  writes every word of every finding.
  NOT for: posting a reply, resolving a thread, or deciding what `keryx review comments
  reply` sends — this reviewer only ever reads the ledger and labels.
triggers:
  - "jev comments"
  - "open comments"
  - "review --jev-comments"
metadata:
  author: "MrCipherSmith"
  version: "1.0.0"
  category: "review"
  compatible_harnesses: "cursor,codex,zed,opencode,claude"
  engine: "jev"
  origin: "authored"
license: "MIT"
---

# Review — Jev Comments (open PR comment triage)

An ADDITIONAL orchestrator reviewer, flow 333. It is a **keryx program**, not an
LLM sub-agent: `review-orchestrator` never dispatches a platform-native agent
for it, it runs `keryx review jev-comments` and reads the `--json` output.
Every finding is composed by keryx; Jev ("System One" on OpenRouter) supplies
only a `choice` label per comment — it never writes prose, and nothing it
returns is quoted verbatim into a finding. Its inputs are the reviewer payload only; session memory and earlier conversation are not inputs.

---

## What it does

1. Reads open comments from the EXISTING ledger
   (`.metaproject/reviews/pr-comments/*.json`, written by `keryx review
   comments collect`) — never re-collects from GitHub itself.
2. Computes deterministic facts per open comment: commits after the comment's
   timestamp touching its file (local `git log`, capped), the review thread's
   resolved flag (best-effort, via one read-only GraphQL query — degrades to
   `"unknown"` on any failure, never a guess), and its replies already on the
   ledger.
3. Asks Jev exactly ONE `choice` question per open comment (batched under the
   vendor's 64k token budget): `resolved-by-fix` / `still-open` /
   `not-actionable` / `needs-escalation`, given the comment, its replies, and
   the code's current hunk(s) at that location.
4. Synthesizes findings for `still-open` (severity `minor`) and
   `needs-escalation` (severity `major`) only — `resolved-by-fix` and
   `not-actionable` produce no finding. It never posts a reply and never
   resolves a thread; the choice for every open comment is also written to an
   advisory-label cache
   (`.metaproject/data/review-jev-comments/labels__<repo>__<n>.json`) that
   `keryx review comments reply` reads back and prints, informationally, next
   to its own output — it never changes what that command sends.

---

## Input Contract

Not dispatched with a prompt — invoked as a CLI command:

```text
keryx review jev-comments --pr <n> --repo <owner/repo>
                          [--model <jev-1.13|jev-latest>] [--fixtures <dir>] [--json]
```

Requires a comment ledger to already exist for `--repo`/`--pr` (`keryx review
comments collect` first) — this reviewer refuses, before any read, when it
does not.

---

## Opt-in and privacy

Refuses before any ledger read or network call unless
`.metaproject/tasks.config.json` declares:

```json
{ "review": { "jev": { "comments": true } } }
```

Every comment body, reply, and hunk sent to Jev is redacted first through
`src/security/service.ts` — the same floor every other Jev-backed reviewer
applies. No cache or output file stores a credential.

---

## Output Contract

Emits a `REVIEW_RESULT`-shaped object matching
`.metaproject/skills/gdskills/review/review-orchestrator/reviewer-finding.schema.json`
— `status`, `reviewer: "review-jev-comments"`, `summary`, `findings`, `stats`
— under `--json`. Its findings merge into the consolidated array exactly like
any other reviewer's: same Quality Gate, same dedup, same Wave C
verification.

### Class scope — required for `blocker` and `major`

A `needs-escalation` finding is `major` and always carries `class_scope`:
`sites` is the single `file:line` the comment is anchored to, and
`enumeration_method` states it is exactly that one comment — there is no
"class" beyond it, one comment is one finding, never a set to enumerate
further. `still-open` is `minor` and carries none, matching the schema's own
rule (`class_scope` required only for `blocker`/`major`).

---

## Orchestrator integration

- `keryx review reviewers --json` lists it under `bundled` with
  `"engine": "jev"`.
- `review-orchestrator` dispatches it in **Wave B**, alongside the domain/
  convention reviewers, when the opt-in is on and a Jev/OpenRouter credential
  resolves (`resolveJevApiKeyResolution`). When either is false it is
  **skipped with the stated reason**, recorded in `Skipped reviewers` —
  never silently absent.
- It is **ADDITIONAL** and strictly advisory over the comment-reply flow: its
  label is printed by `keryx review comments reply`, never acted on
  automatically.

---

## Red Flags

| Rationalization | Why it is wrong |
|---|---|
| "Jev said still-open, so post a reply now" | This reviewer never posts anything — a `still-open`/`needs-escalation` finding is a signal for a human or `keryx review comments reply`'s own logic, not an instruction to act |
| "The thread's resolved flag came back unknown, so treat it as resolved" | `unknown` is a distinct, honest state — it means the read failed, not that the thread is closed |
| "No findings means every comment was addressed" | Only `still-open`/`needs-escalation` produce findings; `resolved-by-fix` and `not-actionable` are correctly silent, but check `openComments` in `--json` to see how many were actually judged |

---

## Verification

Before trusting a run's findings:

1. Read `openComments` in the `--json` output against the ledger's own
   `unanswered so far` count from the last `comments collect` — they should
   agree.
2. Spot-check a `needs-escalation` finding against the comment text: does it
   actually block progress, or is it a `still-open` case Jev over-called?
3. Confirm every finding carries `reviewer: "review-jev-comments"` and a
   `dedupe_key` — both are required for the orchestrator's Quality Gate and
   Wave C verification to route it correctly.

---

## Iron Laws

### Shared laws (every reviewer)

1. **A claim of runtime harm with no reproducible path is `info`.** If you cannot name the input, call, or condition that reaches the code, you have an observation, not a finding. Report it as `info` and say what would settle it.
2. **Never flag the theoretical.** The path you describe must exist in the code under review. Do not report a safe API because it could be misused, or a pattern because it is often wrong elsewhere.
3. **One finding per class, not one per occurrence.** When the same shape appears at several sites, report it once and list every site. Ten findings that are one finding hide the other nine problems.
4. **A deliberate choice is not a defect until its reason is read and shown wrong.** An explicit override, suppression or exemption, a comment or commit giving a reason, or a sibling doing the same is a decision: read its reason (the comment, `git log -L` or `git blame`, the sibling) before you report it, and report it only when you can show that reason wrong. A project rule is checked against accepted platform practice and its known exceptions before a deviation from it is reported.

Severity levels are defined once, in `review-orchestrator/SKILL.md` →
**Severity (canonical)**. This reviewer does not restate them: it emits only
`minor` (`still-open`) or `major` (`needs-escalation`, always with
`class_scope`) — `blocker` never applies to an unanswered comment.

---

## Scope Boundaries

| Concern | This skill | Use instead |
|---------|------------|-------------|
| An open PR comment looks unaddressed or blocking | YES | — |
| Posting a reply, resolving a thread | NO | `keryx review comments reply`, a human |
| Judging whether a reported finding is real | NO | `review-verifier` |
| Collecting comments from GitHub | NO | `keryx review comments collect` |
