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

6.5 KiB

0. Pre-flight (non-negotiable)

  • 0.1 Confirm clean working tree (git status reports nothing) and no in-flight worktrees with uncommitted work (git worktree list then git status in each)
  • 0.2 If any worktrees exist under .claude/worktrees/, account for each one: still-active agent, work-pending-merge, or stale-and-prune. Stale worktrees MUST be removed (git worktree remove) before opening a new one — code that has been lost twice on main is the failure mode this guards against.
  • 0.3 Confirm the package set in MANIFEST.md matches find packages -maxdepth 3 -name package.json count. Drift here means a prior change archived without regenerating the manifest.

1. Package skeleton — @suaveplan/testing-contract

  • 1.1 Create packages/testing/testing-contract/ with package.json (version 0.1.0, type: "module", sideEffects: false, only @suaveplan/types as a workspace:^ internal dep, catalog deps on zod only).
  • 1.2 Add tsconfig.lib.json extending @suaveplan/typescript-config/library.json; add vite.config.ts (preserveModules: true); add vitest.config.ts via createTestConfig().
  • 1.3 Stub README.md (one-paragraph description, install, quick start, Modules index linking each co-located .md).

2. Pact data model

  • 2.1 Implement src/pact-file/pact-file.types.ts — types matching Pact Specification v3 (PactFile, PactInteraction, PactRequest, PactResponse, PactProviderState).
  • 2.2 Implement src/pact-file/pact-file.schemas.ts — Zod schemas for every type above; round-trip parse/serialise covered by tests.
  • 2.3 Implement src/pact-file/read-write.ts — readPactFile(path) and writePactFile(path, pact) with deterministic key order (consumer / provider / interactions / metadata) so diffs are reviewable.

3. Consumer-side recording

  • 3.1 Implement src/define/define-consumer-interaction.ts — defineConsumerInteraction({ provider, request, response, state? }); registers the expectation against a per-process registry; returns a handle for cleanup.
  • 3.2 Implement src/record/record-pact-interaction.ts — recordPactInteraction(httpClient) wraps a FetchLike and matches each request/response pair against registered interactions; on flushPact(path) writes the pact file.
  • 3.3 Implement src/record/match-interaction.ts — match algorithm (method + path + headers subset + body shape); reports unmatched interactions distinctly from interactions with no traffic.
  • 3.4 Co-locate tests, schemas, and .md per file (≥200 words with simple + advanced examples per openspec/AGENTS.md §4).

4. Provider-side verification

  • 4.1 Implement src/verify/verify-provider-against-pact.ts — verifyProviderAgainstPact(pactFile, providerUrl, options); replays each interaction via injectable fetchFn; asserts response matches recorded shape modulo options.ignoreFields.
  • 4.2 Implement src/verify/state-handler.ts — provider-state handler registry; options.stateHandlers: Record<string, () => Promise<void>> runs before each interaction whose state is registered.
  • 4.3 Implement src/verify/diff-report.ts — produce a structured diff when a verification fails (path → expected vs actual); included in the thrown error's context.

5. Pact Broker integration

  • 5.1 Implement src/broker/publish-pact.ts — publishPact(brokerUrl, version) HTTP POST to /pacts/provider/<P>/consumer/<C>/version/<v>; auth via PACT_BROKER_TOKEN.
  • 5.2 Implement src/broker/pull-pacts.ts — pullPactsForVerification(brokerUrl, providerName) returns PactFile[]; uses the broker's provider-pacts-for-verification endpoint.
  • 5.3 Implement src/broker/auth.ts — read PACT_BROKER_TOKEN; throw TestingContractError("TESTING_CONTRACT.BROKER.MISSING_TOKEN") when broker calls are made without auth.

6. Errors

  • 6.1 Implement src/errors/testing-contract-error.ts — TestingContractError extends Error with { code, cause?, context? }; subclasses for the recording, verification, and broker domains.
  • 6.2 Implement src/errors/codes.ts — string-literal-union of every TESTING_CONTRACT.<DOMAIN>.<REASON> code.

7. Spec deltas

  • 7.1 Land specs/testing-contract/spec.md with ## ADDED Requirements (data model, consumer recording, provider verification, broker integration, error code prefix, coverage gate).
  • 7.2 Land specs/oauth-client/spec.md with ## ADDED Requirements for consumer-side pact recording.
  • 7.3 Land specs/webhook-client/spec.md with ## ADDED Requirements for consumer-side and provider-side pact requirements.
  • 7.4 Land specs/schema-registry/spec.md with ## ADDED Requirements for consumer-side and provider-side pact requirements.
  • 7.5 Land specs/api-schemas/spec.md with ## ADDED Requirements for consumer-side pact recording over envelope shapes.

8. Per-consumer wiring

  • 8.1 Add oauth-client.contract.test.ts to @suaveplan/oauth-client; record token endpoint + discovery + introspection; commit pacts/oauth-client__oidc-issuer.json.
  • 8.2 Add webhook-client.contract.test.ts to @suaveplan/webhook-client (consumer side: signed delivery POST); add webhook-client.provider.test.ts (verifies receiver against the same pact); commit pacts/webhook-client__webhook-receiver.json.
  • 8.3 Add schema-registry.contract.test.ts to @suaveplan/schema-registry (consumer side: schema lookup); add schema-registry.provider.test.ts (verifies the registry server); commit pacts/schema-registry__upstream-registry.json.
  • 8.4 Add api-schemas.contract.test.ts to @suaveplan/api-schemas; record envelope-shape interactions for common/auth/admin/events; commit pacts/api-schemas__enterprise-api.json.

9. CI

  • 9.1 Add a pact:verify Turborepo task that runs every provider-shaped package's verifyProviderAgainstPact against the committed pact files.
  • 9.2 Wire pact:verify into the pre-publish gate alongside lint typecheck test.

10. Verification

  • 10.1 bunx turbo lint typecheck test --filter=@suaveplan/testing-contract green.
  • 10.2 bunx turbo test:coverage --filter=@suaveplan/testing-contract at 100% statement / branch / function / line.
  • 10.3 bunx turbo pact:verify --filter=@suaveplan/{oauth-client,webhook-client,schema-registry,api-schemas} green.
  • 10.4 Banned-pattern scan clean.

11. Archive

  • 11.1 Move openspec/changes/enterprise-testing-contract/ → openspec/archive/<yyyy-mm-dd>-enterprise-testing-contract/ after all gates pass.