Skip to content

refactor: centralize HTTP client in internal/httpx (#1503 partial 8.3)#1533

Merged
nextlevelshit merged 1 commit into
mainfrom
refactor/1503-httpx
Apr 29, 2026
Merged

refactor: centralize HTTP client in internal/httpx (#1503 partial 8.3)#1533
nextlevelshit merged 1 commit into
mainfrom
refactor/1503-httpx

Conversation

@nextlevelshit
Copy link
Copy Markdown
Collaborator

Summary

New internal/httpx package: shared HTTP Client with timeout, retry (exponential backoff with cap), and audit-emitter hooks. Eliminates 7 of 9 &http.Client{} constructions across the codebase. 8.5 formatDuration verified — already consolidated by PR #1408.

Public API

type Config struct {
    Timeout       time.Duration
    MaxRetries    int
    RetryBaseWait time.Duration
    RetryMaxWait  time.Duration
    Transport     http.RoundTripper
    CheckRedirect func(*http.Request, []*http.Request) error
    AuditEmitter  func(Event)
}

type Event struct { URL, Method string; StatusCode, Attempt int; Duration time.Duration; Err error }

func New(cfg Config) *Client
func (c *Client) Do(ctx, *http.Request) (*http.Response, error)
func (c *Client) Get(ctx, url string) (*http.Response, error)
func (c *Client) Post(ctx, url, contentType string, body io.Reader) (*http.Response, error)
func (c *Client) HTTPClient() *http.Client  // escape hatch

Defaults

  • 30s timeout, 3 retries, 500ms base / 30s cap exponential backoff
  • Single-shot opt-in: MaxRetries: 0 + non-zero retry-wait fields = explicit single-shot intent

Per-site policy migrated

Site Timeout Retries Notes
contract/llm_judge 60s 2 Anthropic API transients
forge/detect.probeHTTPClient 3s 0 Best-effort probe; preserves InsecureSkipVerify + no-redirect
github.Client ForgeAPI (15s) 0 github layer has its own retry/rate-limit loop
onboarding.probeOllamaModels 2s 0 Localhost probe

8.5 formatDuration verification

Out of scope (deferred follow-up)

  • internal/hooks/{http,webhook_runner}.go — 2 remaining &http.Client{}. Trivial follow-up.

Validation

  • go build ./... + go vet ./... clean
  • go test -race ./internal/httpx/... ./internal/contract/... ./internal/forge/... ./internal/github/... ./internal/onboarding/... all pass
  • golangci-lint 0 issues

Test plan

  • CI green
  • LLM judge still calls Claude (wave run with agent_review contract)
  • Forge detection still works (wave init)

Partial of #1503 (subset 8.3 + 8.5 verify). Parent: #1494.

- New internal/httpx package: shared Client with timeout, retry, and
  audit hook configuration. Single network policy across the codebase.
- Migrate contract/llm_judge, forge/detect, github, onboarding to consume
  httpx.Client. forge probes and github use single-shot mode (their
  callers handle retry/rate-limit). llm_judge keeps 60s timeout, retries
  twice on transient 5xx.
- Verify formatDuration consolidation (8.5): tui/pipeline_list,
  webui/embed, webui/handlers_runs all use internal/humanize. Only
  audit/logger keeps a private formatDuration ("%.3fs" trace format) by
  design — different output shape from humanize.

Closes #1503.
@nextlevelshit nextlevelshit merged commit 72307ee into main Apr 29, 2026
6 checks passed
@nextlevelshit nextlevelshit deleted the refactor/1503-httpx branch April 29, 2026 00:49
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant