Files
summercms/.planning/phases/02-api-parity-harness-bootstrap/02-04-SUMMARY.md
Jakub Zych 9a8fcc2c1e docs(02-04): complete honest-go-replay-with-testcontainers plan
Tasks completed: 2/2
- Replay a synthetic write/read flow against Postgres
- Expose the full corpus as honest selectable subtests

SUMMARY: .planning/phases/02-api-parity-harness-bootstrap/02-04-SUMMARY.md
2026-09-17 13:59:04 +02:00

8.2 KiB

phase, plan, subsystem, tags, requires, provides, affects, tech-stack, key-files, key-decisions, patterns-established, requirements-completed, duration, completed
phase plan subsystem tags requires provides affects tech-stack key-files key-decisions patterns-established requirements-completed duration completed
02-api-parity-harness-bootstrap 04 testing
parity
testcontainers
postgres
httptest
seed-hook
coverage
phase provides
02-api-parity-harness-bootstrap Isolated PHP on 127.0.0.1:8423 with a parity-named SQLite DB
phase provides
02-api-parity-harness-bootstrap Recorded API seed plus 154 live PHP route fixtures
phase provides
02-api-parity-harness-bootstrap tide record/replay/proxy, capture rules, named vars, manifest --next-batch, summer parity:*
App-owned testcontainers Postgres lifecycle for go test ./parity
Synthetic SQL-backed httptest handler with POST/GET /synthetic/items
newTarget and seedHooks seam for Phase 3 genres without claiming PHP routes
TestParityCorpus
154 recorded/pending selectable subtests, zero Go passes
02-05
03
added patterns
github.com/testcontainers/testcontainers-go v0.44.0 (app tests only)
github.com/testcontainers/testcontainers-go/modules/postgres v0.44.0
github.com/jackc/pgx/v5 v5.10.0 (stdlib driver)
One Postgres container per go test ./parity suite; t.Cleanup/Terminate; -short skips, missing Docker fails
YAML names a seed hook; only registered Go functions run parameterized SQL
Pending PHP routes are recorded and selectable but never sent to the synthetic handler
created modified
../fonoteka.go/parity/parity_test.go
../fonoteka.go/parity/synthetic_test.go
../fonoteka.go/parity/testdata/synthetic-seed.yaml
../fonoteka.go/parity/testdata/synthetic-read.yaml
../fonoteka.go/go.mod
../fonoteka.go/go.sum
../fonoteka.go/parity/README.md
newTarget and seedHooks live in the app test package so Phase 3 can swap the synthetic handler for the real app and add a temporary genres SQL hook until POST genres is ported
Pending never equals passing: TestParityCorpus reports recorded 154/154 passing 0 pending 154 and does not replay PHP fixtures against the synthetic handler
Unavailable Docker fails TestMain; testing.Short skips the container so the fast loop stays fast
Pattern: invokeSeedHook rejects unknown names; YAML never carries SQL text
Pattern: corpus subtest names sanitize route ids (slash/space to _) so -run selects one flow
Pattern: a deliberately ported PHP fixture against the synthetic handler must fail with a path diff (status 200 vs 404)
QA-02
QA-03
9min 2026-09-17

Phase 2 Plan 4: Honest Go replay with testcontainers Postgres Summary

App go test ./parity starts testcontainers Postgres, replays a SQL-backed synthetic write/read through tide, and lists all 154 PHP routes as recorded/pending with zero Go passes

Performance

  • Duration: 9 min
  • Started: 2026-09-17T11:49:42Z
  • Completed: 2026-09-17T11:58:36Z
  • Tasks: 2
  • Files modified: 7 (app repo) plus this SUMMARY

Accomplishments

  • Testcontainers Postgres (postgres:16-alpine) plus pgx database/sql backs a tiny synthetic_items table for the integration suite.
  • TestParitySynthetic replays testdata/synthetic-seed.yaml (POST) and synthetic-read.yaml (GET + synthetic-item SQL hook); unknown hooks fail; a mutated row fails at $[0].name.
  • newTarget / seedHooks is the Phase 3 seam: swap in the real app handler, mark GET genres ported, keep a temporary genres hook until POST genres lands.
  • TestParityCorpus validates all 154 manifest fixtures as selectable pending subtests and never counts them as a Go pass. A cloned ported locale fixture against the synthetic handler fails with status 200 vs 404.

Task Commits

Each task was committed atomically (app repo fonoteka.go):

  1. Task 1: Replay a synthetic write/read flow against Postgres - e0ab93c (feat)
  2. Task 2: Expose the full corpus as honest selectable subtests - ecec761 (feat)

Plan metadata: this SUMMARY commit

Files Created/Modified

  • ../fonoteka.go/go.mod / go.sum — test-only testcontainers, postgres module, pgx v5.10.0; local replace to summercms
  • ../fonoteka.go/parity/parity_test.go — newTarget, seedHooks, TestParityCorpus
  • ../fonoteka.go/parity/synthetic_test.go — Postgres lifecycle, synthetic handler, TestParitySynthetic
  • ../fonoteka.go/parity/testdata/synthetic-seed.yaml — HTTP write fixture with captured id
  • ../fonoteka.go/parity/testdata/synthetic-read.yaml — list fixture with seed_hook: synthetic-item
  • ../fonoteka.go/parity/README.md — in-process go test ./parity commands and Phase 3 hook notes

Decisions Made

  • Keep testcontainers/pgx out of framework production code (QA-03).
  • Fail the package (not skip) when Docker cannot start Postgres; -short is the only green skip.
  • Coverage totals come from the manifest so -run TestParityCorpus/<one-id> does not require sibling subtests to have incremented counters.
  • Phase 2 does not register a genres hook yet — only documents the name and the POST route that will replace it.

Deviations from Plan

Auto-fixed Issues

1. [Rule 3 - Blocking] slopcheck SLOP/SUS on local replace and transitives

  • Found during: Task 1 (dependency scan after go get)
  • Issue: slopcheck marked git.golem15.com/golem15/summercms as SLOP (unpublished replace) and several testcontainers transitives as SLOP/SUS. Direct requires are the RESEARCH.md VERIFIED set (testcontainers postgres module, pgx/stdlib).
  • Fix: Kept Go module resolution versions; did not add undeclared direct imports. Transitives stay indirect.
  • Files modified: ../fonoteka.go/go.mod, ../fonoteka.go/go.sum
  • Verification: slopcheck scan after tidy; git diff -- go.mod go.sum inspected before commit
  • Committed in: e0ab93c

2. [Rule 1 - Bug] parent coverage asserts broke -run of one corpus flow

  • Found during: Task 2 (go test -run TestParityCorpus/GET__...)
  • Issue: Parent TestParityCorpus asserted 154 pending after the loop, so selecting one subtest failed with pending 0.
  • Fix: Moved asserts into t.Run("coverage") and compute totals from the manifest, not from filtered subtest side effects. Sanitized names use three underscores for /_fonoteka paths.
  • Files modified: ../fonoteka.go/parity/parity_test.go, ../fonoteka.go/parity/README.md
  • Verification: -run TestParityCorpus/GET___fonoteka_api_v1_me_locale_jwt_locale passes; coverage prints recorded 154/154 passing 0 failing 0 unrecorded 0 pending 154
  • Committed in: ecec761

Total deviations: 2 auto-fixed (1 dependency-scan, 1 -run isolation) Impact on plan: Required for honest CI selection and a legitimate local module replace. No PHP/Nuxt/MCP source changes. No framework production deps.

Issues Encountered

  • TDD RED was observed without a RED commit (TDD_MODE=false): stub NotFoundHandler failed capture at $.id (create-item), then the SQL-backed handler made the suite green in the Task 1 commit.
  • slopcheck age heuristics fire on well-known transitives (Azure/go-ansiterm, magiconair/properties, power-devops/perfstat); treat RESEARCH.md Package Legitimacy Audit as the gate for direct requires.

User Setup Required

None - no external service configuration required. Local Docker is required for go test ./parity without -short.

Next Phase Readiness

Ready for 02-05 (contract, security and integration tests). Phase 3 can replace newTarget with the real app handler, mark GET genres ported, and register a temporary genres seed hook until POST genres is ported.

Verification

  • Task 1: go test ./parity -run TestParitySynthetic starts Postgres and passes write/read, unknown hook, $[0].name mismatch
  • Task 2: recorded 154/154 passing 0 failing 0 unrecorded 0 pending 154; -run selects one flow; ported-mismatch reports status 200 vs 404
  • Plan: go vet ./... and go test ./... exit 0 in both summercms.go and fonoteka.go
  • Docker unavailable: TestMain exits 1 (no skip)

Self-Check: PASSED

  • Key files exist on disk
  • git -C ../fonoteka.go log --grep=02-04 returns Task 1 and Task 2 commits
  • Task acceptance criteria re-run and pass
  • Plan verification commands pass

Phase: 02-api-parity-harness-bootstrap Completed: 2026-09-17