> ## Documentation Index
> Fetch the complete documentation index at: https://docs.myfundingmachine.com/llms.txt
> Use this file to discover all available pages before exploring further.

# Onboarding runbook

# Onboarding pilot, rollout, and recovery

Operational runbook for enabling onboarding Labs, staff writes, stage progression,
and cloud communications. Read the [integration map](onboarding-integrations.md) for
IDs, flags, and API contracts first. Engine cutover (direct configuration, compute cohort review, historical-receipt
reconciliation, token revoke, enablement, rollback) lives only in
[services/onboarding-engine/docs/RUNTIME.md](../../services/onboarding-engine/docs/RUNTIME.md).
Do not duplicate that procedure here.

This document is not authorization to enable flags, deploy, send messages, purchase
numbers, or write production configuration. Each activation needs an explicit,
named approval.

## Decided ownership (2026-09-29)

| Concern | Owner |
| - | - |
| Automated **onboarding** stage moves | Progression job only: `reconcilePage` (`convex/crons.ts`, 15-minute interval) when `ONBOARDING_AUTO_PROGRESS_ENABLED` and the Location allowlist are set, and the general CRM write gate is on |
| Onboarding `move_stage` from the live runner | Never — enforced in `lib/onboardingEngineLive.ts` ([#1807](https://github.com/Funding-Machine/ghl-leadbuilt-marketplace-app-fundingmachine/pull/1807)), even when a cohort allows that kind |
| Progression sync-mode field writes: **Blocked**, **Tech Calls Complete**, **Last App Login**, **Last Credit Pull** | `derivedOnboardingChanges` via `save(mode: "sync")`; Tech Calls Complete requires both technical call dates reached; null activity sources preserve CRM dates |
| Messages, tasks, engine field stamps (**Onboarding Completed Date**, **Hold Status**; retention **Slack Plan Status**, **Churn Risk Reason**, **Last Touchpoint**, and the retention card's **Last Credit Pull** / **Last App Login** from operator-pulse via `usageStamp`), retention create/moves, `mark_won` | Cloud engine (Convex live runner) only. The engine never writes **Blocked** or **Tech Calls Complete** anywhere; progression is the only writer of all four fields above on the onboarding opportunity ([#1857](https://github.com/Funding-Machine/ghl-leadbuilt-marketplace-app-fundingmachine/pull/1857)) |
| E2 / Final QA handoffs after progression moves the card | After [#1814](https://github.com/Funding-Machine/ghl-leadbuilt-marketplace-app-fundingmachine/pull/1814): W5 sends E2 from Compliance **or** Setup In Progress; W8 creates the QA task from Setup In Progress **or** Final QA |
| Shared compliance checklist | **Payment Verified**, **Slack Joined**, **Skool Joined** (after #1814; **Slack Channel Created** retired) |
| Live custom values | After [#1815](https://github.com/Funding-Machine/ghl-leadbuilt-marketplace-app-fundingmachine/pull/1815): read from the CRM every pass; fail closed; never use the snapshot's copy |
| Native CRM workflows that move onboarding stages | Must be retired / gated before cloud live (see RUNTIME.md) |
| Human stage moves | Never auto-reverted |
| Communications sender | Cloud runner only; Mac mini onboarding-engine job retires before live |
| FM1 / FM2 calendars | Separate calendars in onboarding settings (FM2 = FM Follow-up) |
| DND | Allow send unless CRM DND is on (`dnd === true`, channel `active`/`permanent`, or no address). Missing DND data does not block ([#1807](https://github.com/Funding-Machine/ghl-leadbuilt-marketplace-app-fundingmachine/pull/1807)). Waiting members report `waiting`. See `lib/onboardingEngineLive.ts` |

## Preconditions (fail-closed)

Confirm before any pilot widen or communications enablement:

1. Current `origin/main` (or the exact authorized deploy SHA) and the integration map
   state table still match production flags.
2. At most one sender will be active. Stop the Mac mini onboarding-engine job and
   revoke its CRM token before enabling `ONBOARDING_ENGINE_LIVE_ENABLED`. Follow
   RUNTIME.md for direct configuration, compute cohort review, and
   single-writer cutover.
3. Do not treat the retired mini job or a local package `run`/`bootstrap` as the
   current sender.
4. Labs Locations are explicit. An enabled Labs flag is not an automatic-progression
   or communications allowlist.
5. General admin CRM writes (`ONBOARDING_ADMIN_CRM_WRITES_ENABLED`) and KYC field
   writes are separate gates.
6. A Retention card must have exactly one Product Location ID matching the reviewed
   cohort member, as well as the correct Operations Location and contact. Missing,
   duplicate or conflicting mappings block the member before account signals or
   writes. The creation receipt must confirm that mapping and open status; an
   uncertain receipt requires ledger reconciliation before retrying. A card for
   another product account cannot satisfy the Won prerequisite.

## Pilot cohort

Use Location IDs only. As of the September 29 audit the four Labs-enabled Locations
are:

| Role | Location ID |
| - | - |
| Internal / test | `oE9ILHco0XXZUu79wAA0` |
| Pilot Operator A | `Ttl6xzeFebzFEi9QMlXR` |
| Pilot Operator B | `AakcOVxyrekzvV7uCkXv` |
| Pilot Operator C | `AsrA02DtutMnKjXpseym` |

Pilot Operator B mapping (revalidate before repair):

* Operations contact: `KvUhx6Luui3Vw3POkUuY`
* Onboarding opportunity: `C2gg7sYKYkpgym20UrZA`

Operations source Location for calendars and opportunities: `ReoQmuh4ooNuHeE5stlj`.

### Acceptance gates (still open unless freshly proven)

Record dated outcomes, not green flags alone:

| Gate | What “done” means |
| - | - |
| Calendars saved | Kickoff, FM1, and a **separate** FM Follow-up calendar for FM2 saved in Admin → Settings → Onboarding; real appointments match distinct slots |
| KYC end-to-end | Customer completes verification → signed webhook → CRM KYC Verified readback |
| Slack workspace | Private channel created automatically; ID saved to exact CRM opportunity; approved email-matched Operator joins as a free workspace member |
| Staff CRM writes | `ONBOARDING_ADMIN_CRM_WRITES_ENABLED` approved for intended scope; clear/reopen and attendance paths audited |
| No dual writers | Mini onboarding-engine job stopped; cloud live not yet on, or only after RUNTIME.md cutover |
| App readiness | Nine required outcomes (ten with KYC) do **not** imply CRM Won, confirmed attendance, or message delivery |

Rollback for the Operator UI: disable the per-Location Labs flag. That does not reverse
a dispatched phone purchase, appointment change, or independent engine send.

## Rollout sequence

Enable each step only with explicit approval naming the flag/target.

1. **Labs Locations** — keep the cohort explicit; expand Location-by-Location.
2. **Calendar mapping** — save kickoff + FM1 + separate FM Follow-up for FM2; verify
   live events for a known Operations contact.
3. **Admin CRM write gate** — after live synthetic API acceptance of opportunity
   updates, pagination, and audit trails.
4. **Automatic progression** — `ONBOARDING_AUTO_PROGRESS_ENABLED` +
   `ONBOARDING_AUTO_PROGRESS_LOCATION_IDS` (also needs the write gate). Live still
   requires staff QA. Confirm native CRM workflows no longer move onboarding stages.
5. **Cloud communications** — follow RUNTIME.md. Start the cohort in `compute`;
   review proposals, then promote approved members to `send`. Engine may stamp its own
   fields (never Blocked or Tech Calls Complete; on retention cards it stamps Last Credit
   Pull and Last App Login from operator-pulse via `usageStamp`, while progression alone
   writes all four on the onboarding opportunity), send messages, create tasks, create
   retention cards, move retention stages, and `mark_won` — never advance onboarding
   stages (#1807). After #1815, custom values come from the CRM every pass.
6. **Slack workspace** — install the dedicated FM Bot in My Funding Machine Support, configure its credentials and staff roster, then enable the workspace and provisioning flags. Follow [Slack workspace setup](../staff/slack-workspace.mdx). Do not activate a Slack Pro upgrade reminder; this workspace flow no longer requires customers to upgrade.

## Recovery cheatsheet

| Situation | Action |
| - | - |
| Uncertain engine send | Inspect the durable claim; do not blind-retry. Resolve per RUNTIME.md / live ledger tools |
| Lost KYC create response | Recover existing `vs_` in Stripe Identity; staff **Recover existing verification**; wait out lock if shown |
| Stuck pending admin edit | Audited staff force-release with reason (after the approved wait/evidence rules) |
| Wrong calendar pin / cancelled booking | Clear reasoned override or re-pin; cancelled/no-show do not count as completion |
| Ambiguous Slack channel | Pause setup, review the exact CRM account and reserved private channel; recover the original attempt |
| Phone purchase unknown | Check inventory/billing; never buy another number; staff clear only a proven failure |
| Dual writer suspected | Stop cloud live and/or mini job immediately; reconcile ledgers before either resumes |
| Preview DNS / sandbox cleanup | Exact-target approval; preserve live app domain and production secrets |

## What not to do

* Run two writers (mini job + cloud live).
* Purchase a phone number or create a live Identity session “to test docs.”
* Deploy Convex production or change CRM workflows without a named write approval.
* Infer Slack Pro, attendance, or Payment Verified from connection, elapsed time, or
  subscription `active`/`trialing` alone.
* Treat app “onboarding complete” as CRM Won or as permission to enable retention emails.
* Document GoHighLevel / GHL in Operator-facing copy (backend and this internal file may).

## Related guides

* [Integration map](onboarding-integrations.md)
* [Engine runtime / cutover](../../services/onboarding-engine/docs/RUNTIME.md) (cloud cutover runbook)
* [Staff onboarding](../staff/onboarding.mdx) · [connections](../staff/onboarding-connections.mdx) · [account linking](../staff/onboarding-account-linking.mdx)
* [Operator setup](../operators/getting-started/onboarding-setup.mdx)
* [October 2 code review](onboarding-review-2026-10-02.md) (supersedes the [September 29 review](onboarding-review-2026-09-29.md))


This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.