Fix the unconditional `net/url` import bug in protoc-gen-go-client (#105) and land PR #98 (cross-file unwrap resolution) after resolving its merge conflicts.

Purpose: These are the two code-level bugs/missing features in Phase 1. The net/url bug causes compile errors for POST-only services. The cross-file unwrap PR enables real-world usage patterns where proto files are split across multiple files in the same package.

Output: Both fixes landed on main, all tests passing, golden files updated.

<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/01-foundation-quick-wins/01-RESEARCH.md @internal/clientgen/generator.go @internal/clientgen/annotations.go @internal/clientgen/golden_test.go Task 1: Fix conditional net/url import in go-client generator internal/clientgen/generator.go, internal/clientgen/testdata/golden/backward_compat_client.pb.go, internal/clientgen/testdata/golden/query_params_client.pb.go, internal/clientgen/testdata/golden/http_verbs_comprehensive_client.pb.go Fix the unconditional `net/url` import in `protoc-gen-go-client` (GitHub issue #105).

Step 1: Add a fileNeedsURLImport method to Generator in internal/clientgen/generator.go. It mirrors the existing fileNeedsRequestBody pattern (lines 70-84). The function must return true if ANY method in the file uses:

  • Path parameters (httpConfig.PathParams has entries) -- these generate url.PathEscape() calls
  • Query parameters on GET/DELETE methods -- these generate url.Values{} usage

Implementation pattern:

func (g *Generator) fileNeedsURLImport(file *protogen.File) bool {
    for _, service := range file.Services {
        for _, method := range service.Methods {
            httpConfig := getMethodHTTPConfig(method)
            // Path params use url.PathEscape
            if httpConfig != nil && len(httpConfig.PathParams) > 0 {
                return true
            }
            // Determine HTTP method
            httpMethod := http.MethodPost
            if httpConfig != nil && httpConfig.Method != "" {
                httpMethod = httpConfig.Method
            }
            // GET/DELETE with query params use url.Values
            if httpMethod == http.MethodGet || httpMethod == http.MethodDelete {
                queryParams := getQueryParams(method.Input)
                if len(queryParams) > 0 {
                    return true
                }
            }
        }
    }
    return false
}

Step 2: Modify generateClientFile (line 47) to call fileNeedsURLImport and pass the result to writeImports. Find the existing call g.writeImports(gf, needsBytes) and replace with:

needsURL := g.fileNeedsURLImport(file)
g.writeImports(gf, needsBytes, needsURL)

Step 3: Modify writeImports signature to accept needsURL bool (line 94). Make the "net/url" line conditional:

func (g *Generator) writeImports(gf *protogen.GeneratedFile, needsBytes, needsURL bool) {
    // ... existing code ...
    gf.P(`"net/http"`)
    if needsURL {
        gf.P(`"net/url"`)
    }
    // ... rest of imports ...

Step 4: Update golden files by running:

make build && UPDATE_GOLDEN=1 go test -run TestClientGenGoldenFiles ./internal/clientgen/

Step 5: Verify the golden file diff:

  • backward_compat_client.pb.go should LOSE the "net/url" import line (POST-only, no path/query params)
  • query_params_client.pb.go should KEEP "net/url" (has query params)
  • http_verbs_comprehensive_client.pb.go should KEEP "net/url" (has path params and query params)

Step 6 (runs AFTER verification passes): Close GitHub issue #105:

gh issue close 105 --comment "Fixed: net/url import is now conditional based on whether the service uses path parameters or query parameters. POST-only services no longer generate unused net/url imports. The fix adds a fileNeedsURLImport() function that checks for path params (url.PathEscape usage) and query params on GET/DELETE methods (url.Values usage)."
```bash # Build and run all clientgen tests make build && go test -v ./internal/clientgen/

Verify backward_compat golden file does NOT contain net/url

! grep -q '"net/url"' internal/clientgen/testdata/golden/backward_compat_client.pb.go

Verify other golden files DO contain net/url#

grep -q '"net/url"' internal/clientgen/testdata/golden/query_params_client.pb.go grep -q '"net/url"' internal/clientgen/testdata/golden/http_verbs_comprehensive_client.pb.go

Run full test suite#

./scripts/run_tests.sh --fast

  </verify>
  <done>
- `fileNeedsURLImport` function exists in `generator.go` and checks both path params and query params
- `writeImports` conditionally emits `"net/url"` based on the `needsURL` parameter
- `backward_compat_client.pb.go` golden file no longer contains `"net/url"`
- `query_params_client.pb.go` and `http_verbs_comprehensive_client.pb.go` golden files still contain `"net/url"`
- All tests pass (golden file tests, unit tests, full test suite)
- GitHub issue #105 is closed with explanatory comment (closed AFTER verification confirms the fix works)
  </done>
</task>

<task type="auto">
  <name>Task 2: Land PR #98 (cross-file unwrap resolution)</name>
  <files>internal/httpgen/generator.go, internal/httpgen/unwrap.go, internal/httpgen/unwrap_test.go, internal/httpgen/testdata/proto/same_pkg_service.proto, internal/httpgen/testdata/proto/same_pkg_wrapper.proto</files>
  <action>
Land PR #98 which adds cross-file unwrap resolution for proto files in the same Go package.

**Important context:** PR #98 is currently OPEN with merge conflicts (`"mergeable":"CONFLICTING"`). The branch is `unwrap_bug`. The PR also has a lint failure on `go fmt` check, though tests pass on both platforms.

**Step 1:** Fetch and check out the PR branch locally:
```bash
gh pr checkout 98

Step 2: Rebase onto current main to resolve conflicts:

git rebase main

If conflicts arise, they are likely in the files recently changed on main (5 docs commits). Resolve them -- the PR's code changes should take priority for any code files; docs conflicts should incorporate both sides.

Step 3: Fix the lint issue by running:

go fmt ./...

Commit any formatting fixes.

Step 4: Run the full test suite to verify everything works BEFORE merging:

make build && ./scripts/run_tests.sh --fast

CRITICAL: Only proceed to Step 5 if ALL tests pass. If any test fails, debug and fix before merging.

Step 5: After tests pass, merge the PR into main:

gh pr merge 98 --squash --subject "fix(httpgen): resolve unwrap fields across files in same Go package"

If gh pr merge fails due to CI not passing on the rebased branch, push the rebased branch first (git push --force-with-lease) and wait for CI, or merge locally:

git checkout main
git merge --squash unwrap_bug
git commit -m "fix(httpgen): resolve unwrap fields across files in same Go package (#98)"

If merged locally, close the PR on GitHub so it doesn't remain OPEN:

gh pr close 98 --comment "Merged locally after resolving conflicts and passing tests"
```bash # Ensure we're on main with PR #98 changes git log --oneline -5

Run full test suite#

make build && ./scripts/run_tests.sh --fast

Verify cross-file unwrap test files exist#

ls internal/httpgen/testdata/proto/same_pkg_service.proto ls internal/httpgen/testdata/proto/same_pkg_wrapper.proto

Verify PR is merged or closed (CLOSED if merged locally)#

gh pr view 98 --json state -q '.state' | grep -E 'MERGED|CLOSED'

  </verify>
  <done>
- PR #98 is merged into main (state: MERGED, or CLOSED if merged locally)
- Cross-file unwrap test fixtures exist (`same_pkg_service.proto`, `same_pkg_wrapper.proto`)
- `GlobalUnwrapInfo` collects unwrap annotations from all proto files before code generation
- All tests pass (httpgen golden tests, unwrap tests, full suite)
  </done>
</task>

</tasks>

<verification>
After both tasks complete:

1. `go build ./cmd/protoc-gen-go-client/` succeeds
2. `go build ./cmd/protoc-gen-go-http/` succeeds
3. `./scripts/run_tests.sh --fast` passes all tests
4. `backward_compat_client.pb.go` golden file does NOT contain `"net/url"`
5. PR #98 shows state MERGED or CLOSED on GitHub (CLOSED if merged locally)
6. Issue #105 shows state CLOSED on GitHub (closed by Task 1 after verification confirms the fix)
7. `git log --oneline -5` shows both fix commits on main
</verification>

<success_criteria>
- The net/url import is conditional: only emitted when path params or query params are used
- Cross-file unwrap resolution works for proto files in the same Go package
- All golden file tests pass without manual intervention
- Full test suite passes with 85%+ coverage
- PR #98 merged, issue #105 closed
</success_criteria>

<output>
After completion, create `.planning/phases/01-foundation-quick-wins/01-01-SUMMARY.md`
</output>