Migrate httpgen to use the shared `internal/annotations` package, then delete the old annotation code.

Purpose: httpgen is the most complex generator with the widest annotation surface area. Migrating it first validates the shared package's API covers the most demanding use case. After this plan, httpgen has zero duplicated annotation parsing code.

Output: httpgen fully migrated to shared annotations, old annotations.go deleted, all tests passing.

<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/phases/02-shared-annotations/02-CONTEXT.md @.planning/phases/02-shared-annotations/02-01-SUMMARY.md @internal/httpgen/annotations.go @internal/httpgen/generator.go @internal/httpgen/unwrap.go @internal/httpgen/validation.go @internal/httpgen/mock_generator.go @internal/httpgen/annotations_test.go Task 1: Replace httpgen annotation calls with shared package calls internal/httpgen/generator.go internal/httpgen/unwrap.go internal/httpgen/validation.go internal/httpgen/mock_generator.go Add `"github.com/SebastienMelki/sebuf/internal/annotations"` import to each file that uses annotation functions. Then replace ALL calls to the local annotation functions with shared package calls. Specific replacements:

generator.go (6 call sites):

  • getMethodHTTPConfig(method) -> annotations.GetMethodHTTPConfig(method) (lines ~790, ~810, ~819)
    • Where config.Method is used: no change needed (shared package returns uppercase, httpgen already uses uppercase)
    • Where config.PathParams is used: no change needed (same type)
  • getServiceHTTPConfig(service) -> calls need adjustment: replace getServiceHTTPConfig(service) with annotations.GetServiceBasePath(service) and use the returned string directly instead of serviceConfig.BasePath. Look at line ~801 where config := getServiceHTTPConfig(service) is called and config.BasePath is accessed -- replace with basePath := annotations.GetServiceBasePath(service).
  • getServiceHeaders(service) -> annotations.GetServiceHeaders(service) (line ~1417)
  • getMethodHeaders(method) -> annotations.GetMethodHeaders(method) (line ~1436)
  • getQueryParams(method.Input) -> annotations.GetQueryParams(method.Input) (line ~1482)
    • IMPORTANT: httpgen's QueryParam only has FieldName, FieldGoName, ParamName, Required. The shared QueryParam has additional fields (FieldJSONName, FieldKind, Field). httpgen code accesses only the fields it needs, so this works without any extra changes. But verify every access pattern: .FieldName, .FieldGoName, .ParamName, .Required -- all still valid.
  • getFieldExamples(field) -> annotations.GetFieldExamples(field) (in mock_generator.go line ~69)
  • lowerFirst(...) -> annotations.LowerFirst(...) (line ~827 area -- but lowerFirst is also used extensively in generator.go for non-annotation purposes. Replace ALL occurrences.)
  • Remove parseExistingAnnotation call at line ~796 and replace with empty string or adjust the helper function that calls it. This is dead code (always returns "").

Also in generator.go: Remove the lowerFirst function definition (lines 827-832) and the parseExistingAnnotation usage. The function getPath at ~793 calls parseExistingAnnotation -- this always returns empty string, so just replace the body to return empty string directly, or remove the entire getPath function if it's only used in one place and inline the empty-string logic. Check all callers.

unwrap.go (5 call sites):

  • getUnwrapField(msg) -> annotations.GetUnwrapField(msg) (lines ~90, ~136, ~178, ~252)
  • Type references: *UnwrapFieldInfo -> *annotations.UnwrapFieldInfo
  • &UnwrapValidationError{...} -- this type is defined in annotations.go but the struct literal creation in unwrap.go should reference annotations.UnwrapValidationError if needed. Check if unwrap.go creates any UnwrapValidationError directly or only receives them from getUnwrapField. (It only receives them -- getUnwrapField returns them.)
  • UnwrapContext struct references *UnwrapFieldInfo in its fields -- update to *annotations.UnwrapFieldInfo.
  • GlobalUnwrapInfo struct's UnwrapFields map type: map[string]*UnwrapFieldInfo -> map[string]*annotations.UnwrapFieldInfo

validation.go (2 call sites):

  • getMethodHTTPConfig(method) -> annotations.GetMethodHTTPConfig(method) (line ~22)
  • getQueryParams(method.Input) -> annotations.GetQueryParams(method.Input) (line ~64)
  • The getBodyFields function takes []QueryParam -- update to []annotations.QueryParam
  • The ValidationError struct stays local (it's httpgen-specific, not annotation-related)

mock_generator.go (1 call site):

  • getFieldExamples(field) -> annotations.GetFieldExamples(field) (line ~69)

After ALL replacements, remove the HTTP method constants (httpMethodGET, etc.) from generator.go if they exist there (they're in annotations.go which will be deleted).

Run go build ./internal/httpgen/ after changes to verify compilation. Then run make lint-fix. go build ./internal/httpgen/ compiles successfully. go build ./cmd/protoc-gen-go-http/ compiles successfully. make lint-fix produces no errors. All httpgen files import and use annotations package. No local annotation parsing functions remain in generator.go, unwrap.go, validation.go, or mock_generator.go.

Task 2: Delete httpgen/annotations.go and annotations_test.go, run full test suite internal/httpgen/annotations.go internal/httpgen/annotations_test.go Delete `internal/httpgen/annotations.go` entirely (392 lines). This file contains: - HTTP method constants (httpMethodGET, etc.) - pathParamRegex - HTTPConfig, QueryParam, ServiceConfigImpl structs - getMethodHTTPConfig, httpMethodToString, extractPathParams, getServiceHTTPConfig - getServiceHeaders, getMethodHeaders, parseExistingAnnotation, getFieldExamples - getQueryParams, UnwrapFieldInfo, hasUnwrapAnnotation, getUnwrapField, UnwrapValidationError

ALL of these are now in the shared package or removed (parseExistingAnnotation was dead code).

Delete internal/httpgen/annotations_test.go entirely (188 lines). The tests for pure functions (TestHttpMethodToString, TestExtractPathParams, benchmarks) were moved to the shared package in plan 02-01. The struct tests (TestHTTPConfig_Struct, TestQueryParam_Struct, TestServiceConfigImpl_Struct) tested local struct types that no longer exist -- equivalent tests exist in the shared package.

After deletion, verify:

  1. go build ./internal/httpgen/ still compiles (no missing references)
  2. go build ./cmd/protoc-gen-go-http/ still compiles
  3. Run go test ./internal/httpgen/... -- all remaining tests pass
  4. Run the golden file tests: go test -v -run TestExhaustiveGoldenFiles ./internal/httpgen/... -- MUST pass with ZERO changes to golden files
  5. Run ./scripts/run_tests.sh --fast for full test suite
  6. Run make lint-fix

If any golden file test fails, the migration introduced a behavior change -- investigate and fix. The most likely causes:

  • Missing import causing nil dereference
  • QueryParam field name mismatch
  • HTTP method case mismatch

Do NOT update golden files. If golden files need updating, the migration is wrong. go build ./cmd/protoc-gen-go-http/ succeeds. go test ./internal/httpgen/... all tests pass. Golden file tests pass WITHOUT updating golden files. ./scripts/run_tests.sh --fast all tests pass. ls internal/httpgen/annotations.go returns "No such file or directory". ls internal/httpgen/annotations_test.go returns "No such file or directory". make lint-fix clean. httpgen/annotations.go (392 lines) and annotations_test.go (188 lines) are deleted. All httpgen tests including golden file tests pass unchanged. Zero behavior change confirmed.

1. `go build ./cmd/protoc-gen-go-http/` succeeds 2. `go test ./internal/httpgen/...` all tests pass 3. Golden file tests pass with zero golden file changes 4. `./scripts/run_tests.sh --fast` passes 5. `internal/httpgen/annotations.go` does not exist 6. `internal/httpgen/annotations_test.go` does not exist 7. `grep -r "annotations\." internal/httpgen/` shows shared package usage 8. `make lint-fix` clean

<success_criteria>

  • httpgen/annotations.go deleted (392 lines removed)
  • httpgen/annotations_test.go deleted (188 lines removed)
  • All httpgen source files import internal/annotations
  • All golden file tests pass unchanged
  • Full test suite passes
  • Zero behavior change </success_criteria>
After completion, create `.planning/phases/02-shared-annotations/02-02-SUMMARY.md`