# Recipes

Use the smallest durable layer that proves the task:

1. call an existing action;
2. compose existing recipes;
3. write a task-local recipe;
4. use a verified controller or CDP path when no stable action exists.

Discover before authoring:

```bash
mm-harness actions <intent>
mm-harness actions --action <name>
mm-harness run --list
mm-harness run <name> --describe
```

Discovery reports parameters, selected adapter variant, nested recipes, source,
and shadows. Use `--json` for exact metadata.

## Author and run

An action performs one typed operation. A recipe owns a reusable graph or a
task proof and may call other recipes.

```json
{
  "$schema": "https://farmslot.io/schemas/recipe-v1.schema.json",
  "title": "Wallet readiness",
  "description": "Proves the running wallet is reachable and unlocked.",
  "paramsSchema": {
    "type": "object",
    "properties": {
      "account": { "type": "string", "default": "Account 1" }
    },
    "additionalProperties": false
  },
  "workflow": {
    "entry": "unlock",
    "nodes": {
      "unlock": {
        "action": "metamask.wallet.ensure_unlocked",
        "intent": "Make the fixture-backed wallet ready for use",
        "next": "done"
      },
      "done": { "action": "end", "status": "pass" }
    }
  }
}
```

Defaults are applied before validation. Root values use `key=value`; a nested
recipe call uses `action: "call"`, `ref`, and `params`.

```bash
mm-harness run recipe.json account="Account 2" --plan
mm-harness run recipe.json account="Account 2"
```

Use the shared wallet setup recipe on either Mobile or Extension. `auto`
reuses a ready fixture-backed profile and otherwise completes visible
onboarding. On Extension, `ui` completes fresh visible onboarding or visibly
unlocks and proves/selects the exact derived account in an existing session.
On Mobile, `ui` requires fresh onboarding.

```bash
mm-harness run wallet.import method=auto
mm-harness run wallet.import method=ui credential_source=environment
mm-harness run wallet.import method=ui metametrics=true 'interests=["trade_perpetuals"]'
```

The UI path reads the primary mnemonic from `MM_HARNESS_WALLET_SRP` and the
password from `MM_HARNESS_WALLET_PASSWORD`, or from the canonical wallet
fixture. Secret values are redacted from commands and evidence. Visible imports
default to MetaMetrics off and skip Mobile's optional interests; password terms
are required and always accepted by the action.

### Extension Perps release recipes

Discover these identifiers with `run --list --adapter extension --json` and
inspect the exact graph with `run <id> --describe --adapter extension --json`:

| Behavior | Canonical recipe |
| --- | --- |
| Activity filter routes | `perps.release-activity-filters` |
| Deposit and withdraw previews without submission | `perps.release-funds-flows` |
| Resting limit placement and exact cancellation | `perps.release-live-limit-order` |
| Filled market placement and exact position close | `perps.release-live-market-order` |
| Market header and statistics | `perps.release-market-details` |
| Market categories | `perps.release-market-filters` |
| Market text search | `perps.release-market-search` |
| Long/Short and Market/Limit entry controls | `perps.release-order-entry` |
| Amount, leverage, keyboard, auto-close, and TP/SL validation | `perps.release-order-validation` |
| Official-build rendered market/activity consistency | `perps.release-visible-consistency` |
| Favorite persistence and cleanup | `perps.release-watchlist` |
| Hook-backed controller snapshot consistency | `perps.source-dev-snapshot-consistency` |

The source-development snapshot recipe is compatibility evidence only and must
not support an official artifact verdict. Activity and funds recipes are
Extension-scoped because their semantic actions are not shared release
capabilities. Keep ticket-specific orchestration task-local and compose these
identifiers with `call` instead of copying their graphs.

Order-entry and order-validation callers must supply a market with no existing
position; the product exposes Modify/Close instead of New Long/Short for an
already-open market. Source-development snapshot callers may opt into a
positive `minimum_changed_market_count`; the default does not require a price
tick, while typed-history and visible-activity agreement remain strict.

The two live recipes require explicit `confirm_live=true`. The trusted runner
must also verify the exact consented funding request, preflight, release proof,
and contained balance proof. Market placement declares the exact provider and
network; background placement and cancellation refuse a mismatch without
toggling it. Immediately before publication and dispatch, the action also reads
the current visible Perps Home balance and requires the runner-trusted minimum.
The release onboarding session proves artifact, wallet, and origin provenance;
the fresh balance trace identifies the execution session, so a legitimate
release-artifact relaunch does not claim false same-session continuity. The
runner revalidates the current artifact tree and owned CDP profile, persists the
pre-dispatch receipt, and finishes receipt-bound cleanup and reconciliation. A
known-not-dispatched receipt is terminal and requires fresh consent and a new
claim. Selecting or resetting an account, changing its lock/setup session, or
using a generic UI press invalidates the cached identity proof; a fresh visible
`wallet.import` proof is required before another external mutation. Extension
`ensure_positions`, `ensure_orders`, and `teardown_state` only observe and assert
state that already exists; their schemas reject creation and cleanup inputs.
Extension does not expose `start_state`, readiness claims, multi-position
background closure, or the mutating `runner.action-validation` recipe. Financial
transitions must use an explicitly funded leaf action.
The shared `perps.clean-market-testnet` convergence recipe is therefore Mobile-
only: Extension discovery omits it and a direct Extension plan fails statically.
Planning or calling a recipe never weakens those gates.

### Extension submission boundary

Extension currently exposes read-only Assets and Swap/Bridge evidence plus send
preparation/review, quote, Max, and slippage actions. It does not expose
`metamask.assets.finish_send`, `metamask.swap_bridge.submit_transaction`, or
generic `ui.activate_and_observe`. Those operations remain unavailable until a
domain-specific funding policy and durable pre-dispatch receipt/recovery
contract exists. The four former Assets submit recipes are not shipped.

The shared live Swap recipes remain available to Mobile, whose manifest owns a
separate native submission action. Extension `run --list` omits those recipes,
and a direct Extension plan fails statically. Extension quote and visible-state
recipes remain discoverable and plan normally; generic pointer activation is
not a substitute for a funded financial leaf.

To prove the full real-user recovery journey, delete the current wallet through
visible client UI and import it again:

```bash
mm-harness run wallet.reset-import credential_source=fixture
```

For fixture-backed development clients, `mm-harness fixtures reset` performs a
clean reset and reapplies the canonical fixture. Extension resets its owned
Chrome profile; Mobile clears only the selected app's data, preserves the
installed build, relaunches it, and then applies the fixture. Use
`wallet.reset-import` when the reset itself must be exercised through visible UI.

### Mobile device targeting

Always pass `--device <name|udid|serial>` when more than one simulator/device may
be connected. That pin:

1. Sets `IOS_SIMULATOR` / `ADB_SERIAL` for the run.
2. Rewrites the checkout `agentic-runtime.json` simulator/serial so the next
   `resolveSlotPorts` does not revive a stale pin from another PR or slot.

Do **not** shut down other connected devices to "force" selection — selection is
by `--device`, not by exclusive boot.

For visual PR proof, prefer a short simulator recording or GIF over still
screenshots when the claim is a UI flow (timing / transitions). Use screenshots
as supporting stills.

### Perps loading lifecycle validation

One platform-neutral recipe owns the reusable Perps lifecycle proof. The
harness adapter supplies Android or iOS behavior; the graph and lifecycle
parameters remain identical. Run it with an explicit device pin:

```bash
mm-harness run perps.performance \
  --device <android-serial-or-ios-udid> \
  account=<fixture-account-name> \
  content_variant=trending \
  market=BTC \
  lifecycle=cold_no_cache \
  --heal off --record-video=full-run
```

The Mobile recipe HUD is shown by default, including during performance
validation. Use `--hud hide` only when a specific opaque/release proof requires
an unobstructed product surface; do not hide it merely to collect timings.

Supported lifecycle values are `navigate_return`, `cold_disk_cache`,
`cold_no_cache`, `background_short`, `background_reconnect`, `account_switch`,
and `network_switch`. The shared graph uses an existing fixture position and
never fabricates exchange state inside the measurement. It proves native
visible content with `ui.wait_for`, captures production `[PerpsLoadProof]` and
WebSocket milestones, and leaves detailed TTC/DFD to the app's Sentry traces.
It never relabels Metro, fixture, or process-start duration as TTC.
The recipe does not label a checkout as main or candidate; pin and record the
exact checkout commit externally, then use captured source milestones to verify
which data path actually ran.

Rules:

- Validate with `--plan` before side effects.
- Use real product paths; never mutate hidden state to fabricate proof.
- Prove preparation with an independent read/assert or visible UI postcondition.
- Keep ticket-specific claims in task-local recipes.
- Compose, repair, or parameterize repeated behavior instead of multiplying names.
- Keep secrets out of recipes, libraries, and evidence.
- Limit claims to the boundary actually exercised. In-app navigation cannot
  prove external ingress, and security-boundary proofs require accepted and
  rejected cases.

## Classify failures before changing either layer

Recipes are maintained proof assets, not immutable descriptions of the app.
Locators, labels, routes, and screen structure can legitimately change, so a
failed recipe is not by itself evidence of either recipe drift or a product
regression.

1. Reproduce the failing node and compare it with authoritative acceptance
   criteria, product contracts, or known-good evidence.
2. Inspect the current product surface and resolved recipe source, then classify
   the cause as product regression, recipe drift, fixture/runtime drift, or
   harness defect.
3. If an accepted product change establishes recipe drift, repair the smallest
   shared action or recipe node that owns it. Otherwise preserve the failure
   and fix or report the owning product, runtime, or harness layer.
4. Rerun the repaired path and every shared recipe that composes it.
5. Report the classification, owning source, change, and fresh evidence together.

Do not duplicate a stale recipe to avoid maintaining it. Do not change product
code merely to satisfy an obsolete proof path, or update a recipe merely to
make a real regression pass.

Keep responsibilities narrow:

- **Parameters** expose caller choices that may vary without changing the
  journey's meaning.
- **Recipes** compose actions and own journey order, safe defaults, invariants,
  and proof.
- **Actions** translate one stable operation to existing UI, CDP, or controller
  capabilities; they do not reimplement product business logic.
- **Product/controllers** remain the source of truth for state transitions,
  validation, transactions, and domain behavior.

If changing a value would violate the recipe's postcondition, keep it as a
documented recipe invariant rather than a parameter. Add a shared action only
when repeated direct access has a stable cross-task contract.

The protocol is authoritative:
<https://farmslot.io/docs/reference/recipe-protocol-v1>.

## Capture network requests

Use `app.network_capture` start/end nodes to record redacted HTTP requests made
inside one Mobile or Extension recipe window, then a separate
`app.network_assert` node when the recipe needs self-checking evidence. Every
live recipe also indexes a bounded metadata-only run summary with node-boundary
events. The result distinguishes complete, partial, and unavailable evidence
so a target rotation cannot be misreported as zero requests. See
[Recipe-scoped network capture](NETWORK-CAPTURE.md).

## Capture UI smoothness

Use explicit `app.performance_capture` start/end nodes to correlate Mobile or
Extension CDP trace samples with recipe-node boundaries.
`app.performance_assert` checks the resulting evidence contract. Capture is
not automatic; see [UI smoothness capture](PERFORMANCE-CAPTURE.md).

## Share a library

```text
team-recipes/
  manifests/extension.action-manifest.json
  actions/extension/wallet/ensure_ready.mjs
  recipes/extension/onboarding/smoke.recipe.json
```

```bash
export RECIPE_LIBRARY_PATH="wallet=$HOME/shared-library/wallet-team"
mm-harness run --list
mm-harness run onboarding.smoke --describe
mm-harness run onboarding.smoke --plan
```

Use `--library wallet=/path/to/library` for one command. The alias is the
source name; without one, the directory name is used. Resolution follows the
explicit library order, then bundled MetaMask. Adapter-specific variants are
selected deterministically from `recipes/<adapter>/<domain>/`. Legacy
`*.<adapter>.recipe.json` paths remain readable during migration, but new and
migrated libraries use the adapter-first layout. A file cannot declare its
adapter through both forms. Every run records the root recipe, exact resolved
dependency documents, their digests, call edges, selected sources, and shadows.

## Direct product access

The bundled library is intentionally small. A task may use a verified controller
or CDP path when that is clearer than adding a permanent wrapper. Confirm the
current source path, mutation risk, preconditions, independent postcondition,
and redaction. Do not infer route or controller names from memory. Repeated team
behavior belongs in a reviewed team recipe; only broadly reusable stable
capabilities belong in the bundled library.

Mobile and Extension share vocabulary where the product supports it. Core is
headless and must not fabricate UI state. Inspect the current surface:

```bash
mm-harness actions --category wallet --json
mm-harness actions --category perps --json
mm-harness run --list --json
```

See [Security](SECURITY.md) before enabling custom executable actions.
