Skip to content
Back to skills

Final Review

ASecurity

Use after a PR has been labeled `first pass reviewed` for at least 4 minutes — verifies CI is still green and no new commits landed since the label, aggregates outstanding non-blocking observations, posts an approval comment, replaces the label with `approved`, merges, and labels every issue referenced by `Closes #N` with `merged to dev`.

  • 7 stars
  • 0 votes
  • 0 copies
  • 1 view
  • Added May 27, 2026
toolsbashgitapi

Works with

  • api

Security analysis

A100/100

Pro scans all 4 files and shows the line behind each finding

Scanned May 27, 2026

npx -y skills add normalled/apijack --skill final-review --agent claude-code

Installs into .claude/skills of the current project.

Are you the author of Final Review?

Add the live security badge to your README. It updates with every re-scan.

Security grade badge for Final Review
[![Security: A — Skills Directory](https://www.skillsdirectory.com/api/skills/normalled-final-review/badge)](https://www.skillsdirectory.com/skills/normalled-final-review)

More formats (shields.io, HTML) on the badges page. Keep it an A: scan every change in CI with Pro.

Download with Pro
SKILL.md
---
name: final-review
description: Use after a PR has been labeled `first pass reviewed` for at least 4 minutes — verifies CI is still green and no new commits landed since the label, aggregates outstanding non-blocking observations, posts an approval comment, replaces the label with `approved`, merges, and labels every issue referenced by `Closes #N` with `merged to dev`.
---

# Final Review

Phase 4 of the apijack issue workflow. The first-pass reviewer leaves a PR with `first pass reviewed`. After a 4-minute soak window — long enough for a human to intervene, short enough to keep the loop moving — the final reviewer takes the PR across the line.

## When to Use

- A PR is labeled `first pass reviewed` and the label has been there for at least 4 minutes
- CI is fully green and the PR is mergeable
- No new commits have landed on the head since the first-pass-reviewed label was applied

This skill is invoked automatically by the `final-review` cron, or manually via `/final-review <pr>`.

## Steps

### 1. Verify the gate is still satisfied

The cron's `prompt_cmd` already gates on label-applied-time and head-vs-label staleness. Re-verify the rest before any write, **and capture the head SHA** — step 6 will pin the merge to it so a commit landing mid-flow can't be merged in unreviewed:

```bash
HEAD_SHA=$(gh pr view <pr> --json headRefOid --jq '.headRefOid')
gh pr view <pr> --json state,mergeable,mergeStateStatus,labels
gh pr checks <pr>
gh api "repos/normalled/apijack/pulls/<pr>/reviews" \
    --jq 'map(select(.state == "CHANGES_REQUESTED" and .dismissed_at == null)) | length'
```

Abort and STOP — without writing anything — if any of:

- PR state is not `OPEN`
- `first pass reviewed` is not currently on the PR
- Any check status is `fail`, `pending`, `queued`, or `in_progress`
- `mergeable` is `false` or `mergeStateStatus` indicates conflicts
- Any active "request changes" review (the count above is non-zero)

If the gate fails, leave a brief comment naming the failed check via `scripts/pr-comment.sh <pr> <body-file>` and stop.

### 2. Read the prior first-pass-review body

```bash
gh api "repos/normalled/apijack/pulls/<pr>/reviews" \
    --jq 'map(select(.body // "" | startswith("> 🤖 **Automated review by claude**")))
          | sort_by(.submitted_at) | reverse | .[0].body // empty'
```

Extract the bullets inside `<details><summary>Non-blocking observations</summary> ... </details>`. These are the items to surface in the approval comment. Ignore the `Nitpicks` block — too noisy for this summary.

### 3. Cross-reference open issues

For each non-blocking observation, check whether an open issue already tracks it:

```bash
gh issue list --repo normalled/apijack --state open --limit 50 --json number,title,body,labels
```

Match by topical keywords from the observation (function names, file paths, behaviors). If a single open issue clearly covers the bullet, append `(#NN)`. If unclear or no match, leave the bullet alone — do **not** invent issue links.

### 4. Build the approval body

Use the `Write` tool — never inline in a heredoc — to avoid backtick-escaping artifacts.

Write the body to `.claude-jobs/review-bodies/final-<pr>.md`. Then:

```bash
.claude/skills/review-issue/scripts/post-review.sh <pr> comment .claude-jobs/review-bodies/final-<pr>.md
```

You don't need to **literally** approve the PR. Just post a comment that _says you approve_. The workflow signal is the `approved` label moved in step 5.

#### Body template

```
> 🤖 **Final review by claude** — generated by the `final-review` skill. CI is green, no blockers, soak window elapsed. Marking approved and merging.

Approved.

### Outstanding observations from first-pass review

- <bullet copied verbatim from the first-pass body> [optional `(#NN)` link if a tracking issue exists]
- <next bullet>
```

If the first-pass review had no `Non-blocking observations` block at all, omit the `### Outstanding observations` heading entirely — keep the body to two short lines.

### 5. Move the label

```bash
.claude/skills/review-issue/scripts/set-review-label.sh <pr> "approved"
```

This atomically removes `first pass reviewed` and adds `approved`. Other PR labels are untouched.

### 6. Merge (SHA-pinned)

```bash
.claude/skills/final-review/scripts/merge-pr.sh <pr> "$HEAD_SHA"
```

The script pins the merge to `$HEAD_SHA`, so a commit landing between step 1 and step 6 causes GitHub to reject the merge with 409. **If the script exits non-zero, STOP** — do not retry. The cron will pick the PR up again next tick after the new commit gets a fresh first-pass review.

### 7. Label referenced issues with `merged to dev`

```bash
.claude/skills/final-review/scripts/label-merged-issues.sh <pr>
```

Parses the PR body for `Closes #N` / `Fixes #N` / `Resolves #N` and adds the `merged to dev` label to each referenced issue. The label marks the issue as shipped to dev, pending release to main. Idempotent and best-effort — per-issue failures are logged but do not fail the run.

### 8. Stop

This skill does NOT invoke `next-deployer`. Publishing to the rolling `next` channel is a separate concern; if you want it automated, that belongs in its own cron.

## Red Flags — Do Not Approve

- "CI has one flaky test, the rest pass" → STOP, leave a comment, ask a human
- "There's a `request-changes` review but it's old / unresolved" → STOP
- "The first-pass label is only 8 minutes old, close enough" → STOP, the cron will catch it next tick
- "There's a commit right after the first-pass label, but it's just a typo fix" → STOP, the first-pass review is stale; force a re-review
- "There's no prior first-pass body to read" → STOP, the cron should have filtered this out; abort defensively

## Output

Either: an approving review + merged PR + deleted branch, or: a comment naming the failed gate and STOP.

Files in this skill

  • SKILL.md5.7 KB
  • scripts/find-final-review-candidate.sh1.6 KB
  • scripts/label-merged-issues.sh1.8 KB
  • scripts/merge-pr.sh731 B

Attribution

Is this your skill, or is something wrong with this listing? Request removal or report an issue. Author removals are honored within 72 hours.

Comments

Loading comments…

Newsletter

Get the weekly list of safe new skills, and the ones we pulled.