Tasks completed: 2/2 - Record and replay one route through the summer CLI - Lock the one-route tide record and replay contract SUMMARY: .planning/phases/02-api-parity-harness-bootstrap/02-01-SUMMARY.md Co-authored-by: Cursor <cursoragent@cursor.com>
163 lines
7.1 KiB
Markdown
163 lines
7.1 KiB
Markdown
---
|
|
phase: 02-api-parity-harness-bootstrap
|
|
plan: 01
|
|
subsystem: testing
|
|
tags: [tide, parity, yaml, httptest, bonfire, goccy, json-diff]
|
|
|
|
requires:
|
|
- phase: 01-framework-kernel-foundation
|
|
provides: bonfire.Command kernel and cmd/summer toolCommands()
|
|
provides:
|
|
- Version-1 tide Flow/Step request/response contracts
|
|
- Validated YAML load and atomic fixture save
|
|
- HTTP RecordFlow/ReplayFlow against an injected target
|
|
- summer parity:record and parity:replay commands
|
|
affects: [02-02, 02-03, 02-04, 02-05]
|
|
|
|
tech-stack:
|
|
added:
|
|
- github.com/goccy/go-yaml v1.19.2
|
|
patterns:
|
|
- Fixture bodies are YAML literal block scalars; JSON compares structurally with UseNumber
|
|
- Record/replay inject http.Client, context, target URL and a body size cap
|
|
- Bonfire string flags --spec --target --output --fixtures; errors exit through cobra
|
|
|
|
key-files:
|
|
created:
|
|
- 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/parity.go
|
|
- cmd/summer/parity_test.go
|
|
modified:
|
|
- cmd/summer/main.go
|
|
- go.mod
|
|
- go.sum
|
|
|
|
key-decisions:
|
|
- "tide is the framework-owned parity library; it does not import Fonoteka"
|
|
- "goccy/go-yaml v1.19.2 decodes fixtures with DisallowUnknownField; save uses a dedicated encoder so literal bodies keep nested indent"
|
|
- "JSON diffs ignore object key order and fail on missing keys or token-type changes at $.path"
|
|
- "Non-JSON bodies compare raw bytes and report offset plus printable escaped windows"
|
|
- "toolchain go1.27.0 is restored after go mod tidy drops it"
|
|
|
|
patterns-established:
|
|
- "Pattern: CLI tests drive bonfire.NewRoot with an injected writer and httptest.Server, never a real TTY"
|
|
- "Pattern: SaveFlow writes a temp file, Syncs, then rename; RecordFlow errors never create the destination"
|
|
|
|
requirements-completed: [QA-01, QA-02, QA-03]
|
|
|
|
duration: 7min
|
|
completed: 2026-09-17
|
|
---
|
|
|
|
# Phase 2 Plan 1: Record and Replay One Fixture Summary
|
|
|
|
**A developer can record GET /sample through `summer parity:record` and replay it with `summer parity:replay` against httptest, with JSON path diffs at `$.data` and non-JSON byte-offset diffs**
|
|
|
|
## Performance
|
|
|
|
- **Duration:** 7 min
|
|
- **Started:** 2026-09-17T10:14:10Z
|
|
- **Completed:** 2026-09-17T10:21:51Z
|
|
- **Tasks:** 2
|
|
- **Files modified:** 12
|
|
|
|
## Accomplishments
|
|
|
|
- Generic `tide` package owns version-1 Flow/Step contracts, validated YAML IO, HTTP record/replay and structural JSON/byte diffs
|
|
- `parity:record` and `parity:replay` register on the Phase 1 bonfire kernel with string flags `--spec`, `--target`, `--output`, `--fixtures`
|
|
- One-route testdata spec records and replays against httptest; changed JSON or bytes fail the CLI with expected/actual diagnostics
|
|
|
|
## Task Commits
|
|
|
|
Each task was committed atomically:
|
|
|
|
1. **Task 1: Record and replay one route through the summer CLI** - `f6e1b89` (feat)
|
|
2. **Task 2: Make the one-route record/replay path work** - `f669d05` (feat)
|
|
|
|
**Plan metadata:** pending `docs(02-01)` commit
|
|
|
|
_Note: TDD RED was observed as compile/command discovery failure inside Task 1 and was not committed separately, per the plan's single-green-commit instruction._
|
|
|
|
## Files Created/Modified
|
|
|
|
- `tide/flow.go` - Flow/Step/Request/Response types, Result, MismatchError, validation
|
|
- `tide/fixture.go` - LoadFlow/ParseFlow/SaveFlow with unknown-field rejection and atomic sync+rename
|
|
- `tide/record.go` - RecordFlow with injected client, context and bounded bodies
|
|
- `tide/replay.go` - ReplayFlow against an arbitrary HTTP target
|
|
- `tide/diff.go` - UseNumber JSON compare and non-JSON byte-offset diffs
|
|
- `tide/testdata/one-route-spec.yaml` - version-1 GET /sample request spec
|
|
- `tide/roundtrip_test.go` - TestParityRoundTrip library round trip and contract cases
|
|
- `cmd/summer/parity.go` - parity:record and parity:replay commands
|
|
- `cmd/summer/parity_test.go` - TestParityCommands through bonfire.NewRoot
|
|
- `cmd/summer/main.go` - registers the parity commands on toolCommands()
|
|
- `go.mod` / `go.sum` - direct github.com/goccy/go-yaml v1.19.2, toolchain go1.27.0 kept
|
|
|
|
## Decisions Made
|
|
|
|
- Named the harness library `tide` as allowed by CONTEXT.md discretion
|
|
- Decode with goccy; encode fixtures with a small dedicated writer so `body: |-` content is indented under nested mappings (goccy BytesMarshaler dropped indent)
|
|
- Compare JSON structurally (key sets, array lengths, scalars, json.Number token types) and ignore object key order
|
|
- Inject `http.Client`, context and MaxBody; default cap is 8 MiB; truncation fails before SaveFlow
|
|
- Keep the package generic: no Fonoteka route names, PHP fields, or standalone CLI
|
|
|
|
## Deviations from Plan
|
|
|
|
### Auto-fixed Issues
|
|
|
|
**1. [Rule 2 - Missing Critical] Restored toolchain go1.27.0 after go get/tidy dropped it**
|
|
- **Found during:** Task 1 (module resolution)
|
|
- **Issue:** `go get github.com/goccy/go-yaml@v1.19.2` and `go mod tidy` removed the `toolchain go1.27.0` directive the plan requires
|
|
- **Fix:** Re-inserted `toolchain go1.27.0` in go.mod after tidy
|
|
- **Files modified:** go.mod
|
|
- **Verification:** `grep toolchain go.mod` shows `toolchain go1.27.0`; go vet/test pass
|
|
- **Committed in:** f6e1b89 (Task 1 commit)
|
|
|
|
**2. [Rule 1 - Bug] Dedicated YAML encoder for literal nested bodies**
|
|
- **Found during:** Task 1 (GREEN of SaveFlow)
|
|
- **Issue:** goccy BytesMarshaler parsed `|-` scalars but re-emitted content without nested indent, so LoadFlow failed with `unexpected map key`
|
|
- **Fix:** SaveFlow writes version-1 YAML with correctly indented block scalars; LoadFlow still uses goccy with DisallowUnknownField
|
|
- **Files modified:** tide/fixture.go
|
|
- **Verification:** TestParityRoundTrip records YAML containing `body: |-` and reloads it
|
|
- **Committed in:** f6e1b89 (Task 1 commit)
|
|
|
|
---
|
|
|
|
**Total deviations:** 2 auto-fixed (1 missing critical, 1 bug)
|
|
**Impact on plan:** Required for the pinned toolchain and for round-tripping recorded JSON bodies. No scope creep.
|
|
|
|
## Issues Encountered
|
|
|
|
- slopcheck on the updated go.mod reported goccy as OK. Pre-existing SUS findings on `golang.org/x/term` and `golang.org/x/sys` were unchanged and not newly added
|
|
- QA-01/QA-02/QA-03 remain phase-level: this plan delivers the one-route CLI path, not the 154-route corpus, normalizer classes, or testcontainers. Frontmatter copies the plan's requirements list; they should not be treated as milestone-complete
|
|
|
|
## User Setup Required
|
|
|
|
None - no external service configuration required.
|
|
|
|
## Next Phase Readiness
|
|
|
|
Ready for 02-02-PLAN.md (proxy sessions and manifest-driven record with strict diffs). Public APIs: `LoadFlow`, `SaveFlow`, `RecordFlow`, `ReplayFlow`, `Flow`, `Result`.
|
|
|
|
## Verification
|
|
|
|
- RED observed: `go test ./tide ./cmd/summer -run 'TestParityRoundTrip|TestParityCommands'` failed with undefined LoadFlow/RecordFlow and missing `parity:record` before implementation
|
|
- GREEN: same focused tests pass; `go vet ./...` and `go test ./...` exit 0
|
|
- slopcheck: goccy VERIFIED/OK; toolchain pin preserved
|
|
|
|
## Self-Check: PASSED
|
|
|
|
- [x] Key files exist on disk
|
|
- [x] `git log --grep=02-01` returns Task 1 and Task 2 commits
|
|
- [x] Task acceptance criteria re-run and pass
|
|
- [x] Plan verification commands pass
|
|
|
|
---
|
|
*Phase: 02-api-parity-harness-bootstrap*
|
|
*Completed: 2026-09-17*
|