Audit the Go HTTP client generator against the Go HTTP server for serialization, error handling, query parameter encoding, header handling, and unwrap consistency. Fix any inconsistencies found and add missing test coverage.

Purpose: The Go client is the primary reference implementation. It must serialize requests exactly as the server expects and deserialize responses exactly as the server produces. Any inconsistency here will propagate to all future language clients that model themselves after this one.

Output: A Go client generator that is verified consistent with the server, with expanded test coverage including unwrap variants.

<execution_context> @/Users/sebastienmelki/.claude/get-shit-done/workflows/execute-plan.md @/Users/sebastienmelki/.claude/get-shit-done/templates/summary.md </execution_context>

@.planning/PROJECT.md @.planning/ROADMAP.md @.planning/STATE.md @.planning/phases/03-existing-client-review/03-CONTEXT.md @.planning/phases/03-existing-client-review/03-RESEARCH.md @.planning/phases/03-existing-client-review/03-01-SUMMARY.md @internal/clientgen/generator.go @internal/clientgen/golden_test.go @internal/httpgen/generator.go Task 1: Add missing test proto coverage for Go client (unwrap + complex features) internal/clientgen/testdata/proto/unwrap.proto internal/clientgen/testdata/proto/complex_features.proto internal/clientgen/golden_test.go internal/clientgen/testdata/golden/unwrap_client.pb.go internal/clientgen/testdata/golden/complex_features_client.pb.go The Go client (clientgen) only has 3 symlinked test protos: backward_compat, http_verbs_comprehensive, query_params. It is MISSING:
  1. unwrap.proto -- All unwrap variants (map-value, root repeated, root map, combined). The httpgen has this and the tsclientgen has complex_features.proto which covers unwrap too.
  2. complex_features.proto -- Enums, optional fields, nested messages, all unwrap variants. The tsclientgen has this.

Add symlinks in internal/clientgen/testdata/proto/:

  • unwrap.proto -> ../../../httpgen/testdata/proto/unwrap.proto
  • complex_features.proto -> ../../../tsclientgen/testdata/proto/complex_features.proto

NOTE: The complex_features.proto file has go_package set to tsclientgen/testdata/generated. This is fine for golden file testing since the golden test just compares text output, not compiled Go. But verify the golden test handles different go_package values correctly. If not, create a clientgen-specific version with the correct go_package instead of symlinking.

Update internal/clientgen/golden_test.go to include the new protos in its test list. Read the existing test to understand the pattern -- it likely iterates over proto files in the testdata/proto directory. If it auto-discovers files, just adding the symlinks is sufficient. If it has a hardcoded list, add the new entries.

Generate initial golden files: UPDATE_GOLDEN=1 go test ./internal/clientgen/ -run TestExhaustiveGoldenFiles -count=1

Verify: go test ./internal/clientgen/ -count=1 Run go test ./internal/clientgen/ -count=1 -- all tests pass. Verify golden files exist: ls internal/clientgen/testdata/golden/unwrap_client.pb.go. Verify the generated unwrap client code handles all unwrap variants (root map, root repeated, map-value, combined). Go client has golden file test coverage for all unwrap variants and complex features (enums, optional, nested, maps). All clientgen tests pass.

Task 2: Audit and fix Go client consistency with server internal/clientgen/generator.go Systematically audit the Go client generator against the server for consistency. Check each of these areas and fix any issues found:

1. Query parameter encoding consistency Compare generateQueryParams in clientgen/generator.go with bindQueryParams in httpgen/generator.go:

  • For each scalar type (string, int32, int64, uint64, bool, float32, float64), verify that fmt.Sprint(req.Field) produces a string that the server's convertStringToFieldValue can parse back correctly.
  • Pay special attention to float/double: fmt.Sprint(1.5) produces 1.5 which strconv.ParseFloat accepts. Verify this.
  • For bool: client sends true/false via fmt.Sprint, server parses with strconv.ParseBool. These are compatible.
  • For int64/uint64: client sends numeric strings, server parses with strconv.ParseInt/strconv.ParseUint. Compatible.
  • Verify zero-value omission: client checks req.Field != 0 (or != "" for strings, != false for bool). This matches protojson's "omit default values" behavior.

2. Content-Type handling

  • Verify the client sets Content-Type header on all requests.
  • Verify the client handles response Content-Type correctly (uses request Content-Type for response parsing, matching server behavior from 03-02 fixes).
  • Check that both JSON and protobuf binary paths work.

3. Error handling consistency

  • Read handleErrorResponse in clientgen/generator.go. Verify it correctly deserializes ValidationError (400) and Error (other status codes) from the response.
  • Verify the error body structure matches what the server produces: ValidationError with violations array, Error with message field.
  • Verify status code mapping: 400 = ValidationError, other 4xx/5xx = Error.

4. Path parameter URL encoding

  • Verify the client uses url.PathEscape(fmt.Sprint(req.Field)) for all path parameters.
  • Verify this matches the server's expectation (server receives already-decoded path params from the HTTP router).

5. Header handling

  • Verify service-level headers are sent on every request.
  • Verify method-level headers are sent on specific requests.
  • Verify header names match exactly (case-sensitive comparison with what server validates).
  • Check the functional options API: WithXxxHeader(name, value), WithXxxCallHeader(name, value), etc. Verify naming is consistent and complete.

6. Response deserialization

  • For standard responses: verify unmarshalResponse uses protojson.Unmarshal for JSON and proto.Unmarshal for binary.
  • For unwrap responses: verify the client correctly handles custom JSON unmarshaling via the json.Unmarshaler interface.

For each inconsistency found, fix it in the generator code. After all fixes, update golden files.

IMPORTANT: If you find that the client is CORRECT and the server is WRONG (per protojson spec), note this but do NOT fix the server here -- server fixes are in plan 03-02. If the server was already fixed in 03-02, verify the client matches the fixed server behavior.

After all fixes, run make lint-fix to clean up formatting. Run UPDATE_GOLDEN=1 go test ./internal/clientgen/ -count=1 to update golden files after any fixes. Then go test ./internal/clientgen/ -count=1 to confirm all pass. Run make build to verify full project builds. Run make lint-fix for clean code. Go client generator is verified consistent with the server:

  • Query param encoding for all scalar types matches server parsing
  • Content-Type handling is bidirectionally consistent
  • Error deserialization matches server error serialization
  • Path params are correctly URL-encoded
  • Headers are sent consistently with server validation expectations
  • All inconsistencies found are fixed and captured in golden files
1. `go test ./internal/clientgen/ -count=1` passes 2. `make build` succeeds 3. Golden files include unwrap and complex feature coverage 4. No inconsistencies remain between Go client and server for any RPC in the exhaustive test proto

<success_criteria>

  • Go client has complete test coverage including all unwrap variants, enums, optional fields, nested messages
  • Every query param scalar type roundtrips correctly (client encodes, server parses)
  • Error handling matches server error format exactly
  • Header handling is consistent between client and server
  • All clientgen golden file tests pass </success_criteria>
After completion, create `.planning/phases/03-existing-client-review/03-03-SUMMARY.md`