Production engineering
Reveal answer and reasoning
A useful consumer contract covers the representation and persisted outcome it needs, not merely whether transport returned a familiar status. This fixture provides a200 body with an added optional field and another200 body whose required name has the wrong JSON kind. It also provides two503 responses at different transaction boundaries: before commit and after commit. Those pairs deliberately show why one status cannot establish compatibility or authorize retrying a mutation.
The external verifier makes real loopback requests and reads the resulting SQL state through an endpoint, while the portable companion checks only supplied representations and simple local publication decisions.
ContractLabs.VerifyAsync accepts an owned HTTP loopback root and creates a bounded-time HttpClient. It requests compatible and breaking responses, checks their actual JSON through the stronger Accept predicate, verifies fresh state zero, sends the controlled before failure and confirms zero, then sends the after failure and confirms one. That is seven explicit checks: two representations, initial state, two statuses and two resulting states.
Both failure endpoints actually update inside SQLite transactions, but only the before path rolls back. The after path commits before returning503, creating the uncertainty a real client must reconcile instead of inferring rollback from the response code.
What a strong answer covers
- A useful consumer contract covers the representation and persisted outcome it needs, not merely whether transport returned a familiar status.
- ContractLabs.VerifyAsync accepts an owned HTTP loopback root and creates a bounded-time HttpClient.
- Ignoring unknown properties can be compatible for this tolerant consumer without making every added field harmless for every client.
Common pitfall
Ignoring unknown properties can be compatible for this tolerant consumer without making every added field harmless for every client. Required property names, kinds, ranges and nullability still matter. JsonDocument parsing proves syntactic JSON, while Accept supplies the narrower application contract. Likewise, a failed response does not prove the server failed before applying a mutation. Repeating the after endpoint would increment again because this endpoint intentionally has no request-receipt protocol. The verifier also requires a fresh fixture, so old contract_effect state must not be mistaken for a failure of its zero baseline or used to claim a clean independent run.
Follow-up questions
- Which invalid bodies can the external Accept predicate reject even though the portable name-kind check would accept them?
- Why is a changed JSON property kind a compatibility failure even when transport status remains200?
Self-review
Choose what to revisit. These marks are your own assessment and are separate from lesson completion.