--- name: openspec-verify description: Wired as the verify:post step. Produces OPENSPEC-VERIFICATION.md, the evidence-backed compliance report the ship:pre gate blocks on. Runs six verification levels — task, scenario, requirement, design compliance, regression, spec-drift — and never marks anything PASS without a cited artifact. allowed-tools: Read, Bash, Grep, Glob license: MIT metadata: author: openspec-gsd-integration version: "0.1.0" --- ## Purpose This is the one skill the whole integration's "Ship is blocked until proven" guarantee rests on. It reads what GSD's own verifier already produced (`VERIFICATION.md`, `SUMMARY.md`) plus OpenSpec's own state (`openspec validate --json`) and produces a second, OpenSpec-specific verdict — never re-deriving GSD's own must_haves check, only adding the OpenSpec compliance dimension GSD has no native concept of. ## Invocation conditions - Automatically at `verify:post`, when `workflow.openspec_verification` is true and `-OPENSPEC-LINK.md` exists for the phase. - Directly, for a spot re-check without re-running the whole `/gsd-verify-work` step. ## Required inputs - `-OPENSPEC-LINK.md` (change_id, requirement_ids, scenario_ids) - `-SUMMARY.md` (one per plan, produced by execute-phase — this step's `consumes`) - `-VERIFICATION.md` (GSD's own core verifier output, if present — read-only cross-reference, never modified) ## Files read - `openspec/changes//specs/**/spec.md`, `design.md` - All `--SUMMARY.md` and `-VERIFICATION.md` for the phase - Git log/diff for the phase's commits (`git log --oneline ..HEAD`) - The project's actual test output (whatever `SUMMARY.md`/`VERIFICATION.md` already cite — this skill does not re-run tests itself; it verifies evidence already produced, per the "no fabricated test results" guardrail) ## Files this skill may write - `-OPENSPEC-VERIFICATION.md` (this step's sole output artifact) - `.planning/openspec/EVIDENCE.json` (append-only; delegates full regeneration to `openspec-traceability`, but appends this run's raw findings so nothing is lost between runs) ## Algorithm — the six levels **Level 1 — Task verification.** For each OpenSpec `tasks.md` checklist item mapped to this phase: is it checked off, does its cited `PLAN.md` task have a matching `SUMMARY.md` entry, do the files it claims to touch actually appear in the phase's git diff? **Level 2 — Scenario verification.** For each `scenario_id` in scope: identify GIVEN/WHEN/THEN, find the automated test (or documented manual check) that exercises it, run/read its actual result — never infer "probably passes" from a green build alone. A scenario with no cited test is `NOT_TESTED`, not `PASS`. **Level 3 — Requirement verification.** Roll up every scenario under a requirement into one of `PASS | FAIL | PARTIAL | NOT_TESTED | NOT_APPLICABLE | BLOCKED`. `NOT_APPLICABLE` requires a written reason (e.g. "feature-flagged off this release") — never a bare status flip. **Level 4 — Design compliance.** Diff the actual implementation's structure (files touched, new dependencies, new public interfaces) against `design.md`'s stated approach. An undocumented architectural decision is a finding here, not silently accepted because tests pass. **Level 5 — Regression verification.** Cross-reference `openspec/specs/` (the merged, pre-existing truth) for requirements *adjacent to* this change's domain — did this change's diff touch files those requirements depend on? Flag for re-check rather than assuming isolation. **Level 6 — Spec-drift audit.** Delegates to `openspec-drift` for the full cross-reference (OpenSpec ↔ GSD plans ↔ git diff ↔ tests ↔ evidence); this skill only consumes `openspec-drift`'s summary verdict for its own frontmatter roll-up, it does not repeat that audit's logic inline. ## Output contract (`OPENSPEC-VERIFICATION.md` frontmatter) ```yaml --- change_id: status: passed | gaps_found | human_needed # <- ship:pre gate reads exactly this field requirements: - id: HEALTH-01 status: PASS evidence: [".planning/openspec/EVIDENCE.json#HEALTH-01"] verified_at: verified_by: openspec-verify --- ``` `status: passed` is written **only** when every in-scope requirement resolved to `PASS` or `NOT_APPLICABLE` (with a reason) and zero `openspec-drift` findings are unresolved. Any `FAIL`/`PARTIAL`/`NOT_TESTED`/`BLOCKED` forces `status: gaps_found`. A finding the skill cannot classify with available evidence forces `status: human_needed` — never a guessed `passed`. ## Failure states - Cited test file/command doesn't exist or doesn't actually exercise the scenario → that requirement is `NOT_TESTED`, full stop — never upgraded on the strength of "the code looks right." - `openspec validate --json` itself fails (spec structurally invalid) → `status: human_needed`, this is not a code problem this skill can resolve. ## Guardrails - Never writes `status: passed` from an agent's own confidence — every `PASS` cites a concrete evidence entry with a runnable command or a code reference. - Never treats "no test found" as "presumably fine" — absence of a test is `NOT_TESTED`, a blocking state, not a neutral one. - Never modifies `openspec/` — this is a read-only auditor of OpenSpec content, not a writer. ## Idempotency Re-running against unchanged code/specs reproduces the same `status` and per-requirement table (evidence entries are content-addressed by requirement ID + commit SHA, not appended duplicates). ## Example ``` [openspec-verify] Phase 1 · change add-health-check-endpoint HEALTH-01 (readiness endpoint): PASS — tests/health.test.ts:12-30 HEALTH-02 (liveness endpoint): PASS — tests/health.test.ts:32-48 status: passed → .planning/phases/01-health-check/01-OPENSPEC-VERIFICATION.md written ```