From b36acb375ae353b346dfdc158bad092c5fed5621 Mon Sep 17 00:00:00 2001 From: Jakub Zych Date: Wed, 14 Oct 2026 13:19:58 +0200 Subject: [PATCH] docs(phase-18.1): add validation strategy --- .../18.1-VALIDATION.md | 90 +++++++++++++++++++ 1 file changed, 90 insertions(+) create mode 100644 .planning/phases/18.1-payment-gateway-subscriptions/18.1-VALIDATION.md diff --git a/.planning/phases/18.1-payment-gateway-subscriptions/18.1-VALIDATION.md b/.planning/phases/18.1-payment-gateway-subscriptions/18.1-VALIDATION.md new file mode 100644 index 0000000..8396627 --- /dev/null +++ b/.planning/phases/18.1-payment-gateway-subscriptions/18.1-VALIDATION.md @@ -0,0 +1,90 @@ +--- +phase: "18.1" +slug: "payment-gateway-subscriptions" +# status lifecycle: draft (seeded by plan-phase) → validated (set by validate-phase §6) +# audit-milestone §5.5 distinguishes NOT-VALIDATED (draft) from PARTIAL (validated + nyquist_compliant: false) (#2117) +status: draft +nyquist_compliant: false +wave_0_complete: false +created: "2026-10-14" +--- + +# Phase 18.1 — Validation Strategy + +> Per-phase validation contract for feedback sampling during execution. Source: `18.1-RESEARCH.md` § Validation Architecture. + +--- + +## Test Infrastructure + +| Property | Value | +|----------|-------| +| **Framework** | Go `testing` + testcontainers Postgres 16 (Docker tests skip under `-short`); layer: `node --test` via `pnpm test` | +| **Config file** | per-repo `testmain_test.go` (copy of P18 `sm-pgstripe-plugin/testmain_test.go`: `flag.Parse()` + `testing.Short()`) — Wave 0 for the new pgsub repo | +| **Quick run command** | `go -C ../sm-paymentgatewaysubscriptions-plugin vet ./... && go -C ../sm-paymentgatewaysubscriptions-plugin test -short ./...` ; `go -C ../sm-pgstripe-plugin vet ./... && go -C ../sm-pgstripe-plugin test -short ./...` | +| **Full suite command** | same with `go test ./...` (Docker) in both plugin repos; `pnpm -C ../vue-paymentgateway-layer test`; `go vet ./... && go test -short ./...` in `summercms.go` | +| **Phase gate** | `scripts/check-phase18.1.sh` in `summercms.go` (precedent `scripts/check-phase18.sh`) | +| **Estimated runtime** | quick ~30 s per repo; full ~3–5 min (containers) | + +--- + +## Sampling Rate + +- **After every task commit:** the `-short` quick run of the touched repo +- **After every plan wave:** full suite of the touched repos (Docker) +- **Before `/msd-verify-work`:** `scripts/check-phase18.1.sh` green +- **Max feedback latency:** 60 seconds for the quick run + +--- + +## Per-Task Verification Map + +Filled in by the planner per task; the success-criterion map below is the contract. + +| Req | Behaviour | Type | Automated command | File exists | Status | +|-----|-----------|------|-------------------|-------------|--------| +| SC-1 | Baseline up/down, idempotent re-run, names match the Horoskopia dump; `users.stripe_customer_id` added only if missing | Docker | `go test ./updates/ -run TestBaseline` (pgsub) | ❌ W0 | ⬜ pending | +| SC-1 | Registry: duplicate alias fails boot; unknown alias errors; `user` subscribable reads/writes `users.stripe_customer_id` | unit + Docker | `go test -short ./... -run TestRegistry`; `go test ./... -run TestUserSubscribable` | ❌ W0 | ⬜ pending | +| SC-1 | Status / grace / feature / days-until-renewal matrices | unit | `go test -short ./... -run 'TestAccess\|TestGrace\|TestFeatures'` | ❌ W0 | ⬜ pending | +| SC-2 | Webhook: 500 no secret, 400 bad sig/payload, 200 duplicate (no job), 200 unhandled type (no job), one job per handled type, both URLs | Docker + `-short` decode | `go test ./subscriptions/ -run TestWebhook` (pgstripe) | ❌ W0 | ⬜ pending | +| SC-2 | Job: marker only on success (STRIPE-006), skip paths keep marker (STRIPE-007), duplicate/concurrent fire once, basil + pre-basil shapes | Docker | `go test ./subscriptions/ -run TestJob` | ❌ W0 | ⬜ pending | +| SC-2 | Event matrix activated / past_due / canceled / reactivated per previous→current; deleted always canceled | unit on `Service.Apply` | `go test ./... -run TestApplyEvents` (pgsub) | ❌ W0 | ⬜ pending | +| SC-2 | `SyncPlanToGateway`: free skip, product create/update, price unchanged / archive+create, stored IDs | fake Stripe | `go test ./subscriptions/ -run TestSyncPlan` | ❌ W0 | ⬜ pending | +| SC-3 | Admin YAML boots, bulk/toolbar sync results, preview partial | Docker smoke | `go test ./ -run TestAdmin` (pgsub) | ❌ W0 | ⬜ pending | +| SC-3 | Customer API authz (401 without JWT, plans public), 404/409/422 paths, redirect URLs from config only | Docker | `go test ./api/ -run TestCustomerAPI` | ❌ W0 | ⬜ pending | +| SC-3 | Layer client and components | node | `pnpm -C ../vue-paymentgateway-layer test` | ❌ W0 | ⬜ pending | +| SC-4 | Host flow: checkout → created → activated; invoice.paid; payment_failed + past_due with grace by clock; cancel at period end → deleted → canceled; reactivation; duplicate idempotency; plan sync; one real conga worker run | Docker | `go test ./subscriptions/ -run TestHostSubscriptionFlow` | ❌ W0 | ⬜ pending | +| SC-5 | PHP test map covered (ReliabilityTest STRIPE-006, DataHandlingTest PAY-10 / STRIPE-001 / STRIPE-003, AuthenticationTest) | gate | `scripts/check-phase18.1.sh` | ❌ W0 | ⬜ pending | + +*Status: ⬜ pending · ✅ green · ❌ red · ⚠️ flaky* + +--- + +## Wave 0 Requirements + +- [ ] `sm-paymentgatewaysubscriptions-plugin/testmain_test.go` + harness (copy P18 `testmain_test.go`, `harness_test.go`) +- [ ] Subscription-endpoint Stripe fake usable from `sm-pgstripe-plugin/subscriptions` (P18's `stripefake_test.go` is not importable): customers, checkout sessions, billing portal sessions, subscriptions get/update/cancel, products create/update, prices list/create/update +- [ ] Webhook event-body builders for both API shapes (pre-basil and basil) for subscription and invoice objects +- [ ] `scripts/check-phase18.1.sh` + +--- + +## Manual-Only Verifications + +| Behavior | Requirement | Why Manual | Test Instructions | +|----------|-------------|------------|-------------------| +| Billing-portal cancellation arrives as `cancel_at_period_end` or `cancel_at` | SC-2 | Depends on live Stripe portal behaviour on the account's API version | Stripe test mode + `stripe listen` forwarding to the subscriptions URL; cancel through the portal; inspect the delivered `customer.subscription.updated` | +| Real Stripe test-mode checkout end to end | SC-4 | The fake cannot prove Stripe's hosted checkout | Test-mode keys in settings, run checkout from the layer playground, confirm activation and the `activated` event | + +--- + +## Validation Sign-Off + +- [ ] All tasks have `` verify or Wave 0 dependencies +- [ ] Sampling continuity: no 3 consecutive tasks without automated verify +- [ ] Wave 0 covers all MISSING references +- [ ] No watch-mode flags +- [ ] Feedback latency < 60s +- [ ] `nyquist_compliant: true` set in frontmatter + +**Approval:** pending