# Connect Scenarios across Personas

Use `dependencies` when reusable Scenarios need to cooperate: A submits a
receipt, B processes that exact receipt, then A checks its result. Define waits
inside the receiving Scenario. Run either connected Scenario normally; Verify
includes the whole connected journey. No separate Run Plan definition is needed.

Read this guide offline without installing the skill:

```sh
com skills get --topic scenario-dependencies
```

Use version 1 files for one Persona per Scenario. Version 2 named actors are
useful when one Scenario itself needs several actors; both formats accept
`dependencies`. Keep unrelated journeys independent.

## Attached files

A connected journey can contain up to 100 distinct attached files across its
Scenarios, totaling at most 100 MiB (25 MiB per file). Fixture names must be
distinct across the journey unless they reference the same content. Identical
fixture entries shared by multiple Scenarios count once.

## Dependency fields

```yaml
dependencies:
  - scenario_id: ./submit-receipt.yaml
    after_step: 1
    before_step: 2
    name: Receipt processed
```

| Field | Meaning |
| --- | --- |
| `scenario_id` | A saved `scenario_…` ID in this Project, or `./relative-file.yaml` (`.yml` also works) within the submitted batch, relative to this file. Display names and retry `key` values are not references. |
| `after_step` | The producer's numbered authored step that must complete. |
| `before_step` | This file's numbered authored step that waits. Use `1` to wait before its first step. |
| `name` | Optional readable handoff label, up to 80 characters. |

Steps start at **1**. Count only entries in each source file's `steps`, including
explicit authored authentication steps; do not count inferred sign-in, outcomes
or cleanup. Reordering steps changes the checkpoints' meaning: review every
affected dependency. A wait releases when its checkpoint completes in the same
run, rather than when the producer's final outcomes pass. Every Scenario's
outcomes still need to pass.

Omitting `dependencies` on upload preserves saved connections. Use
`dependencies: []` to clear them; `null` is invalid. Download before editing so
you retain the existing `id`, `key`, and `version`.

Paths resolve relative to the referring file: `./process.yaml` is a sibling,
`./other/process.yaml` is in a subdirectory, and `./../process.yaml` is in the
parent. They must name one unambiguous file included in the same request. The
server never reads filesystem paths or fetches URLs. Rename references when you
rename files; filenames are local aliases, while saved links use stable IDs.
Download prefers relative filenames for exported dependencies, respecting existing
local filenames. It retains IDs for unavailable targets or unsupported filenames.
Use Composal CLI 1.17.99 or later for file-reference lint and download support.

For MCP, put the location in each submitted file object's `path`, for example
`path: scenarios/submit-receipt.yaml`. `verify_save_tests` receives these objects
in `scenarios`; `verify_prepare_run` receives them in `scenario_files`. The CLI
supplies this metadata automatically. Do not add `path` to the YAML contents:
it belongs to the upload envelope, and referenced files must be included there.

## Create a receipt handoff

Use an authorized Website Environment and two existing Personas, `Submitter`
and `Processor`, assigned to separate test accounts. Store credentials through
the Project's credential workflow, never in YAML. The example assumes the app
itself requests `/api/session` after sign-in and receives
`{"user":{"id":"stable-user-id","email":"assigned-account-email"}}`.
Replace that contract with the actual application's observed endpoint and JSON
pointers. The runner observes the app's authenticated exchange; declaring a
probe does not make it issue a guessed identity request.

1. Download the Project and existing Scenarios:

   ```sh
   com verify scenarios download --org acme --project receipts --dir scenarios
   ```

2. Create both files below with their `dependencies` intact. Relative filenames
   let you connect new files before they have saved IDs. Lint, dry-run and upload
   the whole directory together:

   ```sh
   com verify scenarios lint scenarios --json
   com verify scenarios upload --dir scenarios --org acme --dry-run --json
   com verify scenarios upload --dir scenarios --org acme --json
   ```

   Upload writes `id`, `key` and `version` into each file and retains your file
   references. The server resolves references to real IDs and validates the
   final combined graph atomically, including steps changed by this upload.
   Dry-run saves no Scenarios; attached fixture bytes may still upload.

3. Preserve the generated metadata when editing. Include every referenced file
   in each upload or file-run request, even when it is unchanged. To reference a
   saved Scenario without submitting its file, use its returned `scenario_…` ID.

`scenarios/submit-receipt.yaml`:

```yaml
# yaml-language-server: $schema=https://composal.ai/schema/verify/v1/scenario.json
$schema: https://composal.ai/schema/verify/v1/scenario.json
name: A submitter can see their receipt processed
labels: [receipts, receipt-handoff]
persona: Submitter
allowed_actions: writes
starting_conditions: Authorized disposable receipt workspace, initially empty.
identity_probe:
  path: /api/session
  subject_pointer: /user/id
  email_pointer: /user/email
dependencies:
  - scenario_id: ./process-receipt.yaml
    after_step: 2
    before_step: 2
    name: Processing finished
steps:
  - Submit one fresh receipt; retain its exact generated ID and name.
  - Refresh receipts; find that same ID and unchanged name showing Processed.
outcomes:
  - The original receipt's unchanged ID and name appear with status Processed.
cleanup:
  - Delete only this run's receipt; refresh and verify its removal.
```

`scenarios/process-receipt.yaml`:

```yaml
# yaml-language-server: $schema=https://composal.ai/schema/verify/v1/scenario.json
$schema: https://composal.ai/schema/verify/v1/scenario.json
name: A processor can process a submitted receipt
labels: [receipts, receipt-handoff]
persona: Processor
allowed_actions: writes
starting_conditions: Authorized access to the submitter's disposable receipt workspace.
identity_probe:
  path: /api/session
  subject_pointer: /user/id
  email_pointer: /user/email
dependencies:
  - scenario_id: ./submit-receipt.yaml
    after_step: 1
    before_step: 1
    name: Receipt submitted
steps:
  - Refresh receipts; find the exact handed-off ID and name showing Submitted.
  - Process that exact receipt once; verify its status becomes Processed.
outcomes:
  - Processing the handed-off receipt changes its status to Processed.
```

The resulting order is **A1 → B1 → B2 → A2**. The Scenario references point in
both directions, but their step checkpoints do not form a cycle. Making A1 wait
for B2 while B1 waits for A1 would deadlock and is refused.

Both files use the same identity contract so either can start the journey.
For multiple signed-in Personas, provide `identity_probe` on the launching
Scenario or one consistent probe inherited from connected sources. Personas
retain separate browser sessions; returning to A resumes A's original session.
The same Persona across connected Scenarios shares its actor session. Do not
simulate separate people by changing credentials inside one Persona.

When all sources are narrative Scenarios for one Persona without Account
Verification, their original steps run in one browser session, without an extra
sign-in step. This preserves an authored login prerequisite. Explicit named
actors retain their authentication boundaries.

Carry the exact generated record ID, name or URL through the handoff. A matching
replacement record is not evidence of cooperation. Outcomes belong to each
source Scenario's Persona: A checks its own final view, while B's outcome proves
B's processing. Asking A's private evidence to prove B's action is inconclusive.
For an explicitly joint outcome within one version 2 Scenario, list its owning
actors in `outcomes[].actors`.

## Run and assess the connected journey

After upload, run the saved files without further edits:

```sh
com verify scenarios run scenarios/submit-receipt.yaml scenarios/process-receipt.yaml --org acme --project receipts --environment staging --concurrency 1 --wait
com verify runs get <returned-run-id> --org acme --project receipts --diagnostics
```

Use the actual Project and Environment. File references must resolve within the
selected files. All linked files must match saved definitions before running;
upload edited files together first. Dispatching a saved Scenario by ID includes
incoming and outgoing connections without needing local files.
With `--label`, the CLI selects matching roots and includes referenced files
from the supplied inputs even when those files have different labels. Selecting
several members deduplicates the connected journey. Dependencies can
therefore expand a label selection; review all included definitions and access
before launch. Connected steps execute in checkpoint order in one coordinated
browser attempt; concurrency 1 is sufficient. This does not promise simultaneous
foreground actions. Each Persona's session and background activity are retained.

Prepared runs pin every connected source's version, access and Environment.
If definitions or connections change, prepare and review a fresh run. An older
attempt cannot release a new run's wait. See [Tests](https://composal.ai/skills/composal-tests.md) for separate
prepare/review/launch commands and exact-version reruns.

Inspect both source Scenarios' outcomes and actor-owned evidence. Confirm the
same record reached B and returned to A. Report the test verdict separately
from `application_cleanup_state`; a passed journey can have incomplete cleanup.
Do not turn an audit log or an agent's deletion claim into a passing browser
cleanup checkpoint. Keep failed attempts and investigate product, access,
fixture, runner or evidence blockers before retrying changed definitions.

## Select a connected journey automatically

Add `on.pull_request` or `on.schedule` to a member that
should select the journey; see [event rules and schedules](https://composal.ai/skills/composal-scenarios.md#event-rules-and-schedules).
Its connected members join that run even if their own event rules do not match
or they declare `on: {}`. Set the root's condition to allow every intended event;
a PR-author-only condition will not match cron, whose PR metadata is null.

For a manual run, dispatch a member by ID; connected dependencies join without
any dispatch event declaration or matching condition.

For one timed connected journey, put the cron entry on one root. Giving each
member its own cron creates separate timers, not a shared schedule. Within each
Run, connected members are deduplicated; independent timer occurrences remain
separate runs. Review the full target access and recurring mutation scope before
activating a root. Qualify the resulting occurrence and each Persona's evidence
using [Tests](https://composal.ai/skills/composal-tests.md#qualify-dependencies-and-automatic-selection).

## Limits and refusals

- Website Scenarios only; Messages journeys are unsupported here.
- Up to 20 connected Scenarios, 4 Personas, 100 handoffs and 100 executed steps,
  including inferred sign-in steps.
- The referenced Scenario must remain available in the same Project. Self
  dependencies, duplicate edges, missing checkpoints and step deadlocks fail
  validation. Lint checks file shape offline; dry-run checks the actual graph.
- Dependencies order work; they do not grant target access, create accounts,
  add permitted Environment origins or waive write authorization.
- Signup in a connected journey needs a named actor and an explicit complete
  `authentication: true` step. Narrative signup remains usable on its own.
- Cleanup is deferred until the connected journey is attempted, then follows
  reverse Scenario completion order so a producer does not delete data a
  consumer still needs. Missing access or a lost browser can leave it incomplete.

The public [v1 schema](https://composal.ai/schema/verify/v1/scenario.json) and
[v2 schema](https://composal.ai/schema/verify/v2/scenario.json) describe the YAML
fields. Use a CLI that preserves `dependencies` and `identity_probe` in both
formats; retain downloaded metadata and fields when reconciling older clients.
