Files
summercms/.planning/phases/02-api-parity-harness-bootstrap/02-05-PLAN.md
2026-09-17 01:57:41 +02:00

14 KiB
Raw Blame History

phase, plan, type, wave, depends_on, files_modified, autonomous, requirements, must_haves
phase plan type wave depends_on files_modified autonomous requirements must_haves
02-api-parity-harness-bootstrap 05 execute 5
02-01
02-02
02-03
02-04
tide/flow_contract_test.go
tide/diff_contract_test.go
tide/proxy_security_test.go
tide/manifest_contract_test.go
cmd/summer/parity_contract_test.go
../fonoteka.go/parity/parity_contract_test.go
scripts/check-phase2.sh
.planning/phases/02-api-parity-harness-bootstrap/02-VALIDATION.md
true
QA-01
QA-02
QA-03
truths artifacts key_links
QA-01: A source-to-corpus audit proves 154/154 PHP routes have fixtures and named real Nuxt/MCP sessions exist.
QA-02: Negative contract tests detect nil versus [], Carbon +00:00 versus Z, null versus absent dates, tri-state booleans, envelope/conditional keys and string versus number money.
QA-03: Both Go modules pass vet/test/race, and the app integration suite actually starts testcontainers Postgres.
D-07 D-16: Security and continuation tests prove secrets never persist and failures produce full path-level and coverage reports.
path provides
tide/diff_contract_test.go Complete parity-class negative tests
path provides
tide/proxy_security_test.go Loopback, bounds, scrub and traversal regression tests
path provides
../fonoteka.go/parity/parity_contract_test.go Pending/ported and SQL-hook integration assertions
path provides
scripts/check-phase2.sh Repeatable root/app vet/test/race and corpus audit gate
path provides
.planning/phases/02-api-parity-harness-bootstrap/02-VALIDATION.md Measured phase verification evidence
from to via
scripts/check-phase2.sh ../fonoteka.go/parity/parity_test.go App module go test with Postgres
from to via
scripts/check-phase2.sh ../fonoteka.go/parity/check_corpus.go Exact PHP route and credential audit
from to via
tide/diff_contract_test.go tide/diff.go Behavioral negative cases and path diagnostics
**As a** port developer, **I want to** trust the parity corpus and its failure signals, **so that** future endpoint work cannot pass by masking a response difference or skipping an unported route.

Purpose: Finish dedicated unit and integration coverage after all feature slices exist, as required by project guidance. Output: Contract tests, security regression tests, cross-module phase gate and validation evidence.

<execution_context> @/home/jin/.codex/get-shit-done/workflows/execute-plan.md @/home/jin/.codex/get-shit-done/templates/summary.md </execution_context>

@.planning/phases/02-api-parity-harness-bootstrap/02-CONTEXT.md @.planning/phases/02-api-parity-harness-bootstrap/02-RESEARCH.md @.planning/phases/02-api-parity-harness-bootstrap/02-VALIDATION.md @.planning/phases/02-api-parity-harness-bootstrap/02-01-SUMMARY.md @.planning/phases/02-api-parity-harness-bootstrap/02-02-SUMMARY.md @.planning/phases/02-api-parity-harness-bootstrap/02-03-SUMMARY.md @.planning/phases/02-api-parity-harness-bootstrap/02-04-SUMMARY.md @tide/flow.go @tide/diff.go @tide/normalize.go @tide/proxy.go @tide/manifest.go @../fonoteka.go/parity/parity_test.go @../fonoteka.go/parity/manifest.yaml Use the public `tide` Record/Replay/Manifest APIs and CLI values established in Plans 01–04. The root and sibling app are separate Go modules; `go test ./...` in one does not traverse the other. The app's `TestParitySynthetic` must run with a real testcontainers Postgres and `TestParityCorpus` must report all 154 PHP routes as recorded/pending until actual Go handlers are ported. Task 1: Lock down every response parity class with negative tests tide/flow_contract_test.go, tide/diff_contract_test.go, tide/manifest_contract_test.go tide/flow.go, tide/fixture.go, tide/diff.go, tide/normalize.go, tide/replay.go, tide/manifest.go, tide/report.go, .planning/research/PITFALLS.md, .planning/phases/02-api-parity-harness-bootstrap/02-CONTEXT.md Write table-driven public-behavior tests over `RecordFlow`, `ReplayFlow` and manifest reporting. Include one good baseline and individually mutated fixtures for `null` versus `[]` (including empty object), Carbon ISO-8601 `+00:00` versus `Z` and non-date text, date key present-null versus absent, `true`/`false`/`null`, top-level `{data,meta}` envelope and nested conditional-key presence, fixed-decimal money JSON string versus number, integer id versus string/fraction, exact slug, capture-by-reference mismatch, unknown/missing variable and per-step normalization disable (D-11, D-13, D-15). Assert each failure names a stable JSON path and expected/actual type/value; object key reorder must pass. Add status and allow-listed header cases for OAuth `Cache-Control`/`Pragma`, 401 `WWW-Authenticate`/protected-resource-metadata, CSV `Content-Disposition`, plus ignored Date/Server/request id. Add CSV/image exact-byte mismatch and safe binary sidecar digest/path cases. Add two-flow continuation cases: comparison failure allows later steps/flows; capture failure skips only its flow remainder (D-14, D-16). Do not write tests that merely assert private helper structure. go vet ./... && go test ./tide -run 'TestFlowContract|TestDiffContract|TestManifestContract' -count=1 && go test ./... - Every named QA-02 parity class has a passing baseline and at least one failing mutation with a path-level diagnostic. - Header, binary and flow-continuation cases exercise observable Record/Replay results. - Root vet/test remain green after the task commit. Formatting, types and missing-key distinctions cannot be silently normalized away. Task 2: Cover proxy, scrub, CLI and Go pending-state boundaries tide/proxy_security_test.go, cmd/summer/parity_contract_test.go, ../fonoteka.go/parity/parity_contract_test.go tide/proxy.go, tide/variables.go, tide/fixture.go, cmd/summer/parity.go, cmd/summer/main.go, ../fonoteka.go/parity/parity_test.go, ../fonoteka.go/parity/synthetic_test.go, ../fonoteka.go/parity/manifest.yaml, .planning/phases/02-api-parity-harness-bootstrap/02-VALIDATION.md Test fixed loopback proxy target, rejection of client-selected upstream/non-loopback bind, request and response size cap, cookie/redirect passthrough, separate concurrent sessions, atomic write on error, path traversal and binary sidecar digest (T-02-01). Test credential replacement in Authorization, cookie, query and JSON/form body; scan written YAML and CLI error text for JWT, `inv_`, client secret, OAuth code and `auth_token`, then test unknown credential rejection and missing placeholder failure (T-02-02). Run bonfire commands with injected writers and assert `parity:record`, `parity:proxy`, `parity:replay` discovery and nonzero error propagation. In app tests, verify 154 manifest ids match source, all remain pending in Phase 2, a deliberately marked `ported` failing route fails its subtest, unknown seed hooks fail, synthetic SQL read/write and hook are backed by testcontainers Postgres, and pending is never counted as passing (D-08, D-09, D-10, D-12, D-16). Keep Docker absence as an explicit failure in the integration gate; use `-short` only for a separately named fast loop if needed, never for the phase sign-off. go vet ./... && go test ./tide ./cmd/summer -run 'TestProxySecurity|TestParityCommandContract' -count=1 && (cd ../fonoteka.go && go vet ./... && go test ./parity -run 'TestParitySynthetic|TestParityCorpus|TestParityContract' -count=1) - Proxy and fixture security regressions fail under the named attack cases. - CLI errors produce nonzero exit status and do not print secrets. - App test runs real Postgres and reports 154 recorded/pending, zero Go-passing PHP routes. The harness cannot pass by leaking a credential, misrouting proxy traffic, or calling pending routes green. Task 3: Run and document the repeatable phase gate scripts/check-phase2.sh, .planning/phases/02-api-parity-harness-bootstrap/02-VALIDATION.md scripts/check-phase1.sh, .planning/phases/02-api-parity-harness-bootstrap/02-VALIDATION.md, ../fonoteka.go/parity/README.md, ../fonoteka.go/parity/manifest.yaml, .planning/phases/02-api-parity-harness-bootstrap/02-RESEARCH.md Create `scripts/check-phase2.sh` that checks root and `../fonoteka.go` separately with `go vet ./...`, `go test ./...`, `go test -race ./...`, an explicit `TestParitySynthetic` Postgres run, corpus validator `--require-recorded --require-clients --check-secrets`, and CLI synthetic record/replay smoke. In required `--fresh-php` mode, provision a temporary MariaDB container on an ephemeral loopback port with a unique `fonoteka_parity_` database and process-local credentials, never the PHP checkout's `.env` or developer DB. Before migrations, query the active PHP DB connection through artisan, assert it equals that unique name and has zero application tables; then run existing PHP migrations. Read `../fonoteka.go/parity/README.md` and execute its exact documented artisan admin-user bootstrap and `oauth-client` commands against this same verified disposable DB using the same process-local DB environment (D-03); fail if either command fails, and redact generated credentials from logs while passing them only through the private variable store. Start `php artisan serve --host=127.0.0.1 --port=8423` as a child with that DB env. The script itself sets the only permitted replay target `http://127.0.0.1:8423`; reject a caller-supplied `PHP_PARITY_TARGET` or non-loopback target, and use a trap to stop PHP and remove the disposable container. Replay the API seed, all 154 routes and both client flows against that fresh instance, requiring zero failures/unrecorded. Fail on missing Docker, failed DB identity/freshness check, either artisan bootstrap failure, missing route fixture/client flow or any nonzero command; do not skip. Record actual commands, test output summary, route totals, fresh DB preflight and PHP self-replay result in `02-VALIDATION.md` without credentials; mark `nyquist_compliant: true` only when all gates pass. Keep planning doc and code changes in separate commits per CLAUDE.md; preserve the Phase 1 gate. Confirm root and app vet/test were green at each prior implementation commit as QA-03 requires. bash scripts/check-phase2.sh --fresh-php - Both modules pass vet, test and race; the app test visibly starts testcontainers Postgres. - Corpus audit reports exactly 154 recorded routes, zero unrecorded, and Nuxt/MCP flow presence with no secrets. - Fresh PHP self-replay passes every fixture; validation file records command/evidence and only then sets `nyquist_compliant: true`. - The gate proves a unique empty `fonoteka_parity_*` DB before migrations and starts its own PHP child on `127.0.0.1:8423`; caller URL overrides are rejected. - The documented artisan admin-user and OAuth-client bootstrap both run successfully against that same DB before seed replay, with generated secrets absent from output. A single documented gate proves the full Phase 2 harness and corpus are ready for Phase 3.

<threat_model>

Trust Boundaries

Boundary Description
Malformed fixtures/proxy requests → public harness APIs Contract tests must prove fail-closed behavior.
CI → Docker and isolated PHP Integration gate must distinguish missing infrastructure from a passing test.

STRIDE Threat Register

Threat ID Category Severity Component Disposition Mitigation Plan
T-02-01 Spoofing/Denial of service high Proxy and fixture IO mitigate Regression tests for fixed loopback upstream, bounded bodies, path traversal and atomicity.
T-02-02 Information disclosure high Recorder and CLI output mitigate Scrub tests across headers/query/body/cookies and committed corpus scan.
T-02-03 Tampering high Normalizer and diff mitigate Mutation tests for token type, date shape, conditional keys, selected headers and sidecar digest.
T-02-04 Tampering high Route coverage gate mitigate Source-derived 154-id audit and pending/ported negative tests.
T-02-05 Denial of service/Data loss high Fresh PHP self-replay gate mitigate Provision unique disposable DB, assert active connection and empty schema, pin loopback PHP origin, clean up child and container.
T-02-06 Elevation of privilege high SQL seed hooks mitigate Unknown-hook rejection and parameterized SQL behavior tests.
</threat_model>
Run `bash scripts/check-phase2.sh --fresh-php`; the script provisions its own isolated PHP DB/server and executes self-replay. Treat an environmental block as an incomplete gate and record it; do not mark the phase compliant without the run.

<success_criteria> Both modules are vet/test/race green, all 154 PHP routes and real client flows are recorded and self-replay cleanly, Postgres integration executes, and every named parity class has a failing mutation test. </success_criteria>

Create `.planning/phases/02-api-parity-harness-bootstrap/02-05-SUMMARY.md` after completion.