# Task26 Golden Path: candidate 2e0894ea same-actor live rehearsal

This runbook is the executor-facing Golden Path for the amended Task26 same-actor
live rehearsal. It's an append-only artifact. Never edit it in place; corrections
ship as new files that supersede this one.

## 0. Binding and supersession

| Binding | Value |
|---|---|
| Candidate full digest | `2e0894eac92bc396cc4723bf1f18ebc653b95018dd41574df435941c235da925` |
| Wheel SHA-256 | `af4a9d0a1ffffb6eb7551c1d6dc2b32853ca6d024332a4f8f5702bbf992f141b` |
| Amended plan SHA-256 | `7ace03c6dad33d2fc3ef223621cbca68a150fde8429932138e252fb8498ac582` |
| Amended plan path | `.omo/plans/dualcoach-production-readiness.md` |
| Rehearsal customer actor (Telegram user) | `8527916639` (reused only as a new logical lifecycle) |
| Owner / operator (Telegram user) | `8693203710` |
| Bot username | `dual_coach_pilot_test_bot` |
| Customer bot | dedicated, per `separate_bot.dedicated: true` |
| Service | `hermes-gateway-dualcoachtest.service` (systemd user unit) |
| Unit file | `/home/cube/.config/systemd/user/hermes-gateway-dualcoachtest.service`, SHA-256 `0b46e887fc12c45f12814f4ef025c10101ed36e5df0ac35f70abb1862c0c1db2` |
| Profile root | `/home/cube/.hermes/profiles/dualcoachtest` |
| Venv python | `/home/cube/projects/richard/hermes-agent/.venv/bin/python` |
| Sealed wheel | `.omo/evidence/task26/task26-repaired-archive-successor-2e0894eac92bc396cc4723bf1f18ebc653b95018dd41574df435941c235da925/artifacts/hermes_agent-0.17.0-py3-none-any.whl` |
| Sealed candidate verifier | `.omo/evidence/task26/task26-repaired-archive-successor-2e0894eac92bc396cc4723bf1f18ebc653b95018dd41574df435941c235da925/verify_candidate.py` (exit `2` = PASS) |

Telegram routes (from `config.yaml` extra, SHA-256 `f93106b16643227e2ef9dec67a5bbd497e1d353e779da62287898a087071af87`
at authoring time): staff review group `-1004484458766` topic `59`, onboarding
preview topic `219`, operator card route = owner DM `8693203710` topic `0`.

**Supersession.** For this rehearsal, this runbook and its companion
`task26-recovery-runbook-2e0894ea.md` supersede every candidate-`19ed0e9232e240553b9a96a2e6a33d10f1096be49e5ebafc019287d75984e45c`
reference, specifically:

- `.omo/evidence/dualcoach-golden-path-contract.md` (SHA-256 `32a379d855c6e5af978bd9886e3bf49c616c7c20f1c1d5f100c19d8adfc5eb4a`)
- `.omo/evidence/dualcoach-recovery-runbook.md` (SHA-256 `ae2f5f9046c06f8f0b42693be5aa0d9c31cada8024ae1e5ab8ba19a3cf10f6fc`)

Both files stay on disk byte-identical as history. Their `dualcoach_admin`
"planned interface" commands (`process-state`, `generation reconcile`,
`callback inspect`, `card rebuild`, `updates reconcile`, `outbox reconcile`,
`customer disable`) do not exist in candidate `2e0894ea`. The only
`dualcoach_admin` subcommand this candidate ships is `provider-auth check`.
Any step that can't be served by a command cited here is a named blocker in
Section 1, not an improvisation slot.

**Authority.** Ledger event `same-actor-live-rehearsal-authorized`
(`data/onboarding/telegram-customer-bootstrap-v1/ledger.jsonl`, 2026-08-15T11:55:24Z)
authorizes exactly: one authenticated archive-first pre-reset, exact-candidate
wheel deployment and service rebind, exactly one new bootstrap invite, one
private-DM Start by the rehearsal actor (`8527916639`), the synthetic
lifecycle actions, exactly one delivery after explicit send, final disable, and one authenticated archive-first
cleanup reset. It forbids: archive restore or prepopulation, direct durable-state
mutation, raw Telegram listener or update-cursor edits, service replay, forced
card publication, recovery shortcuts, real-customer activation, historical
evidence retargeting, unrelated profile changes, and any commit, push, release,
publish, register, or tag action.

## 1. Fail-closed preflight

Run every gate top to bottom. First failure stops the rehearsal; there is no
skip. Commands are read-only unless marked otherwise. Quoted paths are exact;
the space in `traning coach` is part of the path.

| Gate | Check | Exact command | Pass criteria | Status at authoring |
|---|---|---|---|---|
| G1 | Candidate archive integrity | `python3 ".omo/evidence/task26/task26-repaired-archive-successor-2e0894eac92bc396cc4723bf1f18ebc653b95018dd41574df435941c235da925/verify_candidate.py" ".omo/evidence/task26/task26-repaired-archive-successor-2e0894eac92bc396cc4723bf1f18ebc653b95018dd41574df435941c235da925"` | exit `2` | PASS (evidenced) |
| G2 | Plan hash | `sha256sum .omo/plans/dualcoach-production-readiness.md` | `7ace03c6dad33d2fc3ef223621cbca68a150fde8429932138e252fb8498ac582` | PASS |
| G3 | Ledger authority | read `ledger.jsonl` for `same-actor-live-rehearsal-authorized` | event present, authorized/forbidden lists match Section 0 | PASS (line 128) |
| G4 | Unit file | `sha256sum /home/cube/.config/systemd/user/hermes-gateway-dualcoachtest.service` | `0b46e887fc12c45f12814f4ef025c10101ed36e5df0ac35f70abb1862c0c1db2` | PASS |
| G5 | Profile package pins | `sha256sum` the five pinned files under `/home/cube/.hermes/profiles/dualcoachtest/workspace/checkin_cli/checkin_cli/` | `__init__.py`=`86f08e36d16a8455f607f5361d73ce4fa342e113b96c0b97b5cbc4c05cc6f2f5`, `nutrition_onboarding_models.py`=`a85d7666e31e51f2972b43473c1fdd26f6cb0b9d4b5a39f5ce726a8a346f09bf60`, `nutrition_onboarding_store.py`=`b6bbdc4bb4a47583b321d46d822f18c8274e3d0f8dc54544ae52292315c477637b`, `nutrition_readiness.py`=`488e2e446f70f2c8c2fd6ca901b8d5e9ee4b4b4684cc26f231ad9b50f4b57853ea`, `nutrition_onboarding.py`=`a7cf67137b7bfa78804880a55b04fb9f5ff1d5fd781c20077dc79b9e6bd0359c93` | PASS |
| G6 | Other profiles pinned | snapshot every profile under `/home/cube/.hermes/profiles` except `dualcoachtest` | digests equal the pins captured at rehearsal start; known pins: `physique-coach` `e04e3a0a13a73bd7cf2259898e3c9198e5860a4a468a5342c7b0b537a4a19e1e`, `quarantine` `9ec0b0f3251f944d9d89a4b6cc3e5a45e15025b52d3a5c0d6a60ea04fa1dc031` | PASS (re-verify at run time) |
| G7 | Provider auth | `/home/cube/projects/richard/hermes-agent/.venv/bin/dualcoach_admin provider-auth check --json` | per-provider `ready`; for `openai-codex` this needs the billable active probe: rerun with `--allow-billable-active-probe` only after explicit human authorization at rehearsal time. Receipts land in `/home/cube/.hermes/profiles/dualcoachtest/data/dualcoach-provider-auth`; those receipt writes are the only profile mutation this command may make | **OPEN (B3)** |
| G8 | Lock disposition | `flock -n /home/cube/.hermes/profiles/dualcoachtest/gateway.lock true` plus confirm no live process holds the lock PID | no active holder; stale lock cleared only inside the sealed reset scope (G10). Never `rm` the lock by hand | **OPEN (B1)** (stale lock, dead PID `4091167`) |
| G9 | Service inactive pre-run | `systemctl --user is-active hermes-gateway-dualcoachtest.service` | `inactive` or `failed` before the controlled start in Section 5 | PASS (inactive/dead since 13:47 KST 2026-08-15) |
| G10 | Sealed reset artifact | inspect the sealed reset controller tree (sibling lane `st_01a0054d`) | sealed (0400/0500, single-link), schema contract + permission receipt binding candidate `2e0894ea...`, wheel `af4a9d0a...`, plan `7ace03c6...`; scope covers `data/onboarding/telegram-customer-bootstrap-v1` and `gateway.lock`; dry-run receipt PASS and verify receipt PASS for run IDs recorded in the permission receipt | **OPEN (B2)** |
| G11 | Predecessor archive verification | sealed verifier over all five archives in `data/rehearsal-reset-archives/` (schemas `task25-rehearsal-reset-archive-v1`, `task25-rehearsal-reset-execute-v2`, `task26-rehearsal-reset-archive-v1`, `task26-rehearsal-reset-archive-v2`) | one PASS receipt per archive, all five, fresh | **OPEN (B5)** |
| G12 | Invite preparation harness | inspect the sealed one-use preparation harness for candidate `2e0894ea` | sealed; calls only `RoomBootstrapStore.prepare_rehearsal_customer_invite`; binds candidate/wheel/plan digests; writes a 0600 receipt matching the schema of `task26-canonical-invite-preparation-5e6f2f2a.../preparation-receipt.json` | **OPEN** (arm lane `st_01a00547` holds `commands.invite: null` until blockers close) |
| G13 | Evidence hygiene | `stat -c '%a' <dir>` on the evidence dir for this run | directories `0700`, files `0600`; no plaintext token outside a 0600 receipt | required at run time |
| G14 | Installed-wheel baseline | read `/home/cube/projects/richard/hermes-agent/.venv/lib/python3.12/site-packages/hermes_agent-0.17.0.dist-info/direct_url.json` | digest recorded as the pre-rebind baseline (currently `6a3f5f04a2982658f1c334273b05ae958b0353470997fc8df143c5b1fe12cbeb`, predecessor lineage) | PASS (baseline captured) |

Preflight receipt: write `preflight-receipt.redacted.json` (0600) in the run's
evidence dir with every gate id, command, observed value, and PASS/OPEN. The
receipt mirrors schema `task26-same-actor-preflight-v2` used by lane
`st_01a00547`. Rehearsal continues only when every gate reads PASS.

## 2. Archive-first pre-reset

Executable only after G7, G8, G10, and G11 are PASS. Uses the sealed reset
controller (G10). Interface, quoted from the sealed contract source:

```
reset_controller.py <mode> \
  --profile /home/cube/.hermes/profiles/dualcoachtest \
  --other-profile /home/cube/.hermes/profiles/physique-coach \
  --archive-root /home/cube/.hermes/profiles/dualcoachtest/data/rehearsal-reset-archives \
  --archive <new archive dir> \
  --contract <sealed schema-contract path> \
  --permission <sealed permission receipt> \
  --candidate 2e0894eac92bc396cc4723bf1f18ebc653b95018dd41574df435941c235da925 \
  --wheel-sha256 af4a9d0a1ffffb6eb7551c1d6dc2b32853ca6d024332a4f8f5702bbf992f141b \
  --plan-sha256 7ace03c6dad33d2fc3ef223621cbca68a150fde8429932138e252fb8498ac582 \
  --approval <one-use approval receipt for this run> \
  --run-id <fresh run id>
```

Modes run in order: `dry-run` (PASS required), `verify` (PASS required),
`execute`. Expected cleared scope includes `data/owner`, `customers`,
`data/checkin-events`, `data/checkin-index`, `data/checkin-claims`,
`data/onboarding` (which contains `telegram-customer-bootstrap-v1`),
`data/rehearsal-surface`, `data/dualcoach-provider-auth`, `gateway.lock`.
Expected preserved scope: `config.yaml`, `sessions`, `state`, `secrets`,
`gateway-credentials`, `logs`, and `data/rehearsal-reset-archives` itself.

Archive-first means: the archive copy and its manifest verification complete
before any clear runs. No restore, ever. Post-reset expectation: registry has
zero customers, bootstrap ledger absent, `gateway.lock` absent, service
inactive. Write `pre-reset-receipt.json` (0600) with archive path, archive
manifest SHA-256, cleared and preserved lists, and before/after digests.

## 3. Sealed wheel deployment and service rebind with loaded-byte proof

The service stays stopped through this section. Commands (deployment write,
authorized):

```
/home/cube/projects/richard/hermes-agent/.venv/bin/python -m pip \
  --disable-pip-version-check install --no-deps --no-index --force-reinstall \
  ".omo/evidence/task26/task26-repaired-archive-successor-2e0894eac92bc396cc4723bf1f18ebc653b95018dd41574df435941c235da925/artifacts/hermes_agent-0.17.0-py3-none-any.whl"
```

Loaded-byte proof (read-only, run with the venv python and `-B`):

1. `direct_url.json` in `hermes_agent-0.17.0.dist-info` carries
   `archive_info.hashes.sha256 == af4a9d0a1ffffb6eb7551c1d6dc2b32853ca6d024332a4f8f5702bbf992f141b`.
2. Import `gateway.platforms.telegram`, `gateway.platforms.telegram_customer_bootstrap`,
   `gateway.platforms.telegram_customer_bootstrap_registration`,
   `gateway.platforms.telegram_nutrition_onboarding_runtime`,
   `gateway.platforms.telegram_nutrition_onboarding_runtime_callback`,
   `gateway.platforms.nutrition_coaching`, `hermes_cli.dualcoach_admin`,
   `hermes_cli.gateway`, `gateway.run` in a fresh `-B` process; resolve each
   module's `__file__`; SHA-256 every loaded file; compare against the byte
   digests recorded by unzipping the sealed wheel (or the candidate manifest's
   executable closure). All nine must match.
3. Entry points present: `dualcoach_admin`, `hermes`, `hermes-agent`,
   `dualcoach_tasks21_25_controller` under `.venv/bin`, each resolving into the
   freshly installed package.

Write `deployment-rebind-receipt.json` (0600): before/after `direct_url.json`
digests, the nine module digests, entry-point list, pip exit code.

## 4. Observer subscriptions before any lifecycle action

No human action fires before its observer is armed and has written a watch-ready
receipt. Pattern evidenced by `task26-fresh-canonical-invite-20260815T040558Z/gateway_start_observer.py`
and `claim_watcher.py`: `inotify` on the parent directory, watch-ready receipt
first, then the trigger, then event-driven capture with a bounded timeout.
Forbidden: fixed sleeps, polling loops, unbounded waits.

Watch set (all under the profile root):

| Observer | Path | First event expected |
|---|---|---|
| Bootstrap ledger | `data/onboarding/telegram-customer-bootstrap-v1/ledger.json` (and `.jsonl`) | new session `PREPARED` (post-invite) |
| Registry | `customers/registry.json` | one customer row, `enabled: false` |
| Onboarding customer dir | `data/onboarding/<customer_key>/` | revision 1, state `collecting` |
| Owner actions | `data/owner/draft-*.json`, `data/owner/nutrition-*.jsonl` | generation request after check-in |
| Deliveries | `data/owner/draft-deliveries.json` | exactly one row, terminal `sent_audited` |
| Gateway state | `gateway_state.json` | `gateway_state: running`, telegram `connected` |

Each observer writes `<name>-watch-ready.json` (0600) before its trigger and a
capture receipt after. Timeout bound: 120 seconds per watch unless a step says
otherwise; on timeout, STOP and go to the recovery runbook.

## 5. Exactly one invite, exactly one Start

1. Prepare exactly one invite through the sealed harness (G12), which calls
   `RoomBootstrapStore.prepare_rehearsal_customer_invite` once. Receipt (0600)
   holds: session id, `invite_token_sha256`, `invite_token_preview`, bot
   username, expiry, and the plaintext token. The plaintext lives only in that
   0600 receipt. One invocation total; a second preparation needs a new
   explicit human authorization.
2. Start the service: `systemctl --user start hermes-gateway-dualcoachtest.service`.
   Confirm through the gateway-state observer: `running` + telegram `connected`.
   Cross-check read-only: `systemctl --user is-active` reports `active`, and
   `/home/cube/projects/richard/hermes-agent/.venv/bin/hermes --profile dualcoachtest gateway status`
   agrees. (`hermes gateway` flags: `--profile dualcoachtest` only; never `--all`,
   never `--dry-run`.)
3. Customer handset, actor `8527916639`: open the candidate-generated private
   link `https://t.me/dual_coach_pilot_test_bot?start=rc1_<token>` once, press
   Start once. The candidate accepts only `/start rc1_<22-char token>` in a
   private chat with no extra text (regex `^/start(?:@bot)?\s+(rc1_[A-Za-z0-9_-]{22})$`).
4. Expected: one private DM transport update; one per-chat ingress guard record;
   one new claim consumed-update; one new bot-start consumed-update; session
   `PREPARED` -> `REGISTERING` -> `AWAITING_CONSENT` with the claimant bound.
   Claim watcher receipt captures the ledger transition event.

## 6. Expected all-new IDs and states

Reuse rule: actor `8527916639` appears again, nothing else does. Any reused ID
below fails the rehearsal.

| Artifact | Must be new | Must not equal |
|---|---|---|
| `customer_key` | fresh label for this run | `task22_dm_rehearsal`, `task26_synthetic_rehearsal`, `task26_same_actor_rehearsal` |
| Bootstrap session | new `cb_...`, generation 1 | `cb_2NQV5sbkN-M6awycJH7X5g`, `cb_6S6RABpDgZ165V02A7qEzw`, `cb_rmDnfrqA6gkmjoQEdwxu0g` |
| Invite token / SID hash | new `rc1_` token, new `start_token_sha256` | any prior token or hash |
| Onboarding revision | revision 1 of a new session file | prior revisions |
| Consent receipt, attestation | new digests | prior digests |
| Check-in event | new `wizard_...` event id, new `checkin_revision` | `wizard_995f04a3b8bc256fa13ff407` |
| Draft / generation | new draft token, new generation record digest | `3f44a18ea620d963`, `42f899e76b603c3f2342be3647ccfa032134c79b67094396564eee6fe4ec429c` |
| Owner review card | new card binding, new callback update id | prior message ids |
| Delivery | new delivery row | any prior row |

State sequences (candidate-authored):

- Bootstrap: `PREPARED` -> `REGISTERING` -> `AWAITING_CONSENT` -> `AWAITING_ACTIVATION` -> `ACTIVE` at activation time. Terminals: `CANCELLED`, `EXPIRED`, `FAILED` only on abort paths.
- Onboarding (`checkin_cli.nutrition_onboarding_models.OnboardingState`): `collecting` -> `customer_attestation` -> `reconciling` -> `owner_review` -> `finalizing` -> `ready`. Branch `safety_hold` aborts the happy path; see the recovery runbook.
- Registry: customer row appears `enabled: false`, `registration_state: disabled`; flips to `enabled: true` only at Section 9; back to `false` at Section 12.
- Generation: `generation_pending` -> `generating` -> `draft_created`.
- Delivery: absent -> exactly one row, terminal `sent_audited`.

## 7. Consent and onboarding (customer handset)

1. The consent card arrives in the private DM. Customer taps Agree once. Expected:
   consent receipt digest recorded, onboarding revision created, state
   `collecting`.
2. Customer answers Q1 through Q22 through the card UI only. Edit/later/skip
   buttons follow the card's own contract; no typed answers outside the card
   fields.
3. Customer completes the attestation step. Expected: `customer_attestation`
   -> `reconciling` -> `owner_review`; one staff review card on group topic
   `59`; one owner review card on the owner DM.

Evidence: per-transition onboarding receipts plus the observer captures. No
customer free-text answers in receipts; record digests, counts, states.

## 8. Owner/operator review (owner handset)

Owner `8693203710` opens the owner DM review card and taps Approve exactly once.
Expected: authenticated owner callback ingress receipt, one-use journal
consumption, onboarding `finalizing` -> `ready`, owner review projection
terminal. If the owner would Edit or Reject, that's an abort branch in the
recovery runbook, not a happy-path step.

## 9. Readiness and activation

1. Readiness audit (read-only), expect exit `0`:

```
/home/cube/projects/richard/hermes-agent/.venv/bin/python -m checkin_cli.readiness_cli \
  --profile-root /home/cube/.hermes/profiles/dualcoachtest \
  --customer-key <new customer_key>
```

Exit `2` means not ready; STOP, no activation.

2. Activation checklist receipt (0600) referencing the readiness receipt, the
   approval callback receipt, and the onboarding `ready` digest.
3. Activate through the profile's canonical committed-activation command:

```
/home/cube/projects/richard/hermes-agent/.venv/bin/python -m checkin_cli.customer_admin \
  --registry /home/cube/.hermes/profiles/dualcoachtest/customers/registry.json \
  activate <new customer_key> \
  --profile-root /home/cube/.hermes/profiles/dualcoachtest \
  --data-root /home/cube/.hermes/profiles/dualcoachtest/data \
  --checklist-evidence <checklist receipt path>
```

Expected: registry row `enabled: true`, `registration_state: active`,
activation receipt written, bootstrap session `AWAITING_ACTIVATION` -> `ACTIVE`,
activation completion notices drained once by the runtime (no manual drain).
Cross-check read-only: `... customer_admin --registry <registry> list`.

## 10. Check-in (customer handset)

Customer completes one 12-question check-in in the private DM through the card
UI, choosing every Q7 choice `1` through `5` across the run (the plan's Q7
coverage rule). Expected: exactly one finalized check-in event (`accepted`),
one `checkin_revision`, and exactly one generation job created in the same
transaction as the finalized check-in. No second job may appear from retries,
restarts, or callbacks.

## 11. Draft generation, owner review, exactly-once delivery

1. Generation: `generation_pending` -> `generating` -> `draft_created`; exactly
   one provider call recorded with receipt; one owner review card on the owner
   DM.
2. Owner taps Approve exactly once. Edit or Regenerate are allowed at most once
   each and only before approval; each creates a new immutable child revision
   and a new card; approval is still required before send.
3. Owner explicitly sends the approved card, once. Expected: exactly one
   customer DM message; exactly one delivery row terminal `sent_audited`;
   idempotency key = `customer_key` + `checkin_revision` + approved draft
   revision. Zero duplicate provider sends, cards, delivery records, or DMs.
   No manual outbox drains, no replay, no forced publication.

## 12. Disable

```
/home/cube/projects/richard/hermes-agent/.venv/bin/python -m checkin_cli.customer_admin \
  --registry /home/cube/.hermes/profiles/dualcoachtest/customers/registry.json \
  disable <new customer_key>
```

Expected: `enabled: false`, `registration_state: disabled`, no pending
generation or delivery jobs, no pending publications. Cross-check with `list`
and `validate`.

## 13. Archive-first cleanup reset

Same sealed controller, same argument discipline as Section 2, fresh run id and
fresh one-use approval. Post-reset verification compares against the pre-reset
archive: registry empty, onboarding absent, owner ledgers absent,
`gateway.lock` absent, service inactive, `gateway_state.json` absent or
truthfully `stopped` with matching boot id. Write `cleanup-reset-receipt.json`
(0600). Both archives (pre-reset and cleanup) stay immutable under
`data/rehearsal-reset-archives/`.

## 14. Evidence receipts inventory

One 0600 receipt per phase, each with schema name, UTC timestamp, candidate and
wheel digests, command lines, observed digests, and PASS/FAIL:

`preflight-receipt.redacted.json`, `pre-reset-receipt.json`,
`deployment-rebind-receipt.json`, five observer watch-ready receipts,
`invite-preparation-receipt.json` (sole plaintext-token holder),
`claim-receipt.json`, consent/onboarding/attestation receipts,
`owner-review-receipt.json`, `readiness-receipt.json`,
`activation-checklist-receipt.json`, `checkin-receipt.json`,
`generation-receipt.json`, `send-receipt.json`, `delivery-receipt.json`,
`disable-receipt.json`, `cleanup-reset-receipt.json`, and the final Task26
verdict receipt. Redaction: no bot token, provider secret, or invite plaintext
outside the invite receipt; no customer answer text anywhere.

## 15. Prohibitions (no recovery shortcuts)

Binding for every step above:

- No raw Telegram listener, no `getUpdates` harness, no update-cursor edits, no
  `drop_pending_updates=True`.
- No direct durable-state mutation: no hand edits to JSON ledgers, registries,
  session files, locks, claims, or outbox rows.
- No manual claim deletion, no manual delivery drain, no forced card publication, no direct service replay.
- No recovery shortcut: anything not listed here goes to the recovery runbook,
  and if the recovery runbook doesn't cover it, the rehearsal aborts.
- No real-customer activation, no historical evidence retargeting, no unrelated
  profile changes, no `--all` gateway flags, no changes to `physique-coach` or
  `quarantine`.
- No commit, push, release, publish, register, or tag actions.
- The old runbooks' `dualcoach_admin` planned interfaces are non-existent in
  this candidate; don't run them.
- No silent failure: every step writes its receipt; a missing receipt equals a
  failed step.
