# Verify

> Evidence-based verification before claiming completion. Use before committing, creating PRs, or claiming a task is done. Never claim success without proof.

- Skill: `buldee/verify` (Agent Skill)
- Install (CLI): `npx skillmds@latest add buldee/verify`
- Raw SKILL.md: https://api.skillmd.com/api/skills/buldee/verify/raw
- Safety review: pending
- Works with: Claude Code, Claude.ai, OpenAI Codex
- Category: Productivity
- Author: BULDEE (https://skillmd.com/u/buldee)
- Updated: 2026-09-21
- Page: https://skillmd.com/skills/buldee/verify

---


# /craftsman:verify - Evidence Before Completion

## Outcome Contract

- **Outcome**: proof that the work is complete, or an explicit list of what is not.
- **Done when**: every completion claim is backed by a command that ran and its output; unverified claims are listed as unverified.
- **Evidence**: the commands run with their exit codes and output, never a summary of them.

You are a **Quality Guardian**. You NEVER claim success without EVIDENCE.

## The Golden Rule

```
┌─────────────────────────────────────────────────────────────────┐
│                                                                  │
│   NO COMPLETION CLAIMS WITHOUT FRESH VERIFICATION EVIDENCE      │
│                                                                  │
│   ❌ "The tests should pass"                                    │
│   ❌ "I believe this works"                                     │
│   ❌ "This looks correct"                                       │
│                                                                  │
│   ✅ "Tests pass: [actual output shown]"                        │
│   ✅ "Verified working: [evidence provided]"                    │
│   ✅ "Confirmed: [command output included]"                     │
│                                                                  │
└─────────────────────────────────────────────────────────────────┘
```

## When to Verify

Use this skill before:
- Claiming a bug is fixed
- Saying tests pass
- Asserting code is complete
- Creating a commit
- Opening a PR
- Merging to main

## Process

### Phase 1: Identify Verifications Needed

Based on work done, determine what to check:

```markdown
## Verification Checklist

**Work completed:** [Description]

**Required verifications:**
- [ ] Unit tests pass
- [ ] Integration tests pass (if applicable)
- [ ] Type checking passes
- [ ] Linting passes
- [ ] Build succeeds
- [ ] Manual verification (if applicable)
```

### Phase 2: Execute Verifications

Run EACH verification and capture ACTUAL output:

```markdown
## Verification Results

### 1. Unit Tests
**Command:** `vendor/bin/phpunit --testsuite=unit`
**Expected:** All tests pass
**Actual Output:**
```
PHPUnit 10.5.0
...............                                   15 / 15 (100%)
Time: 00:01.234, Memory: 24.00 MB
OK (15 tests, 42 assertions)
```
**Status:** ✅ PASSED

### 2. Static Analysis
**Command:** `vendor/bin/phpstan analyse`
**Expected:** No errors
**Actual Output:**
```
 [OK] No errors
```
**Status:** ✅ PASSED

### 3. Code Style
**Command:** `vendor/bin/php-cs-fixer fix --dry-run`
**Expected:** No changes needed
**Actual Output:**
```
Checked all files, no changes needed.
```
**Status:** ✅ PASSED
```

### Auto-Detection & Execution

Before running verifications, detect the stack and available tools:

Use the **Glob** tool to detect the stack:
- `Glob("composer.json")` → if exists, PHP_STACK=true
- `Glob("package.json")` → if exists, NODE_STACK=true

**Auto-run available checks:**

For PHP projects, attempt in order (skip if tool not found):
1. `vendor/bin/phpunit` - Unit tests
2. `vendor/bin/phpstan analyse` - Static analysis
3. `vendor/bin/php-cs-fixer fix --dry-run` - Code style

For Node projects, attempt in order:
1. `npm test` or `npx vitest run` - Tests
2. `npx tsc --noEmit` - Type checking
3. `npm run lint` or `npx eslint .` - Linting

**Run each command via Bash tool and capture ACTUAL output as evidence.**
Do NOT claim "tests pass" without showing the output.

### Phase 3: Evidence Summary

```markdown
## Verification Summary

| Check | Command | Status | Evidence |
|-------|---------|--------|----------|
| Unit Tests | `phpunit` | ✅ | 15/15 passed |
| PHPStan | `phpstan analyse` | ✅ | No errors |
| CS Fixer | `php-cs-fixer` | ✅ | No changes |
| Build | `composer install` | ✅ | Success |

**VERDICT:** ✅ ALL VERIFICATIONS PASSED

**Ready to:** [commit / PR / merge]
```

## MANDATORY: Mark Session Verified

**IMMEDIATELY after a passing verdict**, run this command. Do NOT skip this step.
Do NOT defer it. Do NOT wait for the user. Execute it NOW:

```
bash ~/.claude/craftsman-set-verified.sh
```

If the wrapper is missing, fall back to:
```
bash -c 'BRIDGE="${HOME}/.claude/craftsman-session-state-path"; if [ ! -f "$BRIDGE" ]; then echo "ERROR: bridge file $BRIDGE not found - session-start may not have run" >&2; exit 1; fi; SF=$(cat "$BRIDGE"); mkdir -p "$(dirname "$SF")"; python3 -c "
import json,os,datetime,tempfile; sf=\"$SF\"
try:
 with open(sf) as f: s=json.load(f)
except: s={}
s[\"verified\"]=True; s[\"verified_at\"]=datetime.datetime.now(datetime.timezone.utc).strftime(\"%Y-%m-%dT%H:%M:%SZ\")
d=os.path.dirname(sf); os.makedirs(d,exist_ok=True)
fd,t=tempfile.mkstemp(dir=d,suffix=\".tmp\")
with os.fdopen(fd,\"w\") as f: json.dump(s,f)
os.rename(t,sf); print(\"verified=true at \"+sf)
"'
```
If both commands fail, say "Session state update skipped".

This unblocks `git push` - the pre-push hook checks this flag.

## Common Verification Commands

### PHP/Symfony

```bash
# Full quality check
composer run quality
# or
make quality

# Individual checks
vendor/bin/phpunit
vendor/bin/phpunit --testsuite=unit
vendor/bin/phpunit --filter=TestClassName
vendor/bin/phpstan analyse
vendor/bin/php-cs-fixer fix --dry-run --diff
```

### TypeScript/React

```bash
# Full check
npm run check
# or
npm run lint && npm run typecheck && npm test

# Individual checks
npm test
npm run test:coverage
npm run typecheck
npx tsc --noEmit
npm run lint
npm run build
```

### Python

```bash
# Full check
make check
# or
pytest && mypy src/ && ruff check src/

# Individual
pytest
pytest --cov=src
mypy src/
ruff check src/
black --check src/
```

## Failure Handling

When a verification FAILS:

```markdown
## ❌ VERIFICATION FAILED

### Failed Check: Unit Tests

**Command:** `vendor/bin/phpunit`

**Output:**
```
FAILURES!
Tests: 15, Assertions: 41, Failures: 1.

1) App\Tests\Domain\UserTest::test_email_validation
Failed asserting that 'invalid' matches expected 'valid@email.com'.
```

**Analysis:**
- **Root cause:** Email validation logic incorrect
- **File:** src/Domain/ValueObject/Email.php:23
- **Impact:** Email creation accepts invalid formats

**Required Action:** Fix before claiming completion.

**DO NOT:**
- Claim work is done
- Create a commit
- Say "tests mostly pass"
- Ignore the failure
```

## Output Format

```markdown
# Verification Report

## Context
- **Work Completed:** [Description]
- **Verification Time:** [Timestamp]

## Verifications Executed

### 1. [Check Name]
**Command:** `[command]`
**Output:**
```
[actual output]
```
**Status:** ✅ PASSED / ❌ FAILED

## Summary

| # | Check | Status |
|---|-------|--------|
| 1 | Tests | ✅ |
| 2 | Types | ✅ |
| 3 | Lint | ✅ |

## Verdict

**Overall Status:** ✅ ALL PASSED / ❌ X FAILED
**Evidence Quality:** Complete
**Ready for:** [Next step]
```

## Bias Protection

**Acceleration:** "Skip verification, it probably works"
→ "Probably" is not evidence. Run the commands.

**Optimism:** "I'm sure the tests pass"
→ You're not sure until you see them pass. Run them.

**Confirmation bias:** "One test failed but it's minor"
→ A failure is a failure. Fix it first.

## Session State

The `set-verified` step is in the "MANDATORY: Mark Session Verified" section above.
It MUST be executed immediately after a passing verdict, not deferred to the end.

