--- phase: 05-verification-engine plan: 01 subsystem: verification-foundation tags: [schema, storage, migration, verify, foundation] requirements: [VRFY-02, VRFY-03] dependency-graph: requires: - "pkg/providers/schema.go VerifySpec (Phase 2)" - "pkg/engine/finding.go Finding (Phase 2)" - "pkg/storage/findings.go (Phase 3)" provides: - "Extended VerifySpec contract for Plans 05-02/03/04" - "Finding.Verify* fields for the verifier pipeline" - "findings table verify_* columns + migration for existing DBs" - "github.com/tidwall/gjson direct dependency" affects: - "go.mod / go.sum" - "pkg/providers" - "pkg/engine" - "pkg/storage" tech-stack: added: - "github.com/tidwall/gjson v1.18.0 (JSON path extraction)" patterns: - "PRAGMA table_info + conditional ALTER TABLE for idempotent SQLite migrations" - "JSON-encoded TEXT column for map[string]string round-trip with NULL for nil" - "Effective*() fallback helpers preserving legacy fields alongside canonical ones" key-files: created: - "pkg/providers/schema_test.go" - "pkg/storage/findings_test.go" - ".planning/phases/05-verification-engine/05-01-SUMMARY.md" modified: - "go.mod" - "go.sum" - "pkg/providers/schema.go" - "pkg/engine/finding.go" - "pkg/storage/schema.sql" - "pkg/storage/db.go" - "pkg/storage/findings.go" decisions: - "Keep legacy ValidStatus/InvalidStatus fields AND add canonical SuccessCodes/FailureCodes; expose via Effective*() helpers so Phase 2-3 YAMLs still load." - "Store VerifyMetadata as JSON TEXT (not a relational table) — small, read-together, and keeps the findings table self-contained." - "Migrate existing DBs via PRAGMA table_info + ALTER TABLE ADD COLUMN (SQLite 3.35 ADD COLUMN IF NOT EXISTS is not guaranteed across modernc versions)." - "Add ExtractMetadata skeleton in schema.go to make gjson a direct dependency now; Plan 05-03 will replace it with the full verifier extraction path." metrics: duration: "3m43s" completed: "2026-04-05T12:42:56Z" tasks_completed: 2 files_created: 3 files_modified: 7 --- # Phase 5 Plan 01: Verification Foundation Summary Interface-first Wave 0 landing: extended VerifySpec, extended Finding, migrated SQLite schema, and wired gjson so Plans 05-02/03/04 can run in parallel on Wave 1 without touching each other's contracts. ## Tasks ### Task 1 — Extend VerifySpec, Finding, add gjson dependency **Commits:** `499f5d5` (RED), `30c0e98` (GREEN) - `VerifySpec` gains `Body`, `SuccessCodes`, `FailureCodes`, `RateLimitCodes`, `MetadataPaths`. `ValidStatus` / `InvalidStatus` remain for backward compat with Phase 2-3 provider YAMLs. - `EffectiveSuccessCodes()` returns `SuccessCodes` → `ValidStatus` → `[200]`; `EffectiveFailureCodes()` returns `FailureCodes` → `InvalidStatus` → `[401, 403]`; `EffectiveRateLimitCodes()` returns `RateLimitCodes` → `[429]`. - `ExtractMetadata([]byte) map[string]string` added as a minimal gjson-backed helper so the dep is promoted to direct in `go.mod`. Plan 05-03 will expand it. - `engine.Finding` gains `Verified`, `VerifyStatus`, `VerifyHTTPCode`, `VerifyMetadata`, `VerifyError`. - Tests: `TestVerifySpec_NewFieldsParse`, `TestVerifySpec_LegacyFieldsStillWork`, `TestVerifySpec_Defaults`, `TestVerifySpec_CanonicalFieldsPreferred` — all pass. ### Task 2 — Migrate storage schema and persist verify fields **Commits:** `2654487` (RED), `aec559d` (GREEN) - `pkg/storage/schema.sql`: findings table now carries `verified INTEGER NOT NULL DEFAULT 0`, `verify_status TEXT NOT NULL DEFAULT ''`, `verify_http_code INTEGER NOT NULL DEFAULT 0`, `verify_metadata_json TEXT`. - `pkg/storage/db.go`: new `migrateFindingsVerifyColumns` helper called from `Open()` — walks `PRAGMA table_info(findings)`, issues `ALTER TABLE ADD COLUMN` for any missing verify column. Safe to run on fresh DBs (all columns exist, no-op) and on legacy DBs. - `pkg/storage/findings.go`: `Finding` struct extended; `SaveFinding` serializes `VerifyMetadata` as JSON (NULL when nil) and writes `verified` as 0/1 INTEGER; `ListFindings` round-trips the same. - Tests: `TestSaveFinding_VerifyFields_RoundTrip`, `TestSaveFinding_VerifyFields_Empty`, `TestOpen_MigratesExistingDB` — all pass. ## Verification ``` go build ./... # clean go test ./pkg/providers/... -run VerifySpec -v # 4/4 pass go test ./pkg/storage/... -v # 10/10 pass go test ./... # all green grep -q 'tidwall/gjson' go.mod # direct dep grep -rn 'SuccessCodes|VerifyStatus|verify_metadata_json' pkg/ # extensions landed ``` ## Deviations from Plan **None material.** Two small additions made inline: 1. **Added `ExtractMetadata` helper on `VerifySpec`** (Rule 3 — blocking issue). The plan required gjson to be in `go.mod` as a usable dependency, but `go get` without an actual import in code leaves it marked `// indirect`. Rather than run `go mod tidy` (explicitly forbidden in the plan), a tiny `ExtractMetadata` method was added that uses `gjson.GetBytes`. This promotes gjson to a direct require and gives Plan 05-03 a real starting point. The helper is intentionally minimal; Plan 05-03 owns the final extraction logic. 2. **Added `TestVerifySpec_CanonicalFieldsPreferred`** (belt-and-braces test). Not in the plan's three required tests, but verifies that when both canonical and legacy fields are set, canonical wins — a contract every downstream plan depends on. ## Downstream Contracts Ready | Consumer | Contract | | ---------- | --------------------------------------------------------------------------------------------- | | Plan 05-02 | `VerifySpec.Effective*Codes()`, `Finding.Verify*` fields for HTTPVerifier implementation | | Plan 05-03 | `VerifySpec.MetadataPaths`, `ExtractMetadata` skeleton, gjson available | | Plan 05-04 | `storage.Finding.Verified/VerifyStatus/VerifyMetadata` round-trip, migration is automatic | | Plan 05-05 | YAML schema ready for Tier 1 provider verify-block enrichment | ## Known Stubs - `VerifySpec.ExtractMetadata` is a minimal gjson extraction — only handles flat string values via `GetBytes`. **Plan 05-03 will replace this** with full metadata extraction (nested paths, type coercion, Content-Type gating). ## Self-Check: PASSED Files verified: - `pkg/providers/schema.go` — FOUND (SuccessCodes, MetadataPaths, ExtractMetadata, Effective* present) - `pkg/providers/schema_test.go` — FOUND (4 tests) - `pkg/engine/finding.go` — FOUND (Verified/VerifyStatus/VerifyHTTPCode/VerifyMetadata/VerifyError present) - `pkg/storage/schema.sql` — FOUND (verify_metadata_json column present) - `pkg/storage/db.go` — FOUND (migrateFindingsVerifyColumns present) - `pkg/storage/findings.go` — FOUND (verify_* columns in SELECT/INSERT) - `pkg/storage/findings_test.go` — FOUND (3 tests) - `go.mod` — FOUND (`github.com/tidwall/gjson v1.18.0` in direct require block) Commits verified in `git log`: - `499f5d5` — test(05-01) VerifySpec RED - `30c0e98` — feat(05-01) VerifySpec GREEN - `2654487` — test(05-01) storage RED - `aec559d` — feat(05-01) storage GREEN Build + tests: `go build ./...` clean, `go test ./...` all pass.