Criterion Verification Map
Contract
Iron law: every acceptance criterion is an eval source: at plan time it must produce a runnable verification command, or planning is blocked. Invoked by /flow:start at the Spec Validation Gate and PLAN (Phases 1-2) to classify each criterion and emit the task's verification fields, and at VERIFY (Phase 4) to run them and assemble the evidence bundle shaped by references/evidence-bundle-format.md. Returns task fields at plan time, the bundle at verify time. Permitted skips: none; an unmappable criterion is escalated through the Spec Validation Gate.
Classification
| Type |
Signal words |
Method |
| behavioral |
"when X then Y", "should return" |
unit/integration test |
| api |
"status code", "endpoint", "header" |
curl/fetch |
| ui |
"displays", "renders", "layout" |
screenshot + analysis |
| error |
"error message", "invalid", "fails gracefully" |
invalid-input test |
| performance |
"within N ms", "timeout" |
benchmark/timing |
| config |
"config", "setting" |
build/load test |
| data |
"transforms", "output matches" |
run with test data |
| contract |
"schema", "type", "signature" |
validator / type-check |
Plan-time task fields
Tasks are atomic (commands/start.md Phase 2). Emit per criterion:
Criterion: {full criterion text}
Verification type: {type from the table}
Verification command: {exact runnable command}
Expected evidence: {what successful output looks like}
Does NOT promise: {non-goals scoped to this criterion}
Risk areas: {risk-map rows whose area this criterion's logic touches, verbatim | none | (disabled by specFirst.riskMap)}
Does NOT promise comes from the journal's ### Non-goals, Risk areas from ### Risk map (references/specification-journal-format.md). implementation-planner adds one discriminating test per risk row (input, expected, source). Any unfillable field: escalate through the Spec Validation Gate.
Evidence collection protocol (verify time)
For each atomic task:
TaskUpdate(taskId, status: "in_progress")
- Run the verification command
- Capture output verbatim
TaskUpdate(taskId, status: "completed", result: "EVIDENCE_COLLECTED")
Then assemble one ## Criterion {N} section each. ### Type and ### Does NOT promise are the plan-time fields; ### What was NOT tested, ### Known limitations of this evidence, ### Negative/adversarial cases covered are authored honestly now (none — {reason} is positive; blank is an auto-FAIL). ### Visual analysis is copied per viewport from the visual-verification result tasks (Viewport:/Screenshot:/Result:/Observed: blocks), never re-derived; non-ui types write none — criterion type {type} has no visual surface.
Two subsections come from test source, never memory:
### Test inputs and expected values: open every test file the command or its output cites. For each test that ran, record one | Test | Input | Expected | Source of expected | row from its source: literal input, literal asserted value, its origin (spec/criterion text, reference implementation, hand computation, existing fixture, external standard). Implementation-captured values are written implementation output; the judge FAILs them. none — {reason} only for ui/config types.
### Risk map coverage: for each Risk areas row, find the test whose input is its discriminating check and write <area> → <test file:line>. A row with no such test is a gap: add it or escalate. none — {reason} only when no row maps here; none — risk map disabled (specFirst.riskMap=false) only when the journal subsection is the disabled marker.
Validate the bundle against the reference (every mandatory subsection present, none only where permitted) before Agent(verdict-judge).
Judge isolation
The verdict-judge has no file tools and receives ONLY acceptance criteria, evidence bundle, and holdout-validation output — never diff, journal, planning notes, self-review findings, test source, or screenshots; tests reach it as ### Test inputs and expected values rows, screens as ### Visual analysis text.
1---2name: criterion-verification-map3description: Transform acceptance criteria into plan-time runnable verification commands (behavioral, API, UI, error, performance, config, data, contract types) with expected evidence shapes and risk areas, then execute at verify time and assemble the evidence bundle with its mandatory completeness subsections, including test inputs/expected values taken from test source and risk-map coverage. Use when planning implementation against issue acceptance criteria or verifying completeness. This skill MUST be consulted because deferring verification to later causes incomplete PRs, and suppressing evidence gaps prevents the verdict judge from reasoning about gaps.4---56# Criterion Verification Map78## Contract910Iron law: **every acceptance criterion is an eval source: at plan time it must produce a runnable verification command, or planning is blocked.** Invoked by `/flow:start` at the Spec Validation Gate and PLAN (Phases 1-2) to classify each criterion and emit the task's verification fields, and at VERIFY (Phase 4) to run them and assemble the evidence bundle shaped by [`references/evidence-bundle-format.md`](../../references/evidence-bundle-format.md). Returns task fields at plan time, the bundle at verify time. Permitted skips: none; an unmappable criterion is escalated through the Spec Validation Gate.1112## Classification1314| Type | Signal words | Method |15|---|---|---|16| behavioral | "when X then Y", "should return" | unit/integration test |17| api | "status code", "endpoint", "header" | curl/fetch |18| ui | "displays", "renders", "layout" | screenshot + analysis |19| error | "error message", "invalid", "fails gracefully" | invalid-input test |20| performance | "within N ms", "timeout" | benchmark/timing |21| config | "config", "setting" | build/load test |22| data | "transforms", "output matches" | run with test data |23| contract | "schema", "type", "signature" | validator / type-check |2425## Plan-time task fields2627Tasks are atomic (`commands/start.md` Phase 2). Emit per criterion:2829```30Criterion: {full criterion text}31Verification type: {type from the table}32Verification command: {exact runnable command}33Expected evidence: {what successful output looks like}34Does NOT promise: {non-goals scoped to this criterion}35Risk areas: {risk-map rows whose area this criterion's logic touches, verbatim | none | (disabled by specFirst.riskMap)}36```3738`Does NOT promise` comes from the journal's `### Non-goals`, `Risk areas` from `### Risk map` ([`references/specification-journal-format.md`](../../references/specification-journal-format.md)). `implementation-planner` adds one discriminating test per risk row (input, expected, source). Any unfillable field: escalate through the Spec Validation Gate.3940## Evidence collection protocol (verify time)4142For each atomic task:43441. `TaskUpdate(taskId, status: "in_progress")`452. Run the verification command463. Capture output verbatim474. `TaskUpdate(taskId, status: "completed", result: "EVIDENCE_COLLECTED")`4849Then assemble one `## Criterion {N}` section each. `### Type` and `### Does NOT promise` are the plan-time fields; `### What was NOT tested`, `### Known limitations of this evidence`, `### Negative/adversarial cases covered` are authored honestly now (`none — {reason}` is positive; blank is an auto-FAIL). `### Visual analysis` is copied per viewport from the `visual-verification` result tasks (`Viewport:`/`Screenshot:`/`Result:`/`Observed:` blocks), never re-derived; non-`ui` types write `none — criterion type {type} has no visual surface`.5051Two subsections come from test source, never memory:5253- **`### Test inputs and expected values`**: open every test file the command or its output cites. For each test that ran, record one `| Test | Input | Expected | Source of expected |` row from its source: literal input, literal asserted value, its origin (spec/criterion text, reference implementation, hand computation, existing fixture, external standard). Implementation-captured values are written `implementation output`; the judge FAILs them. `none — {reason}` only for `ui`/`config` types.54- **`### Risk map coverage`**: for each `Risk areas` row, find the test whose input is its discriminating check and write `<area> → <test file:line>`. A row with no such test is a gap: add it or escalate. `none — {reason}` only when no row maps here; `none — risk map disabled (specFirst.riskMap=false)` only when the journal subsection is the disabled marker.5556Validate the bundle against the reference (every mandatory subsection present, `none` only where permitted) before `Agent(verdict-judge)`.5758## Judge isolation5960The verdict-judge has no file tools and receives ONLY acceptance criteria, evidence bundle, and holdout-validation output — never diff, journal, planning notes, self-review findings, test source, or screenshots; tests reach it as `### Test inputs and expected values` rows, screens as `### Visual analysis` text.