# Shape the World for a test

Build one repeatable workflow with stored data, a scripted answer, a one-time failure, an explicit retry and a frozen clock. Use Node 22.6 or newer and npm in an empty directory; no platform account or real key is needed.

## Separate records from behavior

Create stored records through the vendor's own API. Use ordered scenario handlers for model judgment, stateless lookups and faults. A handler must never fake success for a stored mutation. This example creates a Stripe customer and asks OpenAI to classify its signup; the first ask fails, the second returns the authored label.

```json file=package.json
{
  "name": "acme-web",
  "private": true,
  "type": "module",
  "dependencies": {
    "stripe": "17.7.0",
    "openai": "4.104.0"
  },
  "devDependencies": {
    "@volter/world": "3.0.63",
    "@volter/twin-stripe": "3.0.1",
    "@volter/twin-openai": "3.0.1"
  }
}
```

```text file=.env.example
STRIPE_SECRET_KEY=
OPENAI_API_KEY=
```

```js file=workflow.mjs
import assert from 'node:assert/strict';
import Stripe from 'stripe';
import OpenAI from 'openai';
const stripe = new Stripe(process.env.STRIPE_SECRET_KEY);
const model = new OpenAI({ apiKey: process.env.OPENAI_API_KEY, maxRetries: 0 });
const customer = await stripe.customers.create({ email: 'retry@example.com' });
assert.equal(customer.created, Date.parse('2026-01-15T12:00:00Z') / 1000);
const ask = () => model.chat.completions.create({ model: 'gpt-4o-mini', messages: [{ role: 'user', content: 'classify this signup' }] });
await assert.rejects(ask(), error => error.status === 429);
const answer = await ask();
assert.equal(answer.choices[0].message.content, 'billing');
assert.equal((await stripe.customers.retrieve(customer.id)).email, 'retry@example.com');
const scenario = await fetch(`${process.env.OPENAI_TWIN_URL}/twin/scenario`).then(r => r.json());
assert.match(JSON.stringify(scenario), /rate-limit-once/);
console.log('stored data, one refusal, retry answer and frozen timestamp passed');
```

```bash
npm install
npx volter world init --name repeatable-workflow --twins stripe,openai
```

Review the selected vendors and their exact service sources before booting. Save this handler after init, replacing the starter OpenAI scenario for this example:

```json file=.volter/handlers/openai.json
{
  "handlers": [
    {
      "id": "rate-limit-once",
      "on": {
        "userTextIncludes": "classify this signup"
      },
      "once": true,
      "fault": {
        "kind": "status",
        "status": 429,
        "message": "retry this request"
      }
    },
    {
      "id": "signup-answer",
      "on": {
        "userTextIncludes": "classify this signup"
      },
      "respond": {
        "text": "billing"
      }
    }
  ]
}
```

Handlers are first-match, in order. `once` consumes the first rule once during that twin process's lifetime; the second rule then answers the same prompt. The SDK has retries disabled so the app can assert the first failure and retry explicitly. Your own SDK retry policy can exercise the same failure, but may hide it from application code.

## Wire the handler for this released runtime

The pinned runtime in this example may omit scenario wiring when a published twin contains no starter journey. Saving the file alone does not select it. This helper explicitly names the authored file in the init-generated service and retains its other settings:

```js file=configure-scenario.mjs
import { readFileSync, writeFileSync } from 'node:fs';
const path = '.volter/world.json';
const config = JSON.parse(readFileSync(path, 'utf8'));
const service = config.services.find(s => s.id === 'openai');
if (!service?.execution?.colocate) throw new Error('Expected the generated OpenAI service');
service.execution.colocate.scenarioPath = '.volter/handlers/openai.json';
writeFileSync(path, JSON.stringify(config, null, 2) + '\n');
```

```bash
node configure-scenario.mjs
```

## Execute and inspect

```bash
npx volter world up
npx volter world clock set 2026-01-15T12:00:00Z
npx volter world run -- node workflow.mjs
```

```text
stored data, one refusal, retry answer and frozen timestamp passed
```

```bash
npx volter world log
npx volter world clock advance 30d
npx volter world down
```

The customer is real stored state inside the twin. The answer is authored test behavior, not a claim about a model's judgment. `/twin/scenario` shows handler matches and misses; `/twin` documents this implementation's matcher and time grammar. Use [recovery](./recover-a-failed-call.md) when a call misses.

## Repeat from the same conditions

```bash
npx volter world up
npx volter world reset
npx volter world clock set 2026-01-15T12:00:00Z
npx volter world run -- node workflow.mjs
```

```text
stored data, one refusal, retry answer and frozen timestamp passed
```

```bash
npx volter world down
```

`down` retains data; `up` resumes it. Reset clears this disposable branch's vendor state and reseeds; a restarted twin rearms the once-handler. Restore the clock explicitly before repeating. Editing the handler and restarting loads the new behavior. Reset is destructive to this branch's changes, so use a [failure branch](./reproduce-a-failure.md) when you need to preserve them.

For shared setup, use [seed and reset](./seed-and-reset.md). The [cookbook](../../cookbook/README.md) provides reusable workflows; [browser testing](./test-in-the-browser.md) connects these techniques to application sessions and rendered assertions.

<!-- Fenced tutorial executor: packages/cli/src/journeys/tutorial.ts. Execution scope is recorded separately. -->
