Files
summercms/.planning/phases/07-user-plugin-and-authentication/07-VALIDATION.md
Jakub Zych 9446981ffd docs(07-06): complete the unit coverage plan
The validation contract is signed off and the phase plan count is 6/6. Requirement checkboxes stay open while the user-api routes are still pending.

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-09-22 19:21:31 +02:00

6.4 KiB
Raw Blame History

phase, slug, status, nyquist_compliant, wave_0_complete, created
phase slug status nyquist_compliant wave_0_complete created
7 user-plugin-and-authentication signed-off true true 2026-09-22

Phase 7 — Validation Strategy

Per-phase validation contract for feedback sampling during execution.


Test Infrastructure

Property Value
Framework Go stdlib testing + testify (assert/require); net/http/httptest for handler, guard, limiter and locale tests; testcontainers-go v0.44.0 (modules/postgres) only where the throttle table, jti blacklist, token CRUD and parity replay need real rows; postcard memory driver for mail assertions
Config file none — plain func TestX(t *testing.T); testing.Short() gates container-backed tests (convention from lagoon/postgres_test.go, postcard/mailpit_test.go, plugins/golem15/user/updates/postgres_test.go); parity TestMain in ../fonoteka.go/parity is reused
Quick run command go vet ./... && go test ./... -short (run in the repo the task writes to: summercms.go or ../fonoteka.go)
Full suite command go test ./... -race in summercms.go and in ../fonoteka.go, plus summer parity:replay --manifest fonoteka.go/parity/manifest.yaml
Estimated runtime ~20 s quick, ~120–180 s full

Sampling Rate

  • After every task commit: Run go vet ./... && go test ./... -short in the repo the task touched
  • After every plan wave: Run go test ./... -race in both modules + summer parity:replay against the fixtures recorded so far
  • Before /gsd:verify-work: Full suite green in both modules, every D-11 fixture recorded and replayed
  • Max feedback latency: 30 s (quick command)

Per-Task Verification Map

Task ID Plan Wave Requirement Threat Ref Secure Behavior Test Type Automated Command File Exists Status
07-02-2 07-02 2 AUTH-01 T-07-01 login/register/logout/fetch/refresh return the Go session contract; tokens are read from the bearer, not the URL or body unit + integration `go test ./plugins/golem15/user/ -run 'TestLogin TestLogout TestFetch
07-01-2 07-01 1 AUTH-01 T-07-01 sliding refresh accepts a token inside refresh_ttl, rejects past it; logout blacklists the jti; the grace window is honoured unit `go test ./bouncer/ -run 'TestRefresh TestBlacklist TestMintRefreshBlacklistRoundTrip
07-01-3 07-01 1 AUTH-01 T-07-04 $2y$ PHP hashes verify; a lower-cost hash is eligible for rehash; per-(user,ip) throttle suspends after 5 unit + integration `go test ./bouncer/ -run 'TestPassword' && go test ./plugins/golem15/user/ -run 'TestCheckAndRecordLogin TestLoginSixthAttempt'` ✅
07-02-3 07-02 2 AUTH-02 — fonoteka getApiArray listener adds organisation fields, must_change_password, preferred_locale; the user module does not import fonoteka unit go test ./plugins/golem15/fonoteka/ -run TestGetApiArray && go test ./plugins/golem15/user/ -run TestRegisterImportDirection ✅ ✅ green
07-04-2 07-04 3 AUTH-03 T-07-08 mint/list/revoke; scopes read/write/ai and a two-scope mint succeed; admin is rejected before insert; InvScope 403s a read token on a write route unit + integration `go test ./plugins/golem15/fonoteka/ -run 'TestTokenApi TestMintPersonalToken' && go test ./plugins/golem15/fonoteka/middleware/ -run TestInvScope` ✅
07-06-2 07-06 5 AUTH-04 T-07-08 423 on genres and tokens while locked; me/locale and change-password succeed; genres succeeds after the lock clears integration go test ./plugins/golem15/fonoteka/ -run TestMustChangePasswordLock ✅ ✅ green
07-01-3 07-01 1 I18N-02 — preferred_locale then Accept-Language then app.locale, including while the password lock is set unit go test ./surf/ -run TestLocaleFromPrincipal ✅ ✅ green
07-05-2 07-05 4 AUTH-01..04 — ported fixtures replay green; the 15 user routes stay pending until Go matches the recorded PHP bodies parity replay go test ./parity/ -run TestParityCorpus ✅ ✅ green

Status: ⬜ pending · ✅ green · ❌ red · ⚠️ flaky. Task IDs are filled in by the planner once PLAN.md files exist.


Wave 0 Requirements

  • fonoteka.go/plugins/golem15/user/session_test.go, register_test.go, sequence_test.go — AUTH-01 session and register coverage
  • summercms.go/bouncer/mint_test.go, refresh_test.go, blacklist_test.go, phase07_coverage_test.go — AUTH-01 refresh/blacklist isolated from HTTP
  • fonoteka.go/plugins/golem15/fonoteka/token_locale_test.go — AUTH-03 token and locale handlers
  • summercms.go/surf/locale_from_principal_test.go — I18N-02
  • fonoteka.go/parity/fixtures/routes/*_user_api_v1_*.yaml — recorded against the isolated PHP instance
  • Framework install: none — testcontainers-go and testify already present; golang.org/x/crypto is a direct dependency

Manual-Only Verifications

Behavior Requirement Why Manual Test Instructions
Recording the new parity fixtures AUTH-01..04 Needs the isolated PHP instance and a private 0600 vars store; no live JWT in git Run tide record per D-11 against PHP with the DB-reading seed hook (D-12) for reset/activation codes; commit fixtures, not vars
PHP $2y$ hash cross-check (Assumption A1) AUTH-01 One-off cross-language confirmation php -r 'echo password_hash("secret", PASSWORD_BCRYPT);', paste into a Go test that calls bcrypt.CompareHashAndPassword; keep the test afterwards
Throttle path confirmation (Assumption A2) AUTH-01 Confirms JWTAuth::attempt() reaches Winter's Auth\Manager throttle Record one PHP fixture of 6 rapid failed logins and assert the suspended body appears on the 6th

Validation Sign-Off

  • All tasks have <automated> 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 < 30s
  • nyquist_compliant: true set in frontmatter

Approval: signed off 2026-09-22 after the phase-7 test commands above passed