Files
summercms/.planning/phases/02-api-parity-harness-bootstrap/02-DISCUSSION-LOG.md
2026-09-16 12:47:27 +02:00

9.5 KiB

Phase 2: API parity harness bootstrap - Discussion Log

Audit trail only. Do not use as input to planning, research, or execution agents. Decisions are captured in CONTEXT.md — this log preserves the alternatives considered.

Date: 2026-09-16 Phase: 02-api-parity-harness-bootstrap Areas discussed: Recording strategy, Fixture format and layout, Replay auth and data state, Diff strictness and reporting


Recording strategy

How should fixtures be captured from the PHP backend?

Option Description Selected
Both: proxy + scripted Recording reverse proxy in front of :8422 captures real Nuxt and MCP sessions; a manifest-driven runner fills coverage for all 154 routes ✓
Recording proxy only Point Nuxt and MCP at the proxy and record whatever they send
Scripted runner only A Go program issues each request from a manifest with seeded auth

User's choice: Both: proxy + scripted

Which PHP instance and dataset should recordings come from?

Option Description Selected
Local :8422 with a seeded parity dataset Deterministic dataset built on a fresh DB before recording ✓
Local :8422 with existing dev database Record against whatever is in the dev DB
Production plytarium.com (read-only routes) GET routes from the live site, writes locally

User's choice: Local :8422 with a seeded parity dataset

How should the seeded parity dataset be built on the PHP side?

Option Description Selected
Seed through the API itself Recorded setup flow calls the PHP API; artisan only for what the API cannot create ✓
A PHP seeder command in the fonoteka plugin fonoteka:parity-seed artisan command with fixed ids
A checked-in SQL dump Restore a hand-prepared dump before recording

User's choice: Seed through the API itself

What shape should the recorder tool take, given Phase 1's CLI kernel may not exist yet?

Option Description Selected
Standalone parity binary now, wrapped later cmd/parity on plain flag/cobra, exposed as summer parity:* after Phase 1
go test driven only Recording and replay as go test runs with env-var switches
Wait for Phase 1 and build summer parity:* directly Serialize Phase 2 after Phase 1; recorder is a bonfire command from day one ✓

User's choice: Wait for Phase 1 and build summer parity:* directly Notes: This makes Phase 2 depend on Phase 1 and drops the roadmap's "parallel with Phase 1" note; ROADMAP.md needs updating.


Fixture format and layout

How should recorded fixtures be organized on disk?

Option Description Selected
One file per flow, steps inside Ordered steps per flow; manifest runner emits one-step flows per route ✓
One file per request/response pair Every exchange its own file
One file per route with all cases 154 files each holding every case

User's choice: One file per flow, steps inside

What file format should a flow fixture use?

Option Description Selected
Custom YAML via goccy/go-yaml Small schema, human-editable, same YAML library as config and admin schemas ✓
Custom JSON Same schema as JSON
HAR files Browser-standard archive with a sidecar for rules

User's choice: Custom YAML via goccy/go-yaml

How should credentials and volatile headers be handled in stored fixtures?

Option Description Selected
Scrub to named placeholders at record time {{jwt:alice}}-style placeholders from a credential map; replay resolves them ✓
Store real values, gitignore the fixture directory Never commit fixtures
Strip auth entirely, re-add at replay from the manifest Manifest says which identity each step runs as

User's choice: Scrub to named placeholders at record time

Where should the fixture corpus and the Płytarium manifest live?

Option Description Selected
fonoteka.go/parity/ with fixtures beside the manifest manifest.yaml, fixtures/{nuxt,mcp,routes}, replay test; framework ships library + synthetic corpus ✓
fonoteka.go/plugins/fonoteka/testdata/parity/ Inside the fonoteka plugin module
A third repo for the corpus Shared by PHP and Go sides

User's choice: fonoteka.go/parity/ with fixtures beside the manifest


Replay auth and data state

How should the Go backend's database reach the same state the recording was made against?

Option Description Selected
Replay the recorded seed flow against Go first Same API-driven seed flow on both sides ✓
Direct Postgres seed from the fixture corpus Insert rows from a seed file
Hybrid: SQL seed now, API seed once writes exist Two mechanisms during the port

User's choice: Replay the recorded seed flow against Go first

When a replay needs state that no ported write endpoint can create yet, what fills the gap?

Option Description Selected
Per-flow Go seed hook, deleted once the write route lands Named hook registered by the app test, listed as temporary in the manifest ✓
Port the matching write endpoint in the same phase Phase 3 would grow beyond one route
Permanent SQL seed files per flow Second source of truth for state

User's choice: Per-flow Go seed hook, deleted once the write route lands

How does a replay obtain credentials to substitute for placeholders?

Option Description Selected
Capture rules on seed-flow steps JSON path from response into a variable store; same for ids, share tokens, OAuth codes ✓
Harness-level identity registry Harness logs identities in outside any flow
Mint tokens directly against the Go DB Sign JWTs and insert tokens in Postgres

User's choice: Capture rules on seed-flow steps

How is the Go backend hosted while fixtures replay against it?

Option Description Selected
Both: in-process httptest.Server in tests, any URL from the CLI Hermetic go test with testcontainers Postgres; summer parity:replay --target for any server including PHP as self-check ✓
In-process httptest.Server only Replay exists only as a Go test
External URL only Always target a running server

User's choice: Both: in-process httptest.Server in tests, any URL from the CLI


Diff strictness and reporting

What counts as a body mismatch for JSON responses?

Option Description Selected
Structural equality plus token-type checks Key sets, values and JSON token types; key order ignored ✓
Raw byte equality after canonicalization Sorted keys, fixed whitespace, compare bytes
Strict byte equality, key order included PHP key order becomes part of the contract

User's choice: Structural equality plus token-type checks

Which response headers should the diff compare?

Option Description Selected
Global allow-list plus per-route additions Status, Content-Type, pagination/CORS always; OAuth cache headers, WWW-Authenticate, Content-Disposition per route ✓
Status and Content-Type only Ignore all other headers
All headers except a deny-list Compare everything not on a volatile list

User's choice: Global allow-list plus per-route additions

How should nondeterministic values be normalized before the diff?

Option Description Selected
Global rules by field pattern plus per-step overrides Pattern-keyed normalizers with format assertions on masked fields; captured variables compare by reference ✓
Per-step ignore lists only Each step lists JSON paths to skip
Mask by value type at record time Recorder rewrites dates/ids/tokens into placeholders

User's choice: Global rules by field pattern plus per-step overrides

How should a parity run report its results?

Option Description Selected
Run everything, report per step, summarize per route Path-level diff per failing step; coverage table over 154 routes; flows as go test subtests ✓
Fail fast on first mismatch Stop at the first failing step
Report only, never fail JSON report, exit zero until cutover

User's choice: Run everything, report per step, summarize per route


Claude's Discretion

  • Harness library package name (summer-themed; tide suggested).
  • Expected-failure marking for unported routes so CI stays green on ported routes.
  • Fresh DB per flow vs one seeded DB per run (default: one per run, manifest-ordered flows).
  • Capturing the MCP OAuth PKCE flow through the proxy and into variables.
  • Binary response storage (base64 block vs sidecar file).
  • Proxy transport details (plain HTTP on localhost, cookie passthrough, buffered bodies).
  • Whether summer parity:record has an --update mode or writes to a new directory.

Deferred Ideas

  • ROADMAP.md dependency update for Phase 2 (now depends on Phase 1) via /gsd-phase edit 2.
  • Recording read-only routes against production as a late sanity check before cutover (Phase 15 may consider).
  • Reusing the harness for the keios.eu port when it starts.