Skip to main content
A contract is schema + rules + retry config — none of that needs a live LLM to test. Your contract logic is pure, and the entire pipeline is exposed through verify and a mockable RunFn.

Test schema + rules without an LLM

verify validates data directly:
Fast, deterministic, no mocks. Run these in CI without an API key.

Test the full loop with a fake RunFn

RunFn is just (attempt) => Promise<string | null>. Replace it with a function that returns canned strings:

Assert on repair context

Your RunFn sees attempt.repairs — assert that the loop is actually sending repair messages back:

Test without defineContract at all

Use enforce inline for one-shot tests:

Test failure categories

The 8 failure categories each have distinct triggers. Use fake RunFn outputs to hit them:

Disable retries in tests

Default maxAttempts: 3 means a failing RunFn runs three times. For tighter feedback, lower it:

Turn off the logger

If your test environment has the Boundary API key set (e.g. CI env leaks BOUNDARY_API_KEY), you don’t want tests shipping events to the real dashboard. Three options:
  1. Scrub the envvi.stubEnv("BOUNDARY_API_KEY", "") so createBoundaryLogger returns null.
  2. Pass logger: undefined at call time — overrides the defined logger for this test.
  3. Use a capture sink:
The third approach is great for asserting that the observability layer does what you expect.

See also

Engine primitives

verify, classify, clean used directly

ContractLogger hooks

Assert on specific lifecycle events