---
name: canon-verify
description: >
  Verify code implementation against spec acceptance criteria. Use when you want
  to check if code satisfies spec requirements, after implementing a feature,
  or during code review. Evaluates each AC as realized, partial, or conflicting.
allowed-tools:
  - Read
  - Glob
  - Grep
  - Bash
  - mcp__canon__get_spec
  - mcp__canon__get_section
  - mcp__canon__search
  - mcp__canon__add_realization
  - mcp__canon__update_section_status
---

# Verify Code Against Spec

You are verifying whether the current codebase satisfies a spec's acceptance criteria.

## Quick Check with CLI

Try the CLI first for a fast static check:

```bash
canon verify
```

Or for a specific section:

```bash
canon verify --section <id>
canon verify --gate              # Pass/fail gate mode
canon verify --gate --section 2.1  # Gate a specific section
```

This greps the codebase for keywords from each unchecked AC and classifies them
as "likely realized", "not started", or "unknown". Use the results as a starting
point, then do deeper analysis with the steps below.

## Step 1: Load the Spec

If the user specifies a spec file, load it directly. Otherwise, identify the relevant spec:
- Check recent changes: `git diff --name-only HEAD`
- Search for matching specs using MCP `search` or local `Glob` + `Grep`

Load the full spec with `mcp__canon__get_spec` or `Read`.

## Step 2: Evaluate Each Acceptance Criterion

For each AC checkbox in the spec:

1. **Search the codebase** for implementation evidence using `Grep` and `Read`
2. **Classify** the AC:
   - **Realized** — code fully implements the requirement
   - **Partial** — code partially implements it (explain what's missing)
   - **Not Started** — no implementation found
   - **Conflicting** — implementation contradicts the requirement

## Step 3: Present Results

Format as a table:

| AC | Status | Evidence |
|----|--------|----------|
| Rate limiting | Realized | `src/auth/rate_limit.py:42-60` |
| Email validation | Partial | Validates format but not domain |
| OAuth support | Not Started | — |

## Step 4: Offer Write-Back (MCP only)

If MCP is available, offer to:
- Update section statuses: `mcp__canon__update_section_status`
- Record realization evidence: `mcp__canon__add_realization`

Ask the user before making any writes.

## Gate Mode

When invoked with `--gate` (or called from another Canon skill like `canon-implement`
or `canon-branch`), verify acts as a pass/fail gate rather than a report.

### Gate Checks

1. **AC Coverage** — every linked AC must have realization evidence
2. **Test Suite** — project tests must pass (`uv run pytest`, `npm test`, etc.)
3. **No Conflicts** — no ACs classified as "Conflicting"

### Gate Output

Pass:
```
PASS: all ACs realized, tests pass, no conflicts
```

Fail:
```
FAIL:
  - 2 ACs lack realization evidence: [list]
  - Tests failing: [summary]
  - 1 AC conflict: [detail]
```

### When Called from Other Skills

Gate mode is the default when canon-verify is invoked by:
- `canon-implement` (after each task)
- `canon-branch` (before merge/PR)

Report mode (Steps 1-4 above) remains the default for direct user invocation.

## Spec Format Reference

AC checkboxes appear under `### Acceptance Criteria` headings:
```markdown
- [x] Checked (done)
- [ ] Unchecked (not done)
```

Realization comments appear after ACs:
```
<!-- canon:realized-in:PR#42 file:src/auth.py:10-25 -->
```

## Verification Trail (evidence pipeline)

When `ide.evidence_pipeline.enabled: true` is set in `CANON.yaml`, every
`canon verify --gate` invocation appends a record to
`.canon/verify-log.jsonl`. Each record has the shape:

```json
{"at": "2026-04-11T20:15:00Z", "section": "2.1", "mode": "gate", "result": "pass", "gaps": 0, "conflicts": 0}
```

The Stop hook reads this trail when composing session evidence so the GitHub
App's PR analyzer can see which gate runs ran on which sections during the
dev session. Inspect the trail directly with:

```bash
canon evidence list-verify-runs --since 2026-04-11T00:00:00Z
```

The log auto-rotates at 1 MB (renames to `verify-log.jsonl.1`). When the
evidence pipeline is disabled, no trail is written.

See `docs/specs/plugin-evidence-pipeline.md` §4 for the design.
