Files
summercms/.planning/phases/02-api-parity-harness-bootstrap/02-05-SUMMARY.md
2026-09-17 14:15:37 +02:00

8.7 KiB
Raw Blame History

phase: 02-api-parity-harness-bootstrap plan: 05 subsystem: testing tags: [parity, contract-tests, race, testcontainers, check-phase2, mariadb] requires: - phase: 02-api-parity-harness-bootstrap provides: tide record/replay/proxy, capture rules, named vars, manifest --next-batch, summer parity:* - phase: 02-api-parity-harness-bootstrap provides: Isolated PHP on 127.0.0.1:8423 with a parity-named SQLite DB - phase: 02-api-parity-harness-bootstrap provides: Recorded API seed plus 154 live PHP route fixtures - phase: 02-api-parity-harness-bootstrap provides: App-owned testcontainers Postgres lifecycle for go test ./parity - phase: 02-api-parity-harness-bootstrap provides: TestParityCorpus: 154 recorded/pending selectable subtests, zero Go passes provides: - Public-API contract tests for every named QA-02 parity class - Proxy/CLI security regressions and app pending-vs-passing contracts - Repeatable scripts/check-phase2.sh --fresh-php gate with disposable MariaDB - Measured 02-VALIDATION.md evidence with nyquist_compliant true affects: [03] tech-stack: added: [] patterns: - Contract tests go through RecordFlow/ReplayFlow/manifest public APIs, not private helpers - check-phase2.sh owns PHP_PARITY_TARGET=http://127.0.0.1:8423 and refuses caller overrides - Fresh PHP gate uses unique fonoteka_parity_* MariaDB, artisan preflight tables=0, then winter:up plus oauth-client key-files: created: - tide/diff_contract_test.go - tide/flow_contract_test.go - tide/manifest_contract_test.go - tide/proxy_security_test.go - cmd/summer/parity_contract_test.go - ../fonoteka.go/parity/parity_contract_test.go - scripts/check-phase2.sh modified: - .planning/phases/02-api-parity-harness-bootstrap/02-VALIDATION.md key-decisions: - "Fresh PHP self-replay uses disposable MariaDB fonoteka_parity_* plus process-local hex credentials, never the developer DB or caller-supplied PHP_PARITY_TARGET" - "Client flows run on a second winter:up after dropping tables so they are not replayed after the mutating 154-route suite" - "Capture-by-reference mismatch is a two-step {{share:item}} flow with a live token change on the second /show" patterns-established: - "Pattern: Phase 2 sign-off is one script — scripts/check-phase2.sh --fresh-php — and Phase 1 remains scripts/check-phase1.sh" - "Pattern: MariaDB readiness is mariadb SELECT 1; passwords are token_hex so -p never sees a leading dash" - "Pattern: pkce.vars merge from /tmp/summercms-parity/pkce.vars before mcp-oauth replay" requirements-completed: [QA-01, QA-02, QA-03] duration: 15min completed: 2026-09-17

Phase 2 Plan 5: Complete contract, security and integration tests Summary

Public-API negative tests lock every named parity class, proxy/CLI/pending-state contracts fail closed, and scripts/check-phase2.sh --fresh-php proves 154/154 PHP self-replay plus testcontainers Postgres

Performance

  • Duration: 15 min
  • Started: 2026-09-17T12:00:43Z
  • Completed: 2026-09-17T12:15:30Z
  • Tasks: 3
  • Files modified: 8 (7 created, 1 validation doc) plus this SUMMARY

Accomplishments

  • Table-driven TestDiffContract / TestFlowContract / TestManifestContract cover null vs [], Carbon +00:00 vs Z, null vs absent dates, tri-state bools, envelope/conditional keys, money string vs number, integer ids, exact slug, capture-by-reference, missing variables, and per-step normalize disable — each failure names a JSON path.
  • TestProxySecurity and TestParityCommandContract pin loopback-only proxy, body caps, traversal, scrub of JWT/inv_/OAuth secrets, and nonzero CLI errors without printing secrets.
  • App TestParityContract keeps 154 routes recorded/pending with zero Go passes, unknown seed hooks fail, and synthetic SQL still uses testcontainers Postgres.
  • scripts/check-phase2.sh --fresh-php is the repeatable gate: root and app vet/test/race, TestParitySynthetic Postgres, corpus --require-recorded --require-clients --check-secrets, CLI smoke, disposable MariaDB + artisan bootstrap + 154-route and client-flow PHP self-replay.

Task Commits

Each task was committed atomically:

  1. Task 1: Lock down every response parity class with negative tests - 59b5276 (test, summercms.go)
  2. Task 2: Cover proxy, scrub, CLI and Go pending-state boundaries - 5ed920b (test, summercms.go) and d93392d (test, fonoteka.go)
  3. Task 3: Run and document the repeatable phase gate - a296e98 (feat), 066c3d3 (fix), 84a5f00 (docs VALIDATION)

Plan metadata: this SUMMARY commit

Files Created/Modified

  • tide/diff_contract_test.go — QA-02 parity-class mutations with path-level diffs
  • tide/flow_contract_test.go — Record/Replay continuation, capture-by-reference, headers/binary
  • tide/manifest_contract_test.go — coverage reports, duplicate/missing ids, 154-route snapshot
  • tide/proxy_security_test.go — loopback bind/upstream, caps, scrub, traversal, atomic write
  • cmd/summer/parity_contract_test.go — CLI discovery, error exit, unclassified JWT with --vars
  • ../fonoteka.go/parity/parity_contract_test.go — pending ≠ passing, Postgres, unknown hooks
  • scripts/check-phase2.sh — root/app vet/test/race, corpus, CLI smoke, --fresh-php MariaDB/PHP
  • .planning/phases/02-api-parity-harness-bootstrap/02-VALIDATION.md — measured evidence, nyquist_compliant: true

Decisions Made

  • Keep MariaDB for --fresh-php (plan), not the 02-03 SQLite file; uniqueness is fonoteka_parity_<run-id> on an ephemeral loopback port.
  • Hex-only process credentials so mysql/mariadb -p cannot treat a leading - as a flag.
  • Client OAuth replay still merges /tmp/summercms-parity/pkce.vars; client_secret is redacted from gate logs.
  • Do not re-record PHP and do not implement Fonoteka Go API endpoints in this plan.

Deviations from Plan

Auto-fixed Issues

1. [Rule 1 - Bug] MariaDB urlsafe passwords broke -p and readiness

  • Found during: Task 3 (bash scripts/check-phase2.sh --fresh-php)
  • Issue: token_urlsafe passwords could start with -, so mariadb -p$PASS parsed them as flags. Container also needed a real SQL ping, not only docker inspect.
  • Fix: Switch to token_hex credentials and wait on mariadb ... -e 'SELECT 1'.
  • Files modified: scripts/check-phase2.sh
  • Verification: Second --fresh-php run exited 0 in 116s with phase2 check passed
  • Committed in: 066c3d3

Total deviations: 1 auto-fixed (1 blocking MariaDB readiness) Impact on plan: Required for a true empty-DB PHP self-replay. No PHP/Nuxt/MCP source changes. No Go API endpoints.

Issues Encountered

  • First --fresh-php attempt also found leftover php artisan serve on 8423 (pid 3289319); the process was killed so the gate could bind. Not a plan change.
  • TestFlowContract/unknown_capture_source needed OpenStore so CaptureStep runs; a nil store skipped capture and falsely passed.
  • Unclassified JWT CLI record succeeded until --vars was passed so ScrubStep ran. Both were fixed before the Task 1/2 commits.
  • PHP_PARITY_TARGET=http://example.com bash scripts/check-phase2.sh --fresh-php exits 1 with refuse: caller-supplied PHP_PARITY_TARGET is not permitted.

User Setup Required

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

Next Phase Readiness

Phase 2 complete. Ready for Phase 3 (first vertical slice: GET /_fonoteka/api/v1/genres) to swap newTarget for the real app handler, mark that route ported, and keep PHP fixtures as the acceptance test.

Verification

  • Task 1: go test ./tide -run 'TestFlowContract|TestDiffContract|TestManifestContract' -count=1 pass
  • Task 2: go test ./tide ./cmd/summer -run 'TestProxySecurity|TestParityCommandContract' pass; app go test ./parity -run 'TestParitySynthetic|TestParityCorpus|TestParityContract' -count=1 4.888s (Postgres started)
  • Task 3: bash scripts/check-phase2.sh --fresh-php 116s, phase2 check passed; corpus recorded 154/154; PHP self-replay passing 154 failing 0 unrecorded 0; seed, nuxt-browse, mcp-tools, mcp-oauth matched
  • Root and app go vet ./..., go test ./..., go test -race ./... green
  • scripts/check-phase1.sh still present; PHP_PARITY_TARGET override refused

Self-Check: PASSED

  • Key files exist on disk
  • git log --grep=02-05 returns Task 1–3 commits in summercms.go; fonoteka.go has d93392d
  • Task acceptance criteria re-run and pass
  • Plan verification command bash scripts/check-phase2.sh --fresh-php passed
  • 02-VALIDATION.md records measured evidence and nyquist_compliant: true

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