Files
2026-05-27 23:29:53 +01:00

5.0 KiB

Why

Section 2 of the test-suite audit (/mnt/s/web/genesis/docs/superpowers/specs/2026-04-25-test-suite-audit.md row "No contract tests") lists consumer/provider contract testing as a critical missing tier of the test pyramid: @suaveplan/oauth-client, @suaveplan/webhook-client, @suaveplan/schema-registry, and @suaveplan/api-schemas are textbook Pact candidates whose failure modes (provider drifting from consumer expectations, schema breaking changes, OAuth token-endpoint shape mutations, webhook signature drift) are not catchable by today's unit, integration, or E2E tiers.

Today the only schema-shaped guard is hand-written Zod validation in each package's tests, which proves the consumer's encoder agrees with itself, not that a real provider's responses still match what the consumer was built against. This change introduces a project-wide Pact-style consumer/provider contract testing capability and wires it into every consumer package whose surface crosses a network boundary.

What Changes

New package — @suaveplan/testing-contract

  • Lives at packages/testing/testing-contract and follows the same dependency-graph exception as @suaveplan/testing-integration: zero @suaveplan/* runtime deps except @suaveplan/types (per CLAUDE.md rule 8 testing-infrastructure carve-out).
  • Public API:
    • defineConsumerInteraction({ provider, request, response, state? }) — declarative interaction record.
    • recordPactInteraction(httpClient) — wraps a fetch-shaped client; while wrapped, every request/response pair is recorded against the matching defineConsumerInteraction declarations into a .pact.json file.
    • verifyProviderAgainstPact(pactFile, providerUrl, options) — replays a pact file's interactions against a running provider and asserts each response matches the recorded shape.
    • publishPact(brokerUrl, version) and pullPactsForVerification(brokerUrl, providerName) — optional Pact Broker integration; auth via PACT_BROKER_TOKEN env.
  • Pact file shape conforms to Pact Specification v3 interactions[] (consumer/provider names, request, response, providerStates).
  • Errors prefixed TESTING_CONTRACT.*. Coverage gate at 100% (Istanbul, all four metrics).

Cross-cutting requirements on consumer packages

Each of the four packages SHALL ship a *.contract.test.ts that records interactions against its public API surface using recordPactInteraction. The recorded .pact.json files are committed to pacts/<consumer>__<provider>.json so PR review surfaces wire-format drift. Provider-side specs (where the package itself implements a server / receiver — webhook-client receivers, schema-registry server) SHALL run verifyProviderAgainstPact in CI against the same pact files.

Capability deltas

Each consumer package gets an ## ADDED Requirements block carrying:

  • A Consumer-side pact recording requirement (must produce a pact file in pacts/).
  • For server-shaped packages (webhook-client receiver, schema-registry server), a Provider-side pact verification requirement.

Capabilities

New Capabilities

  • testing-contract — Pact-style consumer/provider contract testing primitives (defineConsumerInteraction, recordPactInteraction, verifyProviderAgainstPact, publishPact, pullPactsForVerification).

Modified Capabilities

  • oauth-client — adds consumer-side pact requirement against the OAuth/OIDC provider's token + discovery endpoints.
  • webhook-client — adds consumer-side (signing) and provider-side (receiver) pact requirements.
  • schema-registry — adds consumer-side (schema lookup) and provider-side (registry server) pact requirements.
  • api-schemas — adds consumer-side pact recording over the common/auth/admin/events envelope shapes that consumers send to API plugins.

(None of these capabilities have a pre-existing openspec/specs/<capability>/spec.md yet; the deltas in this change land them as new files when folded.)

Impact

  • Affected code: new package at /mnt/s/web/genesis/packages/testing/testing-contract/**; new *.contract.test.ts files inside the four consumer packages; new pacts/ directories per consumer package.
  • Affected consumers: every @suaveplan/* package whose surface crosses a network boundary inherits the requirement on its first OpenSpec change after this one lands.
  • Catalog additions (root package.json): none — testing-contract synthesises pact JSON itself rather than depending on @pact-foundation/pact (which is Node-only and pulls a Ruby toolchain). The optional broker-publish path uses native fetch.
  • CI: a new pact:verify Turborepo task runs verifyProviderAgainstPact on every commit for the provider-shaped packages.
  • Pre-publish gate: every package with contract tests must pass pact:verify in addition to lint typecheck test and 100% coverage.
  • Cross-cutting: five new spec files land on archive (testing-contract, oauth-client, webhook-client, schema-registry, api-schemas).