D-04: A developer can invoke `summer parity:record` and `summer parity:replay` through bonfire against one HTTP route.
D-05 D-06: The recorded versioned YAML flow contains an ordered request/response step with verbatim JSON body text.
D-12 D-13: Replaying that fixture against an arbitrary httptest HTTP backend succeeds or reports an exact structural JSON path or raw byte mismatch.
path
provides
tide/flow.go
Framework-owned, versioned flow and step contracts
path
provides
tide/fixture.go
Validated YAML load and atomic save
path
provides
tide/record.go
HTTP recording engine
path
provides
tide/replay.go
Backend-independent replay engine
path
provides
cmd/summer/parity.go
Bonfire parity commands
from
to
via
cmd/summer/main.go
cmd/summer/parity.go
toolCommands registration
from
to
via
cmd/summer/parity.go
tide/record.go
RecordFlow API
from
to
via
cmd/summer/parity.go
tide/replay.go
ReplayFlow API
**As a** port developer, **I want to** record one HTTP route and replay it against another backend, **so that** I can see the first parity result before porting an endpoint.
Purpose: Establish a complete fixture-to-diff path on the Phase 1 command kernel.
Output: Generic tide flow schema, fixture IO, one-route recorder/replayer, and two working summer parity:* commands.
@.planning/ROADMAP.md
@.planning/REQUIREMENTS.md
@.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-PATTERNS.md
@bonfire/command.go
@cmd/summer/main.go
`bonfire.Command` is a value with `Name`, `Description`, `Flags []bonfire.Flag`, `Args []bonfire.Arg`, and `Run(context.Context, bonfire.Input, bonfire.Output) error`. Flags are strings; `bonfire.Input.Flag(name)` retrieves them. `cmd/summer/main.go` assembles values in `toolCommands()` and `main()` maps command errors to exit status 1.
Define the public tide contract here for later plans: Flow{Version, Name, Description, SeedHook, Steps}, Step{ID, RouteID, Request, Response, Capture, Normalize, Headers}, Request{Method, Path, Query, Headers, Body} where Query preserves the raw query string, and Response{Status, Headers, Body, BodyFile, SHA256}. Use LoadFlow, SaveFlow, RecordFlow, ReplayFlow, and a Result carrying per-step differences. Keep transport/target, fixture filesystem and output injected; neither tide nor its tests import Fonoteka.
Task 1: Record and replay one route through the summer CLI
go.mod, go.sum, tide/flow.go, tide/fixture.go, tide/record.go, tide/replay.go, tide/diff.go, tide/testdata/one-route-spec.yaml, tide/roundtrip_test.go, cmd/summer/main.go, cmd/summer/parity.go, cmd/summer/parity_test.go
bonfire/command.go, bonfire/root.go, cmd/summer/main.go, cmd/summer/main_test.go, .planning/phases/02-api-parity-harness-bootstrap/02-CONTEXT.md, .planning/phases/02-api-parity-harness-bootstrap/02-RESEARCH.md
A local httptest server answers GET /sample with JSON. `parity:record --spec one-route-spec.yaml --target URL --output PATH` produces one valid flow; `parity:replay --fixtures PATH --target URL` succeeds; a changed response fails with `$.data` and expected/actual values. A non-JSON response changed by one byte reports the byte offset.
In one committing task, write a version-1 one-step YAML request spec and black-box tests through `bonfire.NewRoot("summer", toolCommands(), writer)` plus `httptest.Server` (D-04, D-05, D-06). Run the focused tests once to observe RED without committing, then implement enough `tide.Flow`, validated YAML load/save, HTTP record/replay and `bonfire` command registration to make the complete round trip GREEN. The fixture keeps request/response body bytes as YAML literal block scalars, records status and Content-Type, and saves atomically; changed JSON scalar or non-JSON byte returns a nonzero CLI error with expected/actual diagnostics. Include both original and changed handlers in the tests. Before adding direct goccy/go-yaml to `go.mod`, review RESEARCH.md Package Legitimacy Audit and run `/home/jin/.local/bin/slopcheck scan go.mod`; after module resolution inspect `git diff -- go.mod go.sum` and scan again. Keep the package generic, preserve `toolchain go1.27.0`, and commit only after full root vet/test is green. Plan 05 expands behavior coverage.
/home/jin/.local/bin/slopcheck scan go.mod && go vet ./... && go test ./... && go test ./tide ./cmd/summer -run 'TestParityRoundTrip|TestParityCommands' -count=1
- RED is observed before implementation within the task, then all tests are GREEN before its single commit.
- A real one-route fixture records and replays through `summer` against httptest; changed JSON or bytes report a mismatch.
- Full root `go vet ./...` and `go test ./...` pass at commit; tests use temp fixtures and injected writers.
A developer can already record and replay one HTTP route through the CLI after this task commits.
Task 2: Make the one-route record/replay path work
go.mod, go.sum, tide/flow.go, tide/fixture.go, tide/record.go, tide/replay.go, tide/diff.go, cmd/summer/main.go, cmd/summer/parity.go, tide/roundtrip_test.go, cmd/summer/parity_test.go
go.mod, bonfire/command.go, bonfire/root.go, cmd/summer/main.go, tide/testdata/one-route-spec.yaml, tide/roundtrip_test.go, cmd/summer/parity_test.go, .planning/phases/02-api-parity-harness-bootstrap/02-PATTERNS.md
Refine the working Plan 01 Task 1 path into the full public `tide` contract above: strict `version: 1` goccy/go-yaml decode rejects unknown fields, empty flow names, unsafe paths and duplicate step ids (D-05, D-06); atomic save syncs before rename. Inject `http.Client` and context, bound request/response body reads, and reject truncation before committing a fixture. In `diff.go`, decode JSON with `UseNumber`, recursively compare exact key sets, array lengths, scalar values and token types while ignoring object key order; report `$.path` with expected and actual values. For non-JSON content types, compare bytes and report offset plus printable escaped bytes. Keep `parity:record` and `parity:replay` in `toolCommands()` with string flags `--spec`, `--target`, `--output`, `--fixtures`; errors return through bonfire so main exits nonzero (D-04, D-12, D-13). Reinspect the `go.mod`/`go.sum` diff and rerun slopcheck if dependency metadata changes. Do not add an app route, PHP-specific field or standalone CLI.
go vet ./... && go test ./... && go test ./tide ./cmd/summer -run 'TestParityRoundTrip|TestParityCommands' -count=1
- `parity:record` writes one replayable YAML flow and `parity:replay` accepts it.
- Identical JSON with changed object key order passes; missing keys and changed string/number types fail at named paths.
- Non-JSON changes fail with byte diagnostics; malformed YAML and oversized bodies fail before committing a fixture.
- Root `go vet ./...` and `go test ./...` exit 0.
A developer can record and replay one fixture using the installed summer tool.
<threat_model>
Trust Boundaries
Boundary
Description
YAML spec and HTTP target → local process
Untrusted paths, headers and bodies become outbound requests and fixture files.
Apply RESEARCH.md Package Legitimacy Audit before module resolution and run slopcheck; block any package marked ASSUMED/SUS pending human verification.
</threat_model>
Run the one-route CLI smoke against httptest, then root `go vet ./...` and `go test ./...`. Confirm the written YAML can be loaded and replayed without changing the input spec.
<success_criteria>
One route fixture records and replays through bonfire, a modified JSON field produces a structural path diff, and modified non-JSON bytes produce a byte diff.
</success_criteria>
Create `.planning/phases/02-api-parity-harness-bootstrap/02-01-SUMMARY.md` after completion.