6.5 KiB
6.5 KiB
0. Pre-flight (non-negotiable)
- 0.1 Confirm clean working tree (
git statusreports nothing) and no in-flight worktrees with uncommitted work (git worktree listthengit statusin 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.mdmatchesfind packages -maxdepth 3 -name package.jsoncount. Drift here means a prior change archived without regenerating the manifest.
1. Package skeleton — @suaveplan/testing-contract
- 1.1 Create
packages/testing/testing-contract/withpackage.json(version0.1.0,type: "module",sideEffects: false, only@suaveplan/typesas aworkspace:^internal dep, catalog deps onzodonly). - 1.2 Add
tsconfig.lib.jsonextending@suaveplan/typescript-config/library.json; addvite.config.ts(preserveModules: true); addvitest.config.tsviacreateTestConfig(). - 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)andwritePactFile(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 aFetchLikeand matches each request/response pair against registered interactions; onflushPact(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
.mdper file (≥200 words with simple + advanced examples peropenspec/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 injectablefetchFn; asserts response matches recorded shape modulooptions.ignoreFields. - 4.2 Implement
src/verify/state-handler.ts— provider-state handler registry;options.stateHandlers: Record<string, () => Promise<void>>runs before each interaction whosestateis 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'scontext.
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 viaPACT_BROKER_TOKEN. - 5.2 Implement
src/broker/pull-pacts.ts—pullPactsForVerification(brokerUrl, providerName)returnsPactFile[]; uses the broker'sprovider-pacts-for-verificationendpoint. - 5.3 Implement
src/broker/auth.ts— readPACT_BROKER_TOKEN; throwTestingContractError("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 Errorwith{ code, cause?, context? }; subclasses for the recording, verification, and broker domains. - 6.2 Implement
src/errors/codes.ts— string-literal-union of everyTESTING_CONTRACT.<DOMAIN>.<REASON>code.
7. Spec deltas
- 7.1 Land
specs/testing-contract/spec.mdwith## ADDED Requirements(data model, consumer recording, provider verification, broker integration, error code prefix, coverage gate). - 7.2 Land
specs/oauth-client/spec.mdwith## ADDED Requirementsfor consumer-side pact recording. - 7.3 Land
specs/webhook-client/spec.mdwith## ADDED Requirementsfor consumer-side and provider-side pact requirements. - 7.4 Land
specs/schema-registry/spec.mdwith## ADDED Requirementsfor consumer-side and provider-side pact requirements. - 7.5 Land
specs/api-schemas/spec.mdwith## ADDED Requirementsfor consumer-side pact recording over envelope shapes.
8. Per-consumer wiring
- 8.1 Add
oauth-client.contract.test.tsto@suaveplan/oauth-client; record token endpoint + discovery + introspection; commitpacts/oauth-client__oidc-issuer.json. - 8.2 Add
webhook-client.contract.test.tsto@suaveplan/webhook-client(consumer side: signed delivery POST); addwebhook-client.provider.test.ts(verifies receiver against the same pact); commitpacts/webhook-client__webhook-receiver.json. - 8.3 Add
schema-registry.contract.test.tsto@suaveplan/schema-registry(consumer side: schema lookup); addschema-registry.provider.test.ts(verifies the registry server); commitpacts/schema-registry__upstream-registry.json. - 8.4 Add
api-schemas.contract.test.tsto@suaveplan/api-schemas; record envelope-shape interactions forcommon/auth/admin/events; commitpacts/api-schemas__enterprise-api.json.
9. CI
- 9.1 Add a
pact:verifyTurborepo task that runs every provider-shaped package'sverifyProviderAgainstPactagainst the committed pact files. - 9.2 Wire
pact:verifyinto the pre-publish gate alongsidelint typecheck test.
10. Verification
- 10.1
bunx turbo lint typecheck test --filter=@suaveplan/testing-contractgreen. - 10.2
bunx turbo test:coverage --filter=@suaveplan/testing-contractat 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.