Files
summercms/.planning/phases/14-domain-jobs-and-external-integrations/14-VALIDATION.md
Jakub Zych 17b2ef1961 docs(14-06): Phase 14 validation signed off, requirements complete, API coverage confirmed, folded todos closed
- 14-VALIDATION.md: per-task map 14-01-T1 to 14-06-T4, all green, the
  measured coverage, validated, Nyquist-compliant, Wave 0 complete, the
  final --all and --removal results
- REQUIREMENTS.md: INTG-02 and API-08 Complete (JOBS-02, JOBS-03, SRCH-02,
  INTG-01, CLI-05 already were)
- COVERAGE.md: every INTEGRATE row's test confirmed by --named
- fetchguard-guarded-http-client and redacting-slog-handler moved to done
2026-10-04 02:47:53 +02:00

18 KiB

phase, slug, status, nyquist_compliant, wave_0_complete, created, validated, gate
phase slug status nyquist_compliant wave_0_complete created validated gate
14 domain-jobs-and-external-integrations validated true true 2026-10-03 2026-10-04 scripts/check-phase14.sh --all

Phase 14 — Validation Strategy

Per-phase validation contract for feedback sampling during execution.


Test Infrastructure

Property Value
Framework go test (+ testify), testcontainers-go postgres, tide parity replay
Config file none (Go); gate script scripts/check-phase14.sh (--self-test --go --parity --named --removal --coverage --evidence --all, modelled on check-phase13.sh)
Quick run command go -C ../fonoteka.go test ./plugins/golem15/fonoteka/... -count=1 -short
Full suite command bash scripts/check-phase14.sh --all (vet and tests in both repos with -race in fonoteka.go, the corpus, every named test, the coverage floors and this file), then bash scripts/check-phase14.sh --removal on its own
Estimated runtime about 15 minutes for --all, about 25 minutes for --removal

Sampling Rate

  • After every task commit: the task's named -run tests plus go vet in the touched repo
  • After every plan wave: go test ./... in both repos plus TestParityCorpus / TestFonotekaNuxtFlows
  • Before /gsd-verify-work: scripts/check-phase14.sh --all must be green: vet and tests in summercms.go and, with -race, in fonoteka.go including sm-user-plugin, sm-golem-plugin and sm-feedback-plugin; no vendor AI SDK in either module graph; the parity corpus (175 recorded, 172 ported and passing, the 3 D-09 routes not ported, read from the replay's own coverage line and the manifest), every TestFonotekaNuxtFlows subtest, the broadcast goldens, TestUpstreamSidecarsAreReplayed, TestFeedbackJobSidecarMatchesPlugin, check_corpus --require-recorded --check-secrets, the fuzz corpus scan, TestDocsTree and docs:build --check; every named test by exact name; the coverage floors; and this file, the security review, COVERAGE.md, REQUIREMENTS.md and the ROADMAP Phase 14 section
  • Max feedback latency: 180 seconds per task's named tests

Per-Task Verification Map

Every row's tests are run by name by scripts/check-phase14.sh --named (the evidence stage refuses a row naming a test it does not run); the parity rows also by --parity. All rows were green in the 2026-10-04 run of --all.

Task ID Plan Wave Requirement Threat Ref Behavior Test Type Automated Command File Exists Status
14-01-T1 14-01 1 INTG-02 (framework) T-14-01, T-14-02 A guarded JSON POST through fetchguard.Client is answered offline by the asserting tide upstream fake; the transport seam is code-only unit go test ./modules/fetchguard -run '^(TestClientPostJSONThroughUpstreamFake|TestTransportSeamIsCodeOnly|TestClientNeverFollowsRedirects)$' -count=1 -v ✅ modules/fetchguard/client_test.go, client_internal_test.go ✅ green
14-01-T2 14-01 1 INTG-02 (framework) T-14-01, T-14-06 PUT, multipart, bearer and trusted mode; https and host checks before I/O; the body cap unit go test ./modules/fetchguard -run '^(TestClientModes|TestClientSchemeGuard|TestClientMultipart|TestClientBodyCap|TestClientPutJSONHeaderOrder)$' -count=1 -v ✅ modules/fetchguard/client_test.go ✅ green
14-01-T3 14-01 1 INTG-01 (framework) T-14-04, T-14-05 summer parity:upstream records masked sidecars on loopback only; the fake asserts the request; refusals of malformed sidecars unit go test ./modules/tide -run '^(TestUpstreamProxyScriptMode|TestUpstreamProxyRefusesNonLoopback|TestEnsureParityCA|TestUpstreamProxyMultipartAndForwardGuard|TestWriteUpstreamRefusesUnmaskedCredential|TestUpstreamFakeRejectsMismatchedRequest|TestUpstreamFakeHashesBase64Bodies|TestUpstreamSidecarRefusals)$' -count=1 -v ; go test ./cmd/summer -run '^(TestParityCommandContract|TestToolCommandNames)$' -count=1 ✅ modules/tide/upstream_test.go, upstream_proxy_test.go, upstream_coverage_test.go ✅ green
14-01-T4 14-01 1 SRCH-02 (framework) T-14-03, T-14-07 sunscreen redacts credentials in every generated main; surf hides panic text; DropIndex and EnsureIndex unit go test ./modules/sunscreen ./modules/surf ./internal/build ./modules/beachcomber/... -run '^(TestRedactHandler|TestScrub|TestInstallDefault|TestRecoverHidesPanicDetails|TestGenerateMainInstallsRedactingLogger|TestDropIndex|TestEngineDropIndex|TestEngineEnsureIndex)$' -count=1 ✅ modules/sunscreen/sunscreen_test.go, modules/surf/recover_redaction_test.go, modules/beachcomber/typesense/engine_test.go ✅ green
14-01-T5 14-01 1 INTG-02, API-08 — REQUIREMENTS, ROADMAP and PROJECT reworded (D-06, D-07, D-13, D-14) gate bash scripts/check-phase14.sh --evidence (the SDK and sitemap wording refused; the ROADMAP Phase 14 repos and criteria name the routes and both plugin repos) ✅ .planning/REQUIREMENTS.md, .planning/ROADMAP.md ✅ green
14-02-T1 14-02 2 JOBS-02, INTG-01 T-14-08, T-14-11 A CSV row's Discogs pick resolves with PHP's draft, replayed from PHP's recorded exchange; the HMAC bucket unit + parity go -C ../fonoteka.go test ./plugins/golem15/fonoteka -run '^(TestCsvRowPickSeam|TestCsvRowPickResolves)$' -count=1 -race ; go -C ../fonoteka.go test ./plugins/golem15/fonoteka/classes/discogs -run '^(TestBucketID|TestRateLimiterPostgresAcquire)$' -count=1 ; go -C ../fonoteka.go test ./parity -run '^(TestParityCorpus|TestUpstreamSidecarsAreReplayed)$' -count=1 ✅ csv_smoke_test.go, classes/discogs/postgres_test.go ✅ green
14-02-T2 14-02 2 INTG-01 T-14-09 Client statuses, limiter budget and Retry-After, the PHP truth tables of the mapper, parser, scorer and price resolver unit + truth table go -C ../fonoteka.go test ./plugins/golem15/fonoteka/classes/discogs -run '^(TestPHPTruthDiscogs|TestClientGetRelease|TestDiscogsClientStatuses|TestRateLimiterBudget|TestRateLimiterSyncFromHeaders|TestRegisterRetryAfter|TestDiscogsDomainVectors|TestDiscogsRateWindowConcurrent|TestNumberFormat4)$' -count=1 -race ✅ classes/discogs/discogs_test.go, php_truth_test.go, testdata/php_*.json ✅ green
14-02-T3 14-02 2 JOBS-02 T-14-10, T-14-12, T-14-13 Match and import workers: 0/1/many, pause and re-dispatch, cancel, superseded, write_failed, lost access; WR-02 locks unit + Postgres go -C ../fonoteka.go test ./plugins/golem15/fonoteka -run '^(TestCsvMatchJob|TestCsvImportJob|TestCsvWR02)$' -count=1 -race ✅ csv_jobs_test.go, csv_wr02_test.go ✅ green
14-02-T4 14-02 2 JOBS-03, SRCH-02, CLI-05 T-14-14, T-14-15 The digest mails once per window; prune-notifications on the daily schedule; reindex with its integrity checks and the legacy drop unit + Postgres go -C ../fonoteka.go test ./plugins/golem15/fonoteka -run '^(TestWishlistDigestJob|TestWishlistDigestWorkerRegistered|TestFonotekaSchedulePrune)$' -count=1 ; go -C ../fonoteka.go test ./plugins/golem15/fonoteka/console -run '^(TestPruneNotifications|TestReindexCommand)$' -count=1 ✅ wishlist_digest_job_test.go, schedule_test.go, console/phase14_commands_test.go ✅ green
14-03-T1 14-03 3 INTG-01 T-14-16, T-14-17 Album match: scope first, the gate, the shared bucket, PHP's scored candidates unit + parity go -C ../fonoteka.go test ./plugins/golem15/fonoteka -run '^(TestDiscogsMatchRoute|TestDiscogsInboundLimits|TestRouteTablePhase14)$' -count=1 -race ✅ discogs_routes_test.go, routes_table_phase14_test.go ✅ green
14-03-T2 14-03 3 INTG-01 T-14-18, T-14-19 Apply-release fill-empty, overwrite, cover_only and PHP's dry run; draft match; wishlist twins unit + parity go -C ../fonoteka.go test ./plugins/golem15/fonoteka -run '^(TestApplyReleaseModes)$' -count=1 -race ; go -C ../fonoteka.go test ./plugins/golem15/fonoteka/classes/discogs -run '^(TestCoverFetcherHostLock)$' -count=1 ✅ discogs_routes_test.go, classes/discogs/cover_fetcher_test.go ✅ green
14-03-T3 14-03 3 INTG-01 T-14-17, T-14-20, T-14-21 Import box, MCP cover-price (write scope, throttle 12/min), token test unit + parity go -C ../fonoteka.go test ./plugins/golem15/fonoteka -run '^(TestDiscogsImportRoute|TestCoverPriceRoute|TestDiscogsCredentialTestRoute)$' -count=1 -race ✅ discogs_routes_test.go ✅ green
14-04-T1 14-04 4 INTG-02 T-14-29 sm-golem-plugin boots before fonoteka; ai-credential/test answers PHP's bodies unit + parity go -C ../fonoteka.go test ./plugins/golem15/golem -run '^(TestGolemPluginBoot)$' -count=1 ; go -C ../fonoteka.go test ./plugins/golem15/fonoteka -run '^(TestAICredentialTestRoute)$' -count=1 ✅ golem/golem_test.go, ai_routes_test.go ✅ green
14-04-T2 14-04 4 INTG-02 T-14-22, T-14-24 Both adapters' payloads, every AIService call, the SSRF guard, the models admin and importer unit go -C ../fonoteka.go test ./plugins/golem15/golem/... -run '^(TestOpenAIAdapterPayload|TestAnthropicAdapterPayload|TestAIServiceFailures|TestAIServiceStream|TestDefaultModelQuirk|TestPromptFactory|TestSSRFGuard|TestImportSettings|TestAdminModelsForm|TestGolemAdminSchemas|TestGolemImportCommand)$' -count=1 ✅ golem/classes/*/..._test.go, golem/golem_admin_test.go ✅ green
14-04-T3 14-04 4 INTG-02 T-14-22, T-14-23 The AI tier: admin vision model trusted, user and org guarded, PHP's precedence unit go -C ../fonoteka.go test ./plugins/golem15/fonoteka -run '^(TestAdminVisionTier|TestResolveAIConfigPrecedence)$' -count=1 ; go -C ../fonoteka.go test ./plugins/golem15/golem/classes/services -run '^(TestAdminModelTrusted)$' -count=1 ✅ ai_routes_test.go, credentials_smoke_test.go ✅ green
14-04-T4 14-04 4 INTG-02 T-14-25, T-14-26, T-14-27 Recognition on both groups: prompt, retry, truncation, caps, image guard, bucket unit + parity go -C ../fonoteka.go test ./plugins/golem15/fonoteka -run '^(TestRecognizeRoutes)$' -count=1 -race ; go -C ../fonoteka.go test ./plugins/golem15/fonoteka/classes -run '^(TestRecognizeAlbums)$' -count=1 ✅ ai_routes_test.go, classes/album_recognition_test.go ✅ green
14-05-T1 14-05 5 API-08 T-14-30 Widget config behind the constant-time key and the fail-closed Origin list unit + parity go -C ../fonoteka.go test ./plugins/golem15/feedback -run '^(TestFeedbackPluginBoot|TestFeedbackConfig|TestKeyMatches|TestURLHost|TestAllowedOriginHosts|TestFeedbackOptionsPreflight)$' -count=1 ; go test ./modules/surf -run '^(TestCORSOptionsMatchesLaravel)$' -count=1 ✅ feedback/feedback_test.go, modules/surf/cors_coverage_test.go ✅ green
14-05-T2 14-05 5 API-08 T-14-31, T-14-32, T-14-35 Submit with PHP's validation and image guard, me/hidden, the user payload key unit + parity go -C ../fonoteka.go test ./plugins/golem15/feedback -run '^(TestFeedbackSubmit|TestMeHidden|TestFeedbackApiArrayHook)$' -count=1 -race ; go -C ../fonoteka.go test ./plugins/golem15/feedback/classes -run '^(TestImageGuardCopy)$' -count=1 ✅ feedback/feedback_test.go, feedback/classes/classes_test.go ✅ green
14-05-T3 14-05 5 API-08 T-14-33, T-14-34, T-14-36 G15Office job replays PHP's exchange; settings and submissions admin; embed.js; settings import unit + parity go -C ../fonoteka.go test ./plugins/golem15/feedback/classes -run '^(TestSyncG15Office|TestTaskText)$' -count=1 ; go -C ../fonoteka.go test ./plugins/golem15/feedback -run '^(TestFeedbackAdminSchemas|TestEmbedJSServed|TestFeedbackImportSettings)$' -count=1 ; go -C ../fonoteka.go test ./parity -run '^(TestFeedbackJobSidecarMatchesPlugin)$' -count=1 ✅ feedback/classes/classes_test.go, parity/feedback_seed_test.go ✅ green
14-06-T1 14-06 6 JOBS-02, JOBS-03, SRCH-02, INTG-01, INTG-02, API-08, CLI-05 T-14-37 The gate runs both repositories, the corpus at 175/172 and the flows, and fails closed gate bash scripts/check-phase14.sh --self-test && bash scripts/check-phase14.sh --go && bash scripts/check-phase14.sh --parity ; go -C ../fonoteka.go test ./parity -run '^(TestParityCorpus|TestCheckCorpusPortedCaseStatus|TestFonotekaNuxtFlows|TestCheckCorpusUpstreamCredential|TestParityContract|TestSchemaMatchesPHPSnapshot)$' -count=1 ✅ scripts/check-phase14.sh ✅ green
14-06-T2 14-06 6 INTG-01, JOBS-02 T-14-19 PHP truth tables row for row; the numeric edges one step either side; the job lifecycles; the route table and the fuzz over the Phase 14 routes unit + truth table + fuzz seeds go -C ../fonoteka.go test ./plugins/golem15/fonoteka -run '^(TestPhase14Edges|TestPhase14Jobs|TestRouteTablePhase14|TestRouteTablePhase13|TestRouteTablePhase12|FuzzWriteEndpoints|TestPhase14HandlersFailClosed)$' -count=1 -race ; go -C ../fonoteka.go test ./plugins/golem15/fonoteka/classes ./plugins/golem15/fonoteka/controllers/api -run '^(TestPhase14Classes|TestPhase14ControllerHelpers)$' -count=1 ; go -C ../fonoteka.go test ./plugins/golem15/fonoteka/classes/discogs -run '^(TestPHPTruthDiscogs)$' -count=1 ✅ phase14_edges_test.go, phase14_jobs_test.go, phase14_handlers_test.go, write_endpoints_fuzz_test.go, classes/phase14_classes_test.go, controllers/api/phase14_controllers_test.go, classes/discogs/php_truth_test.go ✅ green
14-06-T3 14-06 6 INTG-02, API-08 T-14-38, all mitigated Every mitigated threat fails without its protection; the framework and both plugins at the floor unit + gate go -C ../fonoteka.go test ./plugins/golem15/fonoteka -run '^(TestPhase14Threats)$' -count=1 -race ; go -C ../fonoteka.go test ./plugins/golem15/feedback -run '^(TestFeedbackEdges)$' -count=1 ; bash scripts/check-phase14.sh --named && bash scripts/check-phase14.sh --coverage && bash scripts/check-phase14.sh --removal ✅ phase14_security_test.go, feedback/feedback_edges_test.go, 14-SECURITY-REVIEW.md ✅ green
14-06-T4 14-06 6 JOBS-02, JOBS-03, SRCH-02, INTG-01, INTG-02, API-08, CLI-05 — Validation signed off, requirements marked, API coverage checked, folded todos closed, the whole gate green gate bash scripts/check-phase14.sh --evidence && bash scripts/check-phase14.sh --all ✅ this file, COVERAGE.md, .planning/REQUIREMENTS.md ✅ green

Status: ✅ green · ❌ red · ⚠️ flaky

Coverage (scripts/check-phase14.sh --coverage, 2026-10-04)

Package Statements covered
summercms.go modules/fetchguard 84.5%
summercms.go modules/tide 82.1%
summercms.go modules/sunscreen 98.5%
summercms.go modules/beachcomber 84.8%
summercms.go modules/beachcomber/typesense 95.6%
fonoteka classes/discogs 86.1%
fonoteka console 82.6%
fonoteka root, classes, controllers/api: the 132 Phase 14 functions each at 80.0% or more (lowest 80.0%: AlbumReleaseMatchDraft, both workers' fail), two exempt with reasons: cover_importer.go fetch 72.7% (its 2xx path needs the live image host) and validateDiscogsInput 77.8% (its error branch needs a malformed rule table)
sm-golem-plugin root, classes/factories, providers, security, services, valueobjects, console, controllers, models, updates 100.0%, 90.0%, 93.4%, 98.0%, 85.5%, 90.8%, 96.1%, 93.1%, 100.0%, 80.0%
sm-feedback-plugin root, classes, console, controllers, controllers/api, models, updates 93.8%, 82.9%, 92.6%, 100.0%, 86.0%, 90.8%, 91.7%
internal/pgtest of both plugins exempt: a test-only helper whose uncovered lines are container start failures

Wave 0 Requirements

  • fonoteka.go/parity/discogs_truth_tables.php — truth-table generator (csv_truth_tables.php pattern; 14-02, widened in 14-06 to php_mapper.json, php_input_parser.json, php_scorer.json, php_price_suggestion.json)
  • tide upstream sidecar loader + fake and the replay hook for *.upstream.yaml (14-01, 14-02)
  • Shared fake clock helper for limiter, client and job tests (classes/discogs/discogstest, 14-02)
  • Harness to run a conga worker function directly without a live River client (deliverCsvMatch, deliverCsvImport, deliverWishlistDigest take the job id, 14-02)
  • scripts/check-phase14.sh with EXPECTED_ROUTES=175, EXPECTED_PORTED=172, EXPECTED_PENDING=3 (14-06)

Manual-Only Verifications

Behavior Requirement Why Manual Test Instructions
Live Discogs / Anthropic / OpenAI / G15Office exchanges INTG-01, INTG-02, API-08 CI makes no live vendor calls (D-15) Record sidecars once against PHP with real credentials; replay is offline
Feedback widget embed in the Nuxt app API-08 Browser rendering Load the Nuxt app against the Go backend, submit feedback with a screenshot

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 < 180s per task's named tests
  • Nyquist compliance set in the frontmatter

Approval: validated 2026-10-04 (plan 14-06; gate scripts/check-phase14.sh --all and --removal green)

Final gate run: bash scripts/check-phase14.sh --all on 2026-10-04 ended with phase14 all passed (self-test, go, parity at "175/175 recorded, 172 ported and passing, 0 failing, 3 pending", named, coverage and evidence; 13 min 55 s). bash scripts/check-phase14.sh --removal on its own ended with phase14 removal passed (43 of 43 mutations failed their named test; every file restored byte for byte). One earlier --all run refused at the coverage stage when the updates package's testcontainers Postgres did not start within its 60 s wait under load; the rerun passed unchanged.