Build a consumer
A consumer — a UI, client app, or downstream system — implements none of these contracts; it relies on them. The Microcks mock stack stands in for the real services, so a consumer can be built and demonstrated, with data, before any implementation exists. This is what the mocks are for: consumers, and the spec repo's own conformance checks. Holding a real implementation to the contracts is a different job with a different command — see Drive an implementation.
The loop below is carried end-to-end by the consume-service skill. Install the plugin — /plugin marketplace add hungovercoders/sysspec, then /plugin install — and ask to build against a service; the skill runs everything on this page, from interview to verified definition of done. What follows is the shape of that loop, so you can recognise it, review it, or run it by hand.
flowchart TD tag["spec repo: merge to main cuts service/vX.Y.Z"] lock["contracts.lock pins the tag + its commit sha"] fetch["task contracts:fetch - read-only .contracts/ (specs + mocks + kit)"] mocks["task -d .contracts mocks:load - pinned mocks up, fixtures included"] build["build: generate types from the fetched specs"] verify["verify: client flows, envelope handling, idempotence"] done(["consumer satisfies the pinned surface"]) tag -->|"pin the newest tag"| lock lock --> fetch --> mocks --> build --> verify verify -->|green| done verify -->|red| build tag -.->|"each new tag: Renovate re-pins"| lock
1. Pin and fetch, exactly like an implementation
The consumer records which released surface it builds against in a contracts.lock and fetches it read-only into .contracts/ — the same lock and contracts:fetchthe implementation journey uses, mock stack included, so the mocks a consumer sees are versioned by the pin. A consumer may pin more than one service.
2. Stand up the pinned mocks
task -d .contracts mocks:load SERVICE=<service> # stack up + pinned specs loaded
task -d .contracts mocks:watch CHANNEL=<Title>/<version>/<operation>
task -d .contracts mocks:downPoint the client at the mocks (title and version come from the spec's info block):
- REST —
http://localhost:8585/rest/<Title>/<version>/…with fixture data included, so list and detail screens render real-looking aggregates. - Events —
ws://localhost:8081/api/ws/<Title>/<version>/<operation>emits the example CloudEvents on a schedule.
3. Build against them
Generate client types from the fetched OpenAPI and the AsyncAPI message schemas — never hand-model a payload from memory or from observed mock traffic. Honour the event conventions the features state: dedupe on the CloudEvents envelope id, expect at-least-once delivery, assume ordering only within an aggregate, and tolerate additive change — a minor bump must never break a consumer.
4. Verify — the consumer's definition of done
- Client flows against the REST mocks — every call the consumer makes, responses parsed through the generated types.
- Event handling against real envelopes — feed the handler from the WS mock or the pinned example files, validating each payload against the AsyncAPI schema before acting on it.
- Idempotence — replaying the same envelope
idmust not double-apply; the features promise at-least-once delivery, so this is contract, not hygiene. - Falsifiability — prove the suite can fail: run it once against the kit's null service (
task -d .contracts null:run …) or, minimally, with the mock stack down, and require zero passes. A check that stays green against a service answering200 {}to everything verifies nothing.
Green proves the consumer satisfies the pinned surface's examples and schemas. It does not prove the real service behaves — that is the implementation's verification loop, on the other page.
5. Stay current
Identical machinery to implementations: new release tags arrive as Renovate pin-bump PRs, the suite above runs against the new pin — new mocks, new fixtures — and green minors auto-merge with no human and no agent. The consume-service skill (hungovercoders/sysspec) carries the full walkthrough.