Purpose: Ensure the "two capital sins" (breaking backward compat, cross-generator inconsistency) have not been committed. Programmatically verify Phase 4 success criteria.
Output: Expanded exhaustive test proto with all encoding combinations. Cross-generator consistency test that fails if any generator diverges.
<execution_context> @/Users/sebastienmelki/.claude/get-shit-done/workflows/execute-plan.md @/Users/sebastienmelki/.claude/get-shit-done/templates/summary.md </execution_context>
Test infrastructure
@internal/httpgen/exhaustive_golden_test.go @internal/tsclientgen/golden_test.go @internal/openapiv3/exhaustive_golden_test.go @internal/httpgen/testdata/exhaustive.proto
- Add int64 encoding test message:
// Int64 encoding test cases
message Int64EncodingExhaustive {
// Default (STRING per proto3 JSON spec)
int64 default_int64 = 1;
sint64 default_sint64 = 2;
sfixed64 default_sfixed64 = 3;
uint64 default_uint64 = 4;
fixed64 default_fixed64 = 5;
// Explicit STRING encoding
int64 string_int64 = 6 [(sebuf.http.int64_encoding) = INT64_ENCODING_STRING];
uint64 string_uint64 = 7 [(sebuf.http.int64_encoding) = INT64_ENCODING_STRING];
// NUMBER encoding (precision warning)
int64 number_int64 = 8 [(sebuf.http.int64_encoding) = INT64_ENCODING_NUMBER];
uint64 number_uint64 = 9 [(sebuf.http.int64_encoding) = INT64_ENCODING_NUMBER];
// Repeated with encoding
repeated int64 repeated_string_int64 = 10;
repeated int64 repeated_number_int64 = 11 [(sebuf.http.int64_encoding) = INT64_ENCODING_NUMBER];
// Map with int64 values
map<string, int64> map_string_int64 = 12;
// Note: Map values with NUMBER encoding - if supported
}- Add enum encoding test cases:
// Enum with custom JSON values
enum ExhaustiveStatus {
EXHAUSTIVE_STATUS_UNSPECIFIED = 0 [(sebuf.http.enum_value) = "unknown"];
EXHAUSTIVE_STATUS_ACTIVE = 1 [(sebuf.http.enum_value) = "active"];
EXHAUSTIVE_STATUS_PENDING = 2 [(sebuf.http.enum_value) = "pending"];
EXHAUSTIVE_STATUS_INACTIVE = 3; // No custom value - uses proto name
}
// Enum without custom values
enum ExhaustivePriority {
EXHAUSTIVE_PRIORITY_LOW = 0;
EXHAUSTIVE_PRIORITY_MEDIUM = 1;
EXHAUSTIVE_PRIORITY_HIGH = 2;
}
message EnumEncodingExhaustive {
// Custom values (STRING encoding by default)
ExhaustiveStatus status_default = 1;
ExhaustiveStatus status_string = 2 [(sebuf.http.enum_encoding) = ENUM_ENCODING_STRING];
// NUMBER encoding (uses numeric values)
ExhaustivePriority priority_number = 3 [(sebuf.http.enum_encoding) = ENUM_ENCODING_NUMBER];
ExhaustivePriority priority_string = 4 [(sebuf.http.enum_encoding) = ENUM_ENCODING_STRING];
// Default behavior (proto names as strings)
ExhaustivePriority priority_default = 5;
}- Add service endpoint to test encoding:
service EncodingService {
option (sebuf.http.service_config) = {
base_path: "/api/v1"
};
rpc TestInt64Encoding(Int64EncodingExhaustive) returns (Int64EncodingExhaustive) {
option (sebuf.http.config) = {
path: "/encoding/int64"
method: HTTP_METHOD_POST
};
}
rpc TestEnumEncoding(EnumEncodingExhaustive) returns (EnumEncodingExhaustive) {
option (sebuf.http.config) = {
path: "/encoding/enum"
method: HTTP_METHOD_POST
};
}
}Ensure exhaustive.proto still imports the annotations:
import "sebuf/http/annotations.proto";openapiv3 should symlink as well#
ls -la internal/openapiv3/testdata/exhaustive.proto
2. Run golden file generation for all generators:
```bash
UPDATE_GOLDEN=1 go test -run TestExhaustiveGoldenFiles ./internal/httpgen/...
UPDATE_GOLDEN=1 go test -run TestGoldenFiles ./internal/tsclientgen/...
UPDATE_GOLDEN=1 go test -run TestExhaustiveGoldenFiles ./internal/openapiv3/...
UPDATE_GOLDEN=1 go test -run TestGoldenFiles ./internal/clientgen/...
- Verify cross-generator consistency by inspection:
Go golden file should contain:
- MarshalJSON for Int64EncodingExhaustive (only if NUMBER fields present)
- MarshalJSON for ExhaustiveStatus enum (custom values)
- Lookup maps for ExhaustiveStatus (statusToJSON, statusFromJSON)
TypeScript golden should contain:
export type ExhaustiveStatus = "unknown" | "active" | "pending" | "EXHAUSTIVE_STATUS_INACTIVE";
export interface Int64EncodingExhaustive {
defaultInt64: string; // STRING (default)
numberInt64: number; // NUMBER
repeatedNumberInt64: number[];
}
export interface EnumEncodingExhaustive {
priorityNumber: number; // NUMBER encoding
priorityString: ExhaustivePriority;
}OpenAPI golden should contain:
ExhaustiveStatus:
type: string
enum: ["unknown", "active", "pending", "EXHAUSTIVE_STATUS_INACTIVE"]
Int64EncodingExhaustive:
properties:
defaultInt64:
type: string
format: int64
numberInt64:
type: integer
format: int64
description: "Warning: Values > 2^53 may lose precision in JavaScript"-
int64_encoding = STRING serializes as JSON strings in all generators
- Go: Check golden for
strconv.FormatIntor protojson default - TypeScript: Check for
stringtype in interface - OpenAPI: Check for
type: stringin schema
- Go: Check golden for
-
int64_encoding = NUMBER serializes as JSON numbers with precision warning
- Go: Check golden for MarshalJSON with direct int64 assignment
- Go: Check generation logs for warning message
- TypeScript: Check for
numbertype in interface - OpenAPI: Check for
type: integerwith warning description
-
enum_encoding = STRING serializes enum values as proto names
- Go: Check protojson default behavior preserved
- TypeScript: Check union type uses proto names
- OpenAPI: Check enum array uses proto names
-
enum_value annotations map to custom JSON strings
- Go: Check lookup maps with custom values
- TypeScript: Check union type uses custom values
- OpenAPI: Check enum array uses custom values
-
OpenAPI schemas accurately reflect configured encoding
- NUMBER int64: type=integer, format=int64
- STRING int64: type=string, format=int64
- NUMBER enum: type=integer with numeric enum
- Custom enum: type=string with custom string values
-
Cross-generator consistency
- All generators produce equivalent JSON for same input
- TypeScript types match what Go produces
- OpenAPI documents what Go produces
Run full test suite to confirm no regressions:
./scripts/run_tests.shLint check#
make lint-fix
Build all binaries#
make build
All tests pass, 85% coverage maintained, lint clean.
</verify>
<done>
- All 6 Phase 4 success criteria verified
- Full test suite passes
- Coverage threshold maintained (85%)
- Lint clean
- All binaries build successfully
- Ready to close Phase 4
</done>
</task>
</tasks>
<verification>
1. All golden tests pass: `go test -v -run Golden ./...`
2. Full test suite passes: `./scripts/run_tests.sh`
3. Coverage maintained: >= 85%
4. Lint clean: `make lint-fix`
5. All binaries build: `make build`
6. Phase 4 success criteria verified (6/6)
</verification>
<success_criteria>
Phase 4 complete when ALL of these are true:
1. int64_encoding = STRING produces JSON strings in all 4 generators
2. int64_encoding = NUMBER produces JSON numbers in all 4 generators (with warning)
3. enum_encoding = STRING produces proto name strings in all 4 generators
4. enum_value annotations produce custom JSON strings in all 4 generators
5. OpenAPI schemas accurately reflect configured encoding
6. Cross-generator consistency verified for every encoding combination
- Zero regressions in existing tests
- Backward compatible (protos without annotations unchanged)
</success_criteria>
<output>
After completion, create `.planning/phases/04-json-primitive-encoding/04-05-SUMMARY.md`
</output>
