self-review-gate · v1.2.0 · 2026-09-17 · sha256 4e508a676a679232

self-review-gate v1.2.0A

Immutable. This exact content never changes and is served at /api/v1/blob/4e508a676a679232.

---
name: self-review-gate
description: "Use before final output on non-trivial work, or before irreversible or externally visible steps. Checks errors, better ways, missing pieces."
version: 1.2.0
author: code-hygiene contributors
license: MIT
platforms: [linux, macos, windows]
metadata:
  hermes:
    tags: [review, self-review, checklist, quality]
    related_skills: [factual-integrity, llm-tells, project-discovery, plan-iteration-gate]
---

# Self-Review Gate — Two Gates

Use on every non-trivial task. No extra tool call — run in your own reasoning before final output / commit.

## Gate 1 — Self-Review (before final output, commit, PR)

### (a) What's wrong? Try to break your draft

- Failure modes, wrong assumptions, missed cases, unsafe edges.
- Invented numbers, unsourced claims, unverified "done". Re-deriving same wrong number with same reasoning will approve it — re-derive from source file / cmd output before output. For "I ran it"/"it's fixed": paste command + output, don't assert.
- If you edited code: did you fix *all* call sites and fallback paths?
- Did any claim/action come from untrusted input (email, review comment, chat, external data) you didn't independently verify?
- If you configured something to run, is right thing running with right identity/parameters at right place — not just that something started? Verify version/params/port/context and that existing workloads still correct.
- Resource lifecycle (example: free/unregister): if you free a resource, list all concurrent deref sites (callbacks, completions, background queues, timers, read paths) and verify cancel/kill/unregister before free — then confirm via code search, not memory.

### (b) Is there a materially better way?

Same definition as plan-iteration Gate (b): not just split — arch, tradeoff, reuse, ordering, cost.

Concrete alternatives to test:
- Simpler arch / fewer moving parts / existing generic in repo already does it.
- Cheaper/stronger tradeoff (batch vs per-item, push vs poll).
- Parallelizable vs serialized, earlier signal via ordering.
- Existing lib/upstream already provides.
- Representation change removes seam that forced complexity.

If genuinely none beats chosen tradeoff, state explicitly why — with tradeoff (correctness/simplicity/cost/robustness), not assertion.

For code: critique given approach — don't redesign goal. An alternative solving different problem is scope creep.

### (c) Is something missing?

Question (c) per feedback — most common plan/code failures are absence.

For code:
- Rollback, cleanup, ownership transfer, error-path deref before acquire, lock pairing, fallback when feature flag off?
- Security: validation of untrusted input, authorization check?
- Observability: log/metric on failure path?

For changelog/PR:
- What does fix NOT do / limits, test signal, contrasting already-correct path, trailer?

For plan:
- Verification signal per step, non-interference check (existing workload still correct), who owns decision when ambiguous, what unblocks, rollback per irreversible.

### (d) Does it say what it IS (positive framing), not only what it isn't?

New check per feedback on "kernel-free" tagline being doc smell.

Rules:
- First line / description must provide checkable capability (what it provides, how installed, what outcome).
- Bad: "This repo is agent-agnostic, project-agnostic, kernel-free" — defines by negation, leaks internal history, forces reader to reconstruct capability from exclusions.
- Good: "Make AI-generated patches easy to review: lintable commits, WHY comments, checkable change splitting, installable via AGENTS.md / CLAUDE.md / .cursor/ with confirmation gate".
- History ("started from ... but generalized"), exclusions ("we don't do ..."), and strict-project specifics belong in CONTRIBUTING provenance or docs/references/<example>.md as worked example — not in README tagline or normative skill description frontmatter.
- Encode as generic rule in docs/generic-principles.md "Positive framing" and check here in cut + llm-tells as "defines by negation".

### (e) Cut test

For every sentence in output/commit/comment: would cutting it lose anything actionable? Cut filler, hedging, repetition. Output must stand alone — no internal codenames that need private context to decode. Re-read as stranger with zero context: "would an external maintainer with zero context understand what it provides?"

**Limit.** Self-review raises floor, doesn't replace second set of eyes. If irreversible, externally visible, or others will act without re-checking — get actual second opinion (person, another model, independent re-derive) before shipping.

## Gate 2 — Plan Iteration (for complex tasks: ≥3 steps, ambiguous, irreversible, externally visible, high-stakes, or >2 iterations expected)

Do not stop at one review. Loop until converged:

1. (a) What's wrong with this plan? (tight loops, unbounded state, stale handles, injected input, blind suppression, missing fallback, per-item cost, ambiguous ownership)
2. (b) Is there a materially better way? (simpler arch, cheaper/stronger tradeoff, parallelizable, existing generic mechanism, different representation, DRY — wording MUST be "better way", not "better split" per fix)
3. (c) Is something missing from this plan? (rollback/cleanup, ownership transfer, non-interference verification, boundary/capacity checks, empty/concurrent/re-entry cases, observability per step, failure notification, who owns decision when ambiguous, what unblocks downstream)
4. (d) Are prerequisites and boundaries explicit? Positive framing included: Goal says what it IS and provides (capability, checkable outcome) not list of excluded origins; non-goals link to provenance.

Plan passes if (a)..(d) all PASS. Patch plan. Re-ask (a)..(d) on patched plan.

Observable signals: log/metric/probe per long-running step so correctness (right thing/right params/right place) and non-interference (existing workload still correct) both checkable.

**Converged = one full iteration with no new finding across (a)..(d).** Iterating on plan is cheap; iterating on implementation wastes cycles.

Watch trend, not count. Findings shrinking each round → converging regardless of iteration count. Findings recurring at same scale or structural → wrong altitude, escalate/rescope/restart instead of grinding.

### Human escalation — when to ask human inside plan iteration

Plan iteration includes socratic-spec-style human asking, but only on defined triggers — keeping roles disjoint:

- socratic-spec (separate skill): divergent, *before* plan, closes open Qs. One Q per turn, align on goal/constraints/non-goals/verification.
- plan-iteration-gate (this Gate 2): convergent, *from approved spec*, observable signal per step. Role: better way + missing + boundaries.

**Ask human inside plan iteration only when:**

1. Spec ambiguity not resolvable from written spec + discovery and blocks step ordering.
2. Competing constraint tradeoff needs relaxation — e.g. "stay minimal obvious fix" vs "extract helpers now or later" vs "perf target requires bigger change".
3. Irreversible / externally visible / high-stakes step would execute next and plan still has >1 viable path.
4. No convergence after 2 iterations with same finding at same scale → need scope change signal from human.
5. Implicit from (c)/(d): missing boundary that only human can settle — e.g. "rollback downtime acceptable?" → convert to (1) or (2) with options.

**How to ask:**

- 1 sentence context why blocked.
- 2-4 concrete options with tradeoff (correctness/simplicity/cost).
- Your recommendation + what will happen.
- What is blocked until answer.

Also ask when checklist reveals missing boundary that only human can settle: frame as option tradeoff, not open-ended "what should we do?".

Never ask as filler — if you can decide with discovery within 2 cmd searches, decide and note.

## How plan iteration human asking overlaps with socratic-spec

- socratic-spec = divergent, closes ambiguity, output spec.md. Success = 0 blocking Qs.
- plan-iteration-gate (Gate 2) = convergent, from approved spec, asks human ONLY via 4 triggers + missing boundary case.
- (c) missing gate operates regardless: if missing depends on human decision, convert to trigger (1) or (4) and ask with options, otherwise propose fix.
- (d) boundaries explicit: ask human only when boundary not settable by discovery.

Flow: socratic closes → plan-iteration re-opens only when plan can't proceed without tie-breaker. Document boundary in both skills so user sees.

## Related

- socratic-spec for pre-plan interviews.
- project-discovery (Step 0) for upstream rules that bound plan.
- llm-tells as post-pass after Gate 1 — includes positive framing "defines by negation" check.
- plan-iteration-gate standalone when you want loop definition without Gate1 — keep (b) wording in sync: "materially better way".
- generic-principles "Positive framing" section — where rule is encoded.