Files
summercms/.planning/phases/05-data-layer-full-fidelity/05-VALIDATION.md
2026-09-18 17:31:53 +02:00

10 KiB

phase, slug, status, nyquist_compliant, wave_0_complete, created
phase slug status nyquist_compliant wave_0_complete created
5 data-layer-full-fidelity planned true false 2026-09-18

Phase 5 — Validation Strategy

Per-phase validation contract for feedback sampling during execution.


Test Infrastructure

Property Value
Framework Go stdlib testing + testify (assert/require) + testcontainers-go modules/postgres v0.44.0
Config file none — plain func TestX(t *testing.T); TestMain pattern per lagoon/postgres_test.go and fonoteka.go/parity
Quick run command go vet ./... && go test ./... -short (run in the repo the task writes to)
Full suite command go test ./... in summercms.go and in ../fonoteka.go (real Postgres via testcontainers)
Estimated runtime ~20 s quick, ~120-180 s full (Plan 05-06 fuzz targets add ~2-3 min more)

Sampling Rate

  • After every task commit: Run go vet ./... && go test ./... -short
  • After every plan wave: Run go test ./... in both repos
  • Before /gsd:verify-work: Full suite green in both repos, including the D-02 schema-diff test and Plan 05-06's fuzz/security-review pass
  • Max feedback latency: 120 seconds (excluding explicit -fuzz=...s runs, which are bounded by their own -fuzztime)

Per-Task Verification Map

Note: Plan 05-01's original Task 1 (models-leaf restructure) was split into a probe/gate task and a restructure task during revision; the write-path/read-path lagoon-primitive tasks that follow it shifted from Task 2/3 to Task 3/4. Task IDs below reflect the revised numbering.

Task ID Plan Wave Requirement Threat Ref Secure Behavior Test Type Automated Command File Exists Status
05-01-T3 05-01 1 DATA-03 T-05-02 lagoon.WithSoftDeleteCascade framework primitive: cascading soft delete runs in one transaction (real cascade wiring lands in 05-02) integration go test ./lagoon/... -run TestWithSoftDeleteCascade ❌ W0 ⬜ pending
05-02-T2 05-02 2 DATA-03 T-05-24 Collection.BeforeDelete cascades a real soft-delete of every Album inside the same transaction, via the Plan 05-01 primitive integration go test ./plugins/golem15/fonoteka/... -run TestCollectionBeforeDeleteCascadesAlbums ❌ W0 ⬜ pending
05-02-T2 05-02 2 DATA-03 — Artist/Genre/Style BeforeValidate+AfterDelete hooks ported verbatim from PHP (slug/name_key defaulting, unassign-not-cascade, pivot detach) integration `go test ./plugins/golem15/fonoteka/... -run 'TestArtistBeforeValidate TestGenreHooks TestStyleHooks'`
05-02-T3 05-02 2 DATA-03 T-05-23 Album.BeforeSave (refreshTrackTitles+stampMarketPrice) fires on save and writes track_titles/normalizes money integration go test ./plugins/golem15/fonoteka/... -run TestSaveAlbumMoneyNormalization ❌ W0 ⬜ pending
05-02-T3 05-02 2 DATA-04 — 3+ artist album round-trips sort_order via explicit sync, never Association mode integration go test ./plugins/golem15/fonoteka/classes/... -run TestAlbumArtistsOrderRoundTrip ❌ W0 ⬜ pending
05-02-T3 05-02 2 DATA-04 — Collection.Editors RegisterJoinTable round-trips role/granted_at/granted_by on Preload integration go test ./plugins/golem15/fonoteka/... -run TestCollectionEditorsPivotRoundTrip ❌ W0 ⬜ pending
05-02-T3 05-02 2 DATA-05 T-05-06 Untranslatable rule fails loudly; 422 map Laravel-shaped; unique:table respects soft deletes unit + integration go test ./lagoon/... -run TestValidate ❌ W0 ⬜ pending
05-01-T3 05-01 1 DATA-06 T-05-01 Unknown/server-owned keys never persisted (framework primitive) unit go test ./lagoon/... -run TestFill ❌ W0 ⬜ pending
05-06-T1 05-06 5 DATA-06 T-05-04, T-05-20 Fill boundary fuzzed against real Postgres for Album/Collection/4 credential models integration (fuzz) go test ./plugins/golem15/fonoteka/classes/... -fuzz=FuzzSaveAlbum -fuzztime=20s ❌ W0 ⬜ pending
05-02-T2 05-02 2 DATA-07 — Money never float64; jsonable [] vs null per column (tracklist as []TrackEntry, cover_import_failures as []string) unit go test ./lagoon/... -run TestJsonable ❌ W0 ⬜ pending
05-02-T3 05-02 2 DATA-07 T-05-23 Money blank/null/non-numeric/PHP-ceiling/normal-value cases round-trip through SaveAlbum against real Postgres, never a bare float integration go test ./plugins/golem15/fonoteka/... -run TestSaveAlbumMoneyNormalization ❌ W0 ⬜ pending
05-03-T1 05-03 2 DATA-07 T-05-08, T-05-09, T-05-10 Ciphertext at rest, redacted marshal, plaintext only via Reveal(); key rotation via previous_keys; HKDF derivation uses stdlib crypto/hkdf only unit + integration go test ./lagoon/... -run TestEncrypted ❌ W0 ⬜ pending
05-04-T1 05-04 3 DATA-08 T-05-13 Thumb filename/partition match Winter exactly; lazy single resize unit `go test ./lagoon/attach/... -run 'TestThumbFilename TestPartitionDirectory'` ❌ W0
05-04-T2 05-04 3 DATA-08 T-05-14 Force delete removes blobs only after commit; soft delete keeps them integration go test ./lagoon/attach/... -run TestFileLifecycle ❌ W0 ⬜ pending
05-05-T2 05-05 4 DATA-09 T-05-17 Go schema equals committed PHP snapshot modulo a justified allow-list integration go test ./parity/... -run TestSchemaMatchesPHPSnapshot ❌ W0 ⬜ pending
05-02-T1 05-02 2 DATA-09 — Album/Collection slice migrations run up/down individually (incl. track_titles) integration go test ./parity/... -run TestAlbumSliceMigrationsUpDown ❌ W0 ⬜ pending
05-01-T4 05-01 1 DATA-10 — Envelope is {data,meta{...}}, no links key unit go test ./lagoon/... -run TestPaginate ❌ W0 ⬜ pending
05-05-T3 05-05 4 DATA-11 T-05-19 Test-only fixture plugin Boot() callback + own companion migration extend Album without editing models/album.go or fonoteka updates.All() integration go test ./parity/... -run TestCrossPluginCallback ❌ W0 ⬜ pending
05-05-T3 05-05 4 CLI-03 — Rollback touches only the named plugin's history, against the full schema integration go test ./parity/... -run TestRollbackIsolatesFonotekaFullSchema ❌ W0 ⬜ pending
05-06-T2 05-06 5 DATA-06/DATA-08 T-05-21 Every registered model's Hidden() columns are unmarshalable unit go test ./lagoon/... -run TestHiddenNeverMarshals ❌ W0 ⬜ pending
05-06-T2 05-06 5 DATA-09 T-05-07, T-05-18 Collection.public_token delete-then-recreate matches PHP's plain-unique behavior integration go test ./plugins/golem15/fonoteka/classes/... -run TestCollectionPublicTokenDeleteThenRecreate ❌ W0 ⬜ pending
05-06-T3 05-06 5 DATA-08 T-05-15, T-05-16 Full attachment lifecycle (photos, image, thumb, soft/force delete) against memblob integration go test ./plugins/golem15/fonoteka/classes/... -run TestAttachSmoke ❌ W0 ⬜ pending
05-06-T3 05-06 5 ALL (review) T-05-01..T-05-24 Every threat across all 5 prior plans mapped to a passing test or restated acceptance manual + grep-verified grep -rn "AutoMigrate" fonoteka.go/plugins summercms.go/lagoon (expect 0) ❌ W0 ⬜ pending

Status: ⬜ pending · ✅ green · ❌ red · ⚠️ flaky


Wave 0 Requirements

  • fonoteka.go/parity/testdata/php_schema_snapshot.sql — committed D-02 golden snapshot of the PHP final schema (Plan 05-05, Task 2)
  • lagoon/fill_test.go, lagoon/lifecycle_test.go, lagoon/paginate_test.go, lagoon/relations_test.go (Plan 05-01), lagoon/jsonable_test.go, lagoon/validate_test.go (Plan 05-02), lagoon/encrypted_test.go, lagoon/keygen_test.go, lagoon/laravel_decrypt_test.go (Plan 05-03) — tests for the new lagoon primitives
  • lagoon/attach/ package (File model, blob wiring, Thumb()) — does not exist yet, created by Plan 05-04
  • Existing test infra (lagoon/postgres_test.go TestMain, fonoteka.go/parity TestMain, activateAppPlugins/parityDB/gormOnSharedPool helpers) is reused, not rebuilt, across all 6 plans
  • fonoteka.go/parity/fixtureplugin/ — test-only plugin (plugin.go + migrations.go) activated only in TestCrossPluginCallback; not in app/app.go, plugins.gen.go, or fonoteka updates.All()

Manual-Only Verifications

All phase behaviors have automated verification. The one review-shaped item — 05-SECURITY-REVIEW.md (Plan 05-06, Task 3) — is grep-verified (zero AutoMigrate, every .Reveal() call site enumerated and checked against logging/serialization paths) rather than purely narrative.


Validation Sign-Off

  • All tasks have <automated> verify or Wave 0 dependencies
  • Sampling continuity: no 3 consecutive tasks without automated verify (every task across all 6 plans carries its own <verify><automated>)
  • Wave 0 covers all MISSING references (schema snapshot, new lagoon test files, lagoon/attach package)
  • No watch-mode flags
  • Feedback latency < 120s (fuzz targets are explicitly time-boxed via -fuzztime, outside the 120s per-task feedback loop)
  • nyquist_compliant: true set in frontmatter

Approval: approved at plan time (2026-09-18) — 6 plans written per the confirmed plan-count checkpoint; task IDs above are real, sourced from 05-01-PLAN.md through 05-06-PLAN.md. Revised 2026-09-18 after checker feedback: 05-01's Task 1 split into a probe/gate task and a restructure task (renumbering its lagoon-primitive tasks to T3/T4); DATA-03/DATA-07 rows added for the real hook implementations and money-normalization round-trip landed in 05-02; T-05-23/T-05-24 threat IDs added. Revision 2 (2026-09-18): DATA-11 fixture plugin is test-only (not in fonoteka updates.All()); Discogs IDs are TEXT/*string; Collection.Editors + StaticHandler action rows added. Task statuses remain ⬜ pending — this revision does not re-approve Nyquist.