---
name: apt:review
description: "Task-level code review — 6-pass inline analysis with fix-all pipeline"
apt-skill-version: {{APT_VERSION}}
stage: review
intent: ship
when_to_use: "Inline task-level 6-pass review during /apt:run (logic, security, quality, architecture, performance, docs-coherence) with fix-all. NOT for reviewing a GitHub PR by number or URL — use /apt:pr-review for that."
user_invocable: true
internal: false
spawns_agent: true
agent_name: "apt-reviewer"
task_context: require-existing
default_execution_mode: auto
execution_modes:
  - auto
  - step
allowed-tools: "Read, Bash, Grep, Glob"
argument-hint: "apt:review [--skip-docs | --fix-all]"
gates: 
  - verify-approved
config_keys:
  - pipeline.skip_review
---
<objective>
Review the code produced by a task's execution, analyzing logic, security, quality, architecture, and performance. Fix all findings. Update task documentation. Report what's next.

This is the **task review** — a lightweight inline review that runs as part of the pipeline (plan → execute → verify → **review**). As of C32, review is the terminal stage of the STANDARD and DEEP auto pipelines invoked by `/apt:run`; pass `--skip-review` only if you intentionally want to stop after verify. For heavy multi-agent PR reviews with worktree isolation, use `/apt:pr-review` instead.
</objective>

<your_environment>
- **Working directory:** The project root (where you were invoked)
- **apt-tools path:** `node packages/framework/bin/apt-tools.mjs` or the locally installed `apt-tools` binary
- **Constitution:** Read `AGENTS.md` in the project root if it exists
- **Task directory:** `{task_dir}` — passed from the router or apt:run. All artifacts are read/written here.
- **Artifacts:** `{task_dir}/spec.md`, `{task_dir}/implementation_plan.json`, `{task_dir}/build-progress.json`, `{task_dir}/qa_signoff.json`
</your_environment>

<state_files>
## State Files

**Reads:**
- `AGENTS.md` — Project constitution (conventions, architecture patterns)
- `{task_dir}/spec.md` — Requirements and acceptance criteria
- `{task_dir}/implementation_plan.json` — Subtask list
- `{task_dir}/qa_signoff.json` — QA scores from verify phase
- `.aperant/context/notes/{task-id}.md` — **Decision ledger (R6).** If present, read and inject a ≤500-token digest of locked decisions at the top of any reviewer subagent prompt (see `<decision_ledger_inject>` below).
- Git diff of the task's changes

**Writes:**
- `{task_dir}/review.json` — Structured findings with severity, category, and suggestions
</state_files>

<decision_ledger_inject>
## Decision Ledger Re-Injection (R6)

Before spawning any reviewer subagent, check for `.aperant/context/notes/{task-id}.md`. If present, extract a ≤500-token digest of locked decisions from `/apt:discuss` and prepend it to every subagent prompt under:

```
<locked_decisions source=".aperant/context/notes/{task-id}.md">
{digest}
</locked_decisions>
```

This prevents reviewers from flagging decisions the team already settled, which would otherwise show up as spurious findings.
</decision_ledger_inject>

<process>

## 1. Load Context

1. Read `AGENTS.md` if it exists — extract conventions, architecture boundaries, security/test requirements
2. Read `{task_dir}/spec.md` — understand what was supposed to be built
3. Read `{task_dir}/qa_signoff.json` if it exists — see what verify already caught
4. Get current task state:

```bash
node packages/framework/bin/apt-tools.mjs state .
```

### Mark lifecycle phase as `reviewing`

```bash
node packages/framework/bin/apt-tools.mjs task update . --id {task-id} --lifecycle-phase reviewing
```

No phase-status transition fires (the `reviewing` lifecycle phase does not
map to a phase transition). Idempotent.

## 2. Determine Review Scope

The review targets **only the code changed by this task**, not the entire codebase.

If a task directory exists with `implementation_plan.json`, derive the changed files from the plan's subtask target files.

Otherwise, fall back to diff-based detection:
```bash
git diff main...HEAD --name-status
git diff main...HEAD --stat
```

## 3. Multi-Pass Review

For EVERY changed file (never skip a file):

### Pass 1: Logic & Correctness
- Off-by-one errors, incorrect loop bounds
- Null/undefined handling — missing null checks, optional chaining gaps
- Edge cases — empty arrays, zero values, concurrent access
- Incorrect conditionals — inverted logic, missing cases
- Business logic errors — wrong calculations, incorrect state transitions
- Path correctness — file paths, import paths, URL construction

### Pass 2: Security (OWASP Top 10)
- Injection: SQL, command, path traversal, XSS
- Broken access control: missing auth checks, privilege escalation
- Exposed secrets: hardcoded credentials, API keys in code
- Input validation: unsanitized user input, type coercion issues
- Insecure dependencies: known vulnerable packages

### Pass 3: Code Quality
- Error handling: uncaught exceptions, missing error boundaries
- Resource management: unclosed handles, memory leaks, dangling listeners
- Duplication: copy-pasted code that should be abstracted
- Complexity: deeply nested logic, functions over 50 lines
- Naming: unclear variable/function names, misleading identifiers

### Pass 4: Architecture
- Does the change respect module boundaries?
- Are imports following the project's dependency direction?
- Does new code match existing patterns in similar files?
- Are there unintended coupling points introduced?

### Pass 5: Performance
- N+1 queries or unnecessary repeated calls
- Unnecessary re-renders in React components
- Missing memoization where expensive computation repeats
- Bundle size impact — large imports that could be tree-shaken or lazy-loaded
- Memory leaks — event listeners not cleaned up, subscriptions not unsubscribed

### Pass 6: Docs-Coherence Audit (C33)

Pass 6 covers both internal state (features-registry + REGISTRY.md counts +
project_index.json + milestones.json rollups) and external prose (CLAUDE.md,
AGENTS.md, READMEs, docs/**). It is **inline** in the reviewer brief — a
grep workload that does not justify a separate agent spawn.

This pass drives two CLI verbs: `apt-tools docs-audit` (external +
internal drift detection) and `apt-tools features-audit` (registry
coverage). Both emit JSON; the reviewer buckets by policy.

1. Run the docs-drift audit against the task's diff:

   ```bash
   node packages/framework/bin/apt-tools.mjs docs-audit . \
     --since <task-base-ref> --format json
   ```

   Capture the `findings[]` (for `flag-drift` surfaces) and `patch_plan[]`
   (for `auto-update` surfaces).

2. Run the features-registry audit in report-only mode:

   ```bash
   node packages/framework/bin/apt-tools.mjs features-audit . \
     --since <task-base-ref> --format json
   ```

   The executor post-step in `/apt:execute` already applies stubs for
   `auto-update` surfaces; this run catches anything the executor missed
   (e.g. stubs were generated but the user's policy opted out, or the
   executor skipped the post-step on a blocked subtask).

3. **Policy split — critical:**
   - **auto-update findings** are FIXED inline via the fix-review loop. The
     reviewer applies the patch via the matching `apt-tools` subcommand
     (`features-audit --apply-stubs`, `roadmap rollup`, registry rewriter).
     These land in iterations 1–2 of the fix loop.
   - **flag-drift findings** are SURFACED only. They appear in
     `review_findings.md` with category `docs-drift`, severity `warning`,
     and the full shape
     `{file, line, stale_claim, evidence_from_diff, suggested_rewrite?, policy: "flag-drift"}`.
     They are reported to the user. **Never auto-edit external prose under
     any iteration.** The user invokes `/apt:docs` to resolve them.

4. Add `docs-coherence` as a 6th key alongside the existing `scores.{logic,
   security, quality, architecture, performance}` score map. 1–10 scale;
   findings count against the score like every other pass.

## 4. Aggregate Findings

Build findings tree:
```json
{
  "summary": "{1-2 sentence overall assessment}",
  "assessment": "approve|request-changes|comment",
  "scores": {
    "logic": "{1-10}",
    "security": "{1-10}",
    "quality": "{1-10}",
    "architecture": "{1-10}",
    "performance": "{1-10}"
  },
  "findings": [
    {
      "file": "path/to/file.ts",
      "line": 42,
      "severity": "critical|warning|suggestion|nitpick",
      "category": "logic|security|quality|architecture|performance",
      "title": "{short description}",
      "description": "{detailed explanation of the issue}",
      "suggestion": "{how to fix it — concrete code if possible}",
      "fixable": true
    }
  ],
  "stats": {
    "files_reviewed": "{n}",
    "findings_total": "{n}",
    "critical": "{n}",
    "warnings": "{n}",
    "suggestions": "{n}"
  }
}
```

## 5. Fix-Review Loop (max 4 iterations)

Fix **all** findings — critical, warnings, suggestions, and actionable nitpicks. AI agents have near-zero marginal cost per fix. There is no severity gate and no "report for manual resolution" path.

The only exceptions:
- Findings explicitly marked `fixable: false`
- Findings marked as deliberate trade-offs
- Fixes touching Critical/Destructive risk paths (auth, secrets, migrations) require human approval

### Iteration model

The loop runs up to **4 iterations** with two distinct phases:

- **Iterations 1-2 (discovery):** Full review — may find new issues beyond the original set. Fix everything found. **docs-audit `auto-update` findings are applied in this phase** via the matching `apt-tools` subcommand (no human prose edits). `flag-drift` docs findings are surfaced only.
- **Iterations 3-4 (verification-only):** Only check whether previously found issues are actually resolved. Do NOT report new issues. `flag-drift` findings remain surfaced-only — they never get auto-edited regardless of iteration.

This prevents an infinite loop where each review discovers new issues that trigger more fixes that trigger more review.

### Per-iteration process

```
for ITERATION in 1 2 3 4:
  1. Fix all outstanding findings
  2. Re-review changed files
  3. If ITERATION <= 2: accept new findings into the backlog
     If ITERATION > 2: only check prior findings — ignore new discoveries
  4. If 0 outstanding findings: BREAK
  5. If findings remain: continue to next iteration
```

**Fix step (each iteration):**
1. For each finding (critical first, then warnings, suggestions, nitpicks):
   a. Read the affected file and surrounding context
   b. Apply the minimal fix that resolves the issue
   c. Run verification (tests, typecheck, lint)
   d. If verification passes: commit the fix
   e. If verification fails after 3 attempts: mark as `needs_human_review` and move on

```bash
node packages/framework/bin/apt-tools.mjs commit "fix: {finding title}" --files {fixed-files}
```

**Re-review step (each iteration):**
- Re-run the 6-pass review on fixed files only
- Iterations 1-2: merge any new findings into the backlog for the next fix pass
- Iterations 3-4: only verify that previously identified findings are resolved — new discoveries are ignored (they would be caught by `apt:pr-review` later if needed)

**Convergence:** If all findings are resolved at any point, break the loop immediately — don't run unnecessary iterations.

**Exhaustion:** If findings remain after 4 iterations, mark them as `needs_human_review` in `review.json` and report them.

Update `review.json` with final state after the loop completes (findings resolved vs remaining, iteration count).

## 6. Update Task Documentation

After fixes are applied, update the task artifacts to reflect what happened:

### 6a. Update review.json

Write `{task_dir}/review.json` with the final aggregated findings, including which were fixed and which remain.

```bash
node packages/framework/bin/apt-tools.mjs commit "review: task review complete" --files review.json
```

### 6b. Update qa_signoff.json (if verify ran before review)

If `qa_signoff.json` exists and the review fixed issues that would change QA scores, re-score the affected dimensions and update the sign-off:

```bash
node packages/framework/bin/apt-tools.mjs commit "qa: update scores after review fixes" --files qa_signoff.json
```

### 6c. Update build-progress.json

Add a `review` entry to build-progress tracking:
```json
{
  "review": {
    "completed_at": "{ISO date}",
    "findings_total": "{n}",
    "findings_fixed": "{n}",
    "findings_remaining": "{n}",
    "iterations": "{n}",
    "assessment": "approve|request-changes|comment"
  }
}
```

## 7. Report + What's Next

Output the review summary:

```
Task Review: {ASSESSMENT}
Files reviewed: {n} | Findings: {total} found, {fixed} fixed, {remaining} remaining
Iterations: {n}

{If findings were fixed:}
Fixed:
- [{severity}] {file}:{line} — {title}

{If findings remain:}
Remaining (require attention):
- [{severity}] {file}:{line} — {title}: {description}

Scores: logic={n} security={n} quality={n} architecture={n} performance={n}

Report: {task_dir}/review.json
```

`lifecycle_phase` remains at `reviewing` after /apt:review completes — this is
the from-state /apt:ship expects for its atomic `reviewing → shipped-pending-merge`
flip, so no further `task update --lifecycle-phase` call is needed here.

**Always end with a "What's Next" recommendation:**

```
{If assessment is "approve" and QA passed:}
-> Recommended: /apt:ship — create PR for this task
   Also: review manually | run /apt:pr-review for deep multi-agent review

{If assessment is "approve" but QA hasn't run:}
-> Recommended: /apt:verify — run QA scoring before shipping
   Also: /apt:ship (skip verify)

{If assessment is "request-changes" with remaining findings:}
-> Remaining issues need manual attention. Fix them, then re-run /apt:review
   Also: /apt:verify to re-score after manual fixes

{If invoked standalone (no task directory):}
-> Review complete. Fix any remaining issues manually.
   Also: /apt:ship — create PR with review summary
```

</process>
