# Journey recipe reference

Journey recipes record one named path in one browser session. A terminal assertion can turn a route recording into a checked outcome, and each attempt writes an append-only local receipt whether it passes, fails, or errors.

The compatibility version remains `screenbranch.recipe.v0`.

## A checked journey

```json
{
  "schemaVersion": "screenbranch.recipe.v0",
  "journeys": [
    {
      "id": "checkout-v2",
      "title": "Complete the new checkout",
      "startRoute": "/cart",
      "steps": [
        {
          "targetRoute": "/checkout",
          "conditions": [
            {
              "kind": "access",
              "label": "signed in",
              "evidence": "declared"
            },
            {
              "kind": "feature-flag",
              "label": "new checkout enabled",
              "key": "checkout_v2",
              "value": true,
              "evidence": "declared"
            }
          ],
          "conditionLogic": "all",
          "trigger": { "role": "button", "name": "Checkout" }
        }
      ],
      "terminalAssertion": {
        "type": "visible-role",
        "role": "heading",
        "name": "Review your order"
      }
    }
  ]
}
```

Run it from the private checkout:

```bash
pnpm --filter @screenbranch/capture record /absolute/path/to/graph.json \
  --base-url http://127.0.0.1:3000 \
  --assets-dir /absolute/path/to/captures \
  --asset-prefix /captures \
  --out /absolute/path/to/graph.json \
  --recipe /absolute/path/to/journey.recipe.json \
  --receipts-dir /absolute/path/to/journey-runs
```

## Terminal assertions

The bounded assertion set is:

- `visible-text` with `text`;
- `visible-role` with an accessible `role` and exact `name`;
- `test-id` with `value`.

Reaching `targetRoute` proves navigation. A passing terminal assertion proves only that the named visible end condition held in that run. It does not prove accessibility, authorization, data integrity, or every alternate branch.

Recipes without a terminal assertion remain supported and are labeled `recorded-unverified`.

## Conditional relationships

Conditions explain why one edge exists. They do not execute a feature-flag provider or reproduce its targeting rules.

Supported condition kinds are `access`, `choice`, `feature-flag`, `experiment`, `data-state`, `environment`, and `other`. Up to four conditions can be joined with `conditionLogic: "all"` or `"any"`.

Use `evidence` honestly:

- `declared` means the recipe author supplied the condition;
- `observed` means runtime evidence established the exact value;
- `inferred` means Screenwalk or a person concluded it from indirect evidence.

For feature flags, record the resolved flag key and value when they are available. Do not copy a provider's full targeting context into the recipe or receipt: user identifiers, email addresses, tenant secrets, and reusable credentials stay outside Screenwalk artifacts.

One passing `checkout_v2 = true` receipt says nothing about the `false` branch. Record that context separately before calling both branches covered.

## A/B and variant QA

Put each materially different variant in its own named journey with its own condition value and terminal assertion. A QA matrix is covered only when both receipts pass:

```json
{
  "schemaVersion": "screenbranch.recipe.v0",
  "journeys": [
    {
      "id": "onboarding-a",
      "title": "Variant A: guided setup",
      "startRoute": "/onboarding",
      "steps": [{
        "targetRoute": "/onboarding/profile",
        "conditions": [{ "kind": "experiment", "label": "guided setup", "key": "onboarding", "value": "A", "evidence": "declared" }],
        "trigger": { "role": "button", "name": "Personalize" }
      }],
      "terminalAssertion": { "type": "visible-role", "role": "heading", "name": "Tell us about yourself" }
    },
    {
      "id": "onboarding-b",
      "title": "Variant B: skip setup",
      "startRoute": "/onboarding",
      "steps": [{
        "targetRoute": "/dashboard",
        "conditions": [{ "kind": "experiment", "label": "skip setup", "key": "onboarding", "value": "B", "evidence": "declared" }],
        "trigger": { "role": "button", "name": "Skip for now" }
      }],
      "terminalAssertion": { "type": "visible-role", "role": "heading", "name": "Dashboard" }
    }
  ]
}
```

Screenwalk records the variant a recipe declares; it does not configure the experiment provider. The setup or test environment remains responsible for making that variant active. Deliberately broken A and B recipes should also fail independently in certification so one passing side cannot hide a stale assertion on the other.

## Run receipts

Every attempt writes a `screenwalk.journey-run.v0` JSON receipt containing:

- recipe hash, journey, persona, viewport, and browser version;
- pass, fail, or error status;
- whether a terminal outcome was asserted;
- visited node and edge IDs;
- terminal assertion and result;
- declared branch conditions;
- local graph and screenshot paths;
- a nullable trace path reserved for a later explicit trace integration.

Repeated runs use unique run IDs and append new receipt files, even when the recipe content is unchanged.

Screenwalk does not capture a Playwright trace implicitly. The current slice keeps receipts small and avoids silently persisting DOM, network, storage, or credential-bearing trace data.
