# Watch a failure shrink

An order belongs to a customer. Its lines belong to that order, and its total must
equal the sum of the line prices. Those relationships should survive shrinking.

This demo tests a deliberately false rule: **every order fits the selected
budget**. Find an order that breaks it, reveal the real shrink result, then replay
that failure. Change the seed or budget to explore a different run.

[Open the interactive demo](/mimlet/guide/scenario-demo.html).

## What actually runs

The website executes the [tested scenario recipe](https://github.com/JeffreyNijs/mimlet/blob/main/examples/recipes/scenario-demo.ts)
using `createScenario`, `scenarioArbitrary`, `checkFixtureProperty` and
`replayFixtureProperty`. The same recipe is compiled and tested against clean
package tarballs by `pnpm test:examples`.

The arbitrary produces one to six line prices between 1 and 100 cents. It makes
at most 50 property checks before shrinking a failure. Each shrink rebuilds the
customer, order and lines from the reduced prices. No requests leave the browser,
and the demo runs a fixed recipe rather than arbitrary uploaded JavaScript.

The shrink result is the result of this search, not a guarantee of a globally
smallest counterexample. A passing bounded run does not prove a rule correct.
Replay checks the recipe, budget, provider and engine identities before reusing
the recorded seed and shrink path. Changing the budget invalidates an old replay.

## Use the same pattern in a test

```ts
import * as fc from 'fast-check';
import { createScenario } from '@mimlet/core';
import { scenarioArbitrary, checkFixtureProperty } from '@mimlet/fast-check';

const identity = { fingerprint: 'basket/v1', provider: 'my-test@1' };
const cart = createScenario()
  .node('prices', [], () => [] as number[])
  .node('total', ['prices'], ({ prices }) => prices.reduce((sum, n) => sum + n, 0));
const baskets = scenarioArbitrary(
  fc.array(fc.integer({ min: 1, max: 100 }), { minLength: 1, maxLength: 10 }),
  (prices) => cart.override('prices', () => prices),
  { ...identity, seed: 42 }
);

// Deliberately false property: inspect its report without making the example fail CI.
export const report = checkFixtureProperty(baskets, (basket) => basket.total < 5, {
  identity,
  seed: 12345,
  numRuns: 100,
});
// Shrinking recomputes total from prices; the minimal counterexample is { prices: [5], total: 5 }.
// In a real test, use assertFixtureProperty so a failed property fails the test.
```

Continue with [correlated scenarios](/mimlet/guide/correlated-scenarios.md),
[sessions and replay](/mimlet/guide/sessions-and-replay.md), or the
[fast-check reference](/mimlet/packages/fast-check.md).
