Files
summercms/.planning/phases/03-first-vertical-slice-genres-end-to-end/03-VALIDATION.md
2026-09-17 18:40:13 +02:00

74 lines
5.6 KiB
Markdown

---
phase: 03
slug: first-vertical-slice-genres-end-to-end
status: draft
nyquist_compliant: false
wave_0_complete: false
created: 2026-09-17
---
# Phase 3 — Validation Strategy
## Test Infrastructure
| Property | Value |
|---|---|
| Framework | Go 1.27 `testing`, `httptest`; existing `../fonoteka.go/parity` testcontainers Postgres suite |
| Config | Root `go.mod` plus app `../fonoteka.go/go.mod`; existing `go.work` only covers the framework and hello example |
| Quick run | `go vet ./... && go test ./...` in each of `summercms.go` and `../fonoteka.go` |
| Full suite | Root and app vet/test/race, focused real genres parity subtest, Phase 2 corpus contract and regression script |
| Feedback latency | Fast loop should stay within the existing warmed Go test times; Postgres and PHP replay run at wave/final gates |
## Sampling Rate
- After every implementation task commit: root `go vet ./... && go test ./...`; after app files exist, run the same commands in `../fonoteka.go`.
- After each plan wave: run the focused Postgres route/genre test and the ported parity subtest in the app, plus the quick checks.
- Before Phase 3 verification: run root and app `go test -race ./...`, all ported corpus routes, migration up/down, and Phase 2 regression checks.
- Docker unavailable is a failed app integration gate, following Phase 2 `TestMain` behavior; `testing.Short` remains a fast local option only.
## Per-Task Verification Map
The user confirmed four plans on 2026-09-17. Every task has an automated `<verify>` command and an observable acceptance criterion. These rows are planned checks; results are filled during execution.
| Task ID | Wave | Requirement | Threat | Automated evidence | Status |
|---|---:|---|---|---|---|
| 03-01-01 | 1 | DATA-01, DATA-02 | T-03-01, T-03-SC | Root/app vet/test; Postgres 16 ICU migration smoke, 15 seeds, separate history | Pending |
| 03-01-02 | 1 | HTTP-01, HTTP-02, QA-04 | T-03-02, T-03-03 | Root/app vet/test; persisted-user JWT request reaches real genre row | Pending |
| 03-02-01 | 2 | QA-04 | T-03-04 | Root/app vet/test; focused TestGenre nonzero/foreign/editor counts | Pending |
| 03-02-02 | 2 | QA-04 | T-03-05 | Root/app vet/test; focused TestGenre `non_empty`, 422, 15-name order | Pending |
| 03-03-01 | 3 | DATA-02, HTTP-01 | T-03-01, T-03-07 | Root/app vet/test; rollback isolation and hello typed route | Pending |
| 03-03-02 | 3 | QA-04 | T-03-06 | Root/app vet/test; TestParityCorpus one real pass and 153 pending | Pending |
| 03-04-01 | 4 | DATA-01, DATA-02, HTTP-01, HTTP-02 | T-03-01 to T-03-03 | Root vet/test/race and app vet/test; adversarial auth/routing tests | Pending |
| 03-04-02 | 4 | QA-04, HTTP-02 | T-03-04 to T-03-07 | `bash scripts/check-phase3.sh`; app test/race, PHP harness regression, security review | Pending |
| Capability | Requirement | Threat | Test and evidence |
|---|---|---|---|
| Shared pgx/GORM connection and plugin migrations | DATA-01, DATA-02 | T-03-01 schema drift | Testcontainers creates all minimal tables and 15 ordered genres; app and framework observe one `*sql.DB`; two plugin histories survive independent up/down/rollback; no `AutoMigrate` call |
| Named route and middleware pipeline | HTTP-01, HTTP-02 | T-03-02 auth bypass | `httptest` records seven stage order, preflight behavior, missing-name boot failure, typed malformed/unknown ID 404, JWT/must-change-password placement |
| JWT guard | HTTP-02, QA-04 | T-03-03 token forgery | Missing/malformed/expired/wrong algorithm/bad signature/missing `sub`/unknown user yield PHP shaped 401; empty secret fails boot; valid user reaches handler |
| Active collection and genre aggregate | QA-04 | T-03-04 cross-tenant data leak | Postgres inserts owned/editor/foreign albums; exact positive counts and `non_empty=1` set; foreign count remains zero; invalid query yields 422 envelope; empty list is `[]` |
| Polish order | QA-04 | T-03-05 sort drift | Testcontainers initializes Postgres 16 with ICU `pl-PL`; startup rejects a libc or wrong-locale database; ordinary ORDER BY returns all 15 names in fixture order; accented/punctuation edge case documented as a later regression fixture risk |
| Recorded parity | QA-04 | T-03-06 false green | Real `newTarget` and temporary seed hook replay unmodified fixture; corpus reports one ported/pass and 153 pending; deliberate response mutation fails diff |
## Wave 0 Requirements
- Existing `../fonoteka.go/parity/TestMain` already starts a Postgres container and the recorded fixture exists. The first implementation slice adds the real app boot and a focused route smoke test before moving `newTarget`.
- Test helper for applying both plugin migration sets and seeding Alice's active collection belongs in the app test package, and must not be copied into `tide`.
- No additional test framework or watch mode is required.
## Manual-Only Verifications
| Behavior | Requirement | Why manual | Test instructions |
|---|---|---|---|
| Database provisioning | QA-04 | Production Postgres lies outside the test suite | Use a fresh database created with `TEMPLATE template0`, `LOCALE_PROVIDER icu`, `ICU_LOCALE 'pl-PL'`, and UTF8 encoding; run the startup locale check before migrations. The user confirmed database-level locale on 2026-09-17. |
## Validation Sign-Off
- [ ] Plan IDs and per-task commands filled after plan-count checkpoint.
- [ ] Every task has automated feedback; no three consecutive tasks without it.
- [ ] Security threat model appears in each plan and the final plan tests its high severity mitigations.
- [ ] Root and app quick checks, race checks, Postgres integration, and recorded parity are green.
- [ ] Mark `nyquist_compliant: true` only after implementation evidence exists.
**Approval:** pending execution.