Skip to content

[H-11 / Phase 3] [MEDIUM] Zod-parse external API responses #12

@matthewod11-stack

Description

@matthewod11-stack

Full spec: docs/hardening-roadmap-2026-04-16.md#h-11

Description

GitHubClient, HunterClient, XClient, ExaClient declare response interfaces and cast await response.json() to that type. Field renames (e.g., public_reposrepo_count) silently produce undefined and corrupt downstream scoring. The "API field renames" pattern flagged in rules/debugging.md.

Current State

  • packages/adapters/adapter-github/src/github-client.ts
  • packages/adapters/adapter-hunter/src/hunter-client.ts
  • packages/adapters/adapter-x/src/x-client.ts
  • packages/adapters/adapter-exa/ (identify HTTP call site)

Suggested Fix

  • Define Zod schema per client matching minimal fields used.
  • Parse at boundary: const user = GitHubUserSchema.parse(await res.json()).
  • Catch Zod errors, rethrow as named ApiContractError with field path + truncated payload.
  • Warn-log on unknown fields (passthrough diff) — early signal for API evolution.

Verification

  • pnpm build passes
  • pnpm test passes
  • pnpm typecheck clean
  • Unit test per adapter: missing required field → ApiContractError with field path
  • Unit test: unknown field → warn log, no throw

Automation Hints

scope: packages/adapters
do-not-touch: packages/core, packages/scoring
approach: add-validation
risk: medium
max-files-changed: 10
blocked-by: #9
bail-if: any adapter integration test fails

Priority

Medium

Metadata

Metadata

Assignees

No one assigned

    Labels

    tech-debtEligible for automated overnight fixing

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions