---
name: apt:verify
description: "Validate implementation against spec — QA review loop"
apt-skill-version: {{APT_VERSION}}
stage: verify
intent: ship
when_to_use: "The build is done and the user wants 4-dimension QA scoring (correctness, completeness, quality, coverage) with sign-off."
user_invocable: true
internal: false
spawns_agent: true
agent_name: "apt-verifier"
task_context: require-existing
default_execution_mode: auto
execution_modes:
  - auto
  - step
allowed-tools: "Read, Bash, Grep, Glob, Write"
argument-hint: "apt:verify [--fast | --cross-verify]"
gates: 
  - consistency-check
  - all-subtasks-complete
config_keys:
  - verification.evidence_capture
  - verification.max_iterations
---
<objective>
Verify that the implementation matches the spec, all tests pass, code quality checks succeed, and sign off on the build.
</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. All artifacts are read from here.
- **Artifacts:** `{task_dir}/spec.md`, `{task_dir}/implementation_plan.json`, `{task_dir}/build-progress.json` (from apt:plan + apt:execute)
</your_environment>

<state_files>
## State Files

**Reads:**
- `AGENTS.md` — Project constitution
- `spec.md` — Requirements and acceptance criteria
- `implementation_plan.json` — Subtask list with verification commands
- `build-progress.json` — Execution progress
- `.aperant/context/notes/{task-id}.md` — **Decision ledger (R6).** If present, read and inject a ≤500-token digest at the top of any verifier subagent prompt (see `<decision_ledger_inject>` below). Locked decisions from `/apt:discuss` define what "correct" means — verifiers must not score against assumptions the team already rejected.

**Writes:**
- `qa_signoff.json` — QA verdict with dimension scores and issues
</state_files>

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

Before spawning any verifier subagent or running scoring against acceptance criteria, check for `.aperant/context/notes/{task-id}.md`. If present, extract a ≤500-token digest of locked decisions and prepend it under:

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

Verifiers apply this digest when interpreting "completeness" and "correctness" — if a decision explicitly deferred a behavior, its absence is NOT a verification failure.
</decision_ledger_inject>

<process>

## 0. Hard Gate Check

Before any scoring or automated checks, run the hard-gate check for the `verify` skill:

```bash
node packages/framework/bin/apt-tools.mjs gate check . --task-id {task-id} --skill verify
```

Parse the JSON envelope:
- If `status == "ok"`: proceed to Section 1.
- If `status == "fail"`: STOP. Report the failed gates verbatim from `failed:[{id, severity, reason}]`, then emit:
  ```
  Hard gate failed. Fix the issues above, or re-run with:
    --force --reason "<explanation>"
  The override will be logged to .aperant/events/{today}.jsonl.
  ```
  Exit the skill. Do NOT auto-apply `--force`.

The gate covers constitution-read (warn) and all-subtasks-complete (blocking). When all-subtasks-complete blocks, Section 2 below is redundant — the gate already reported the unfinished subtasks.

## 1. Load Context

1. Read `AGENTS.md` if it exists — extract testing/quality requirements
2. Read `spec.md` — extract acceptance criteria
3. Read `implementation_plan.json` — check all subtasks completed
4. Read `build-progress.json` — verify execution finished

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

### Mark lifecycle phase as `verifying`

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

This is a pure task-record update — no phase-status transition fires (the
`verifying` lifecycle phase does not map to a phase transition). Idempotent.

## 2. Pre-Check: Subtask Completion

Covered by the hard gate in Section 0 (`all-subtasks-complete`). If you reached this section, every subtask's `status` is `"completed"` or the run was forced. No additional check is needed — proceed to Section 3.

## 3. Run Automated Checks

### 3a. Test Suite

Detect and run the project's test runner:
```bash
# Node.js
npm test || pnpm test || npx vitest run || npx jest

# Python
python -m pytest

# Rust
cargo test

# Go
go test ./...
```

Record: pass/fail, test count, failure details.

### 3b. Type Checker

```bash
# TypeScript
pnpm typecheck || npx tsc --noEmit

# Python
mypy . || pyright

# Rust (included in cargo test)
```

Record: pass/fail, error count, error details.

### 3c. Linter

```bash
# Node.js
pnpm lint || npx biome check . || npx eslint .

# Python
ruff check . || flake8

# Rust
cargo clippy
```

Record: pass/fail, warning/error count.

## 4. Code Review

Review all changed files via:
```bash
git diff main...HEAD --name-status
```

For each changed file, check:
- **Correctness:** Does the change match the spec requirements?
- **Error handling:** Are errors caught and handled appropriately?
- **Edge cases:** Are boundary conditions covered?
- **Security:** No exposed secrets, proper input validation, no injection vectors
- **Test coverage:** Are there tests for the new/changed behavior?

Reference `prompts/qa_reviewer.md` for review methodology.

## 5. Score Dimensions

Rate each of the 4 dimensions on a 1-10 scale using the rubrics below. Provide a brief rationale for each score.

### Completeness (1-10)

- **9-10:** All spec requirements implemented, all edge cases handled, nothing missing
- **7-8:** All core requirements done, minor edge cases may be missing
- **5-6:** Most requirements done but noticeable gaps
- **3-4:** Significant requirements missing
- **1-2:** Barely started or fundamentally incomplete

### Correctness (1-10)

- **9-10:** All tests pass, types clean, logic verified correct
- **7-8:** Tests pass, minor type warnings, logic sound
- **5-6:** Some test failures or type errors, logic mostly correct
- **3-4:** Multiple test failures, type errors, logic flaws
- **1-2:** Fundamentally broken

### Code Quality (code_quality, 1-10)

- **9-10:** Clean, idiomatic, well-structured, lint-clean, follows all conventions
- **7-8:** Good quality, minor style issues, follows conventions
- **5-6:** Acceptable but needs cleanup, some convention violations
- **3-4:** Poor quality, significant violations, hard to maintain
- **1-2:** Unacceptable quality

### Test Coverage (test_coverage, 1-10)

- **9-10:** Comprehensive tests for all new code, edge cases covered, high coverage
- **7-8:** Good coverage of main paths, some edge cases tested
- **5-6:** Basic tests exist but gaps in coverage
- **3-4:** Minimal tests, many untested paths
- **1-2:** No meaningful test coverage

### Verdict Derivation

Derive the verdict from dimension scores using these threshold rules:

- **approved** -- ALL dimensions >= 7, no critical issues
- **approved-with-notes** -- ALL dimensions >= 5, minor issues noted
- **rejected** -- ANY dimension < 5, or critical issues found

These thresholds match `QA_DIMENSION_THRESHOLDS` in `packages/framework/src/types/qa-scoring.ts`.

## 6. Fix-Verify Loop (max 4 iterations)

AI agents have near-zero marginal cost per fix. Fix **all** issues found — regardless of severity (critical, warning, suggestion, note). The framework does not ask "which findings to fix" — the answer is always "all of them."

The only exceptions:
- `--strict` flag is set (report only, no fixes)
- Findings explicitly marked as deliberate trade-offs
- Fixes touching Critical/Destructive risk paths (auth, secrets, migrations) still require human approval

### Iteration model

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

- **Iterations 1-2 (discovery):** Full re-check — may surface new issues beyond the original set. Fix everything found.
- **Iterations 3-4 (verification-only):** Only check whether previously found issues are actually resolved. Do NOT report new issues. If all prior issues are confirmed fixed, break immediately.

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

### Per-iteration process

```
for ITERATION in 1 2 3 4:
  1. Fix all outstanding issues (group by file, independent groups in parallel)
  2. Re-run affected checks (tests, typecheck, lint)
  3. Re-score dimensions
  4. If ITERATION <= 2: accept any new issues into the backlog
     If ITERATION > 2: only check prior issues — ignore new discoveries
  5. If 0 outstanding issues: BREAK
  6. If issues remain: continue to next iteration
```

**Fix step:**
1. Group issues by file. Independent file groups can be fixed in parallel.
2. Fix each issue. Reference `prompts/qa_fixer.md` for fix patterns.
3. Re-run affected checks (tests, typecheck, lint)
4. Commit fixes:
   ```bash
   node packages/framework/bin/apt-tools.mjs commit "fix: {issue description}" --files {fixed-files}
   ```
5. Re-score dimensions

**Convergence:** If all issues are resolved at any point, break the loop immediately.

**Exhaustion:** If issues remain after 4 iterations, mark them in `qa_signoff.json` and report them. The verdict should reflect the remaining issues.

## 7. Write QA Sign-off

Create `qa_signoff.json` using the `ScoredQASignoff` format (see `packages/framework/src/types/qa-scoring.ts`):

```json
{
  "status": "approved|approved-with-notes|rejected",
  "timestamp": "{ISO date}",
  "iterations": 1,
  "dimensions": [
    { "dimension": "completeness", "score": 8, "rationale": "All spec requirements implemented" },
    { "dimension": "correctness", "score": 9, "rationale": "All tests pass, types clean" },
    { "dimension": "code_quality", "score": 7, "rationale": "Clean code, follows conventions" },
    { "dimension": "test_coverage", "score": 7, "rationale": "Good coverage of main paths" }
  ],
  "checks": {
    "tests": { "status": "pass", "count": 42, "failures": [] },
    "typecheck": { "status": "pass", "errors": [] },
    "lint": { "status": "pass", "warnings": 0 }
  },
  "issues": [],
  "notes": "Implementation meets all requirements"
}
```

The `dimensions` array must contain exactly the 4 dimensions defined in `QA_DIMENSIONS`: `completeness`, `correctness`, `code_quality`, `test_coverage`. Each entry includes a numeric `score` (1-10) and a `rationale` string explaining the score.

The `status` field is derived from the minimum dimension score:
- All >= 7 and no critical issues: `"approved"`
- All >= 5 and no critical issues: `"approved-with-notes"`
- Any < 5 or critical issues: `"rejected"`

```bash
node packages/framework/bin/apt-tools.mjs commit "qa: verification {status}" --files qa_signoff.json
```

### Mark lifecycle phase as `reviewing` (approved path only)

If `status` is `approved` or `approved-with-notes`, flip the task's lifecycle
phase so the next stage (`/apt:review`, or `/apt:ship` if review is skipped)
finds the task in the correct from-state. Skip this transition entirely on
`rejected` — the task stays in `verifying` until the user re-runs after fixes.

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

## 8. Report

Output:
```
QA Verification: {STATUS}
- Tests: {pass/fail} ({count} tests)
- Types: {pass/fail}
- Lint: {pass/fail}
- Scores: completeness={n} correctness={n} quality={n} coverage={n}
- Issues: {count} ({critical} critical, {warning} warnings)
- Iterations: {n}/{max}

{If approved:} Next: /apt:review (optional code review)
{If rejected:} Fix issues and re-run /apt:verify
```

</process>
</output>
