# Runbook: move production onto the API functions
Moving production onto the per-context API functions, gated on the performance baseline and the data canary.
- Page:
- Updated: 2026-09-25
- Verified against: `4391ce0` on 2026-09-26
- From the Sri Guru Granth Sahib Ji — Knowledge Base wiki. Sri Guru Granth Sahib Ji is quoted verbatim, cited by Ang, and never altered.
---
Staging answers every bounded context with its own Vercel function inside the web project
(ADR-0011). Steps 0 and 1 below are merged on `integration` and ship with the next release: production
answers `/api` with `all`, Git previews are off, and `deploy-production` checks every function and the
golden contract on the unaliased deployment before promoting it. Render keeps deploying as the
rollback target until step 4. Every production deployment already carries the six functions, so
moving production is a routing change, released through the normal pipeline, with no new hosting.
## Prerequisites
- A green staging deploy with every context routed (`deploy-staging` → verify: every function ready
at the commit, every probe `ok`, the golden contract PASS through the gateway).
- A spending limit on the Vercel team (Settings → Billing → Spend Management) so usage-based function
pricing can never surprise the plan.
## Steps
0. **Previews.** The committed `frontend/vercel.json` names no functions (the deploy adds them with
the generated files), so Vercel's Git preview builds carry none and their `/api` follows the
production rule. Once production is on `vercel`, that rule points at a function a Git preview
does not have: switch Git previews off (`git.deploymentEnabled: false` in `frontend/vercel.json`)
in the same release, and review web changes on staging.
1. **Move production to the functions, whole API first.** In `gateway/routes.json` set
`production.api_platform` to `vercel` and drop `production.api`, keeping `production.services`
empty, so every `/api` path is answered by `all` (the single API's role, same database, same
code). Run `python3 tools/gen_gateway.py` and release it.
Verify: `curl -sI https://gurbanisoul.com/api/meta | grep -i x-service` shows `all`;
`make verify-prod`; `make canary`; `python3 scripts/ci/verify_functions.py https://gurbanisoul.com --commit --env production`.
2. **Hold the budget.** From the same place the baseline was taken:
`python3 tools/perf_baseline.py --base https://gurbanisoul.com --from "" --compare docs/perf/baseline-2026-09.json`
must PASS (p95 within +10 % per context; cold starts excluded by its warm-up).
3. **Split the contexts.** Add the contexts to `production.services`, regenerate, release, and verify
as in step 1: each context's probe shows its own `X-Service` (e.g. `knowledge`), and step 2's
budget holds per context. *Decision 2026-09-26 (owner):* under the one-version policy every
release is also an App Store update, so all five contexts move in **one** release (after the app
is live) instead of five. Each is still gated on its own: `verify_functions --env production`
proves every function ready at the commit with exactly its contexts, the golden contract runs
through the new rules before promotion, and one context rolls back by removing it (below); the
instant lever is `vercel rollback` to the previous deployment.
4. **Retire Render** after a full release cycle on the functions with the canary green: suspend and
then delete the `sggs-knowledge-base` Render service, remove `RENDER_DEPLOY_HOOK` and the
`deploy-api` / `verify-api` jobs from `deploy-production.yml`, and point the data canary's and the
uptime check's API origin at the site (the functions have no separate origin).
## Roll back
- One context: remove it from `production.services`, regenerate, release — `all` answers it again.
- The whole API: set `production.api_platform` back to `render` with its `api` origin, regenerate,
release. The Render service keeps running until step 4, so this is always available until then.