Guided-flow engine — enablement runbook (ADR-0169)
How to turn the guided-flow engine on, safely. The engine ships gated off (PRs
#379–#381); nothing runs until a persona has a flow AND the guidedFlows flag is
true for that tenant.
- Status: runbook
- Date: 2026-07-04
⚠️ Ordering hazard — read first
Section titled “⚠️ Ordering hazard — read first”resolvePersona runs db.select().from(personas), which Drizzle compiles to an
explicit column list including flow. If the code deploys to an environment
whose personas table lacks the flow column, that SELECT fails → every
persona resolution breaks → chat is down in that env.
Therefore migration 0072_persona_flow must be applied to dev + uat + prod
BEFORE the engine code deploys — and before the auto-deploy daemon can push
main to prod. CI does not run migrations (they are applied by hand).
Correct rollout order:
pnpm migrate:dev·pnpm migrate:uat·pnpm migrate:prod— apply0072to all three (additive, nullable → safe on the running app, which ignores the column until deploy).- Merge the stack: #379 → #380 → #381 (and #376/#377/#378 independently).
- Let the deploy land. Verify chat still works everywhere — it should be byte-for-byte unchanged (flag off, no persona has a
flow). - Only then enable on ONE dev tenant (below).
Rollback is instant at any point (disable the flag / clear the persona flow); the column can stay.
Enable on a dev test tenant
Section titled “Enable on a dev test tenant”Pick a dev tenant + its default persona:
-- the persona to make guided (the tenant's default)SELECT id, name FROM personas WHERE tenant_id = '<TENANT_ID>' AND is_default = 1;1. Give the persona a flow — the Rental Concierge spec:
UPDATE personasSET flow = '{"draftKind":"reservation","slots":[{"key":"rental_dates","required":true},{"key":"size","required":true},{"key":"delivery","required":false},{"key":"quantity","required":false}],"completion":"draft_delivered","maxTurns":12}'WHERE id = '<PERSONA_ID>' AND tenant_id = '<TENANT_ID>';2. Enable the guidedFlows flag for that tenant — a per-tenant override
(feature_flags uses value='true' for booleans; updated_at is Drizzle
mode:'timestamp' = unix seconds):
INSERT INTO feature_flags (tenant_id, key, value, updated_by, updated_at)VALUES ('<TENANT_ID>', 'guidedFlows', 'true', 'dogfood', strftime('%s','now'))ON CONFLICT(tenant_id, key) DO UPDATE SET value = 'true', updated_at = strftime('%s','now');3. Purge the flags cache (KV ff:<TENANT_ID>, 300s TTL) so the override takes
effect immediately instead of after 5 min:
wrangler kv key delete "ff:<TENANT_ID>" --namespace-id <DEV_SESSIONS_KV_ID>Dogfood (dev)
Section titled “Dogfood (dev)”Drive a conversation-backed rental chat (guided flows need a conversationId)
via the headless-auth recipe. Then assert:
- State persists —
conversations.metadatagrew aflowkey; slots fill turn by turn;statuswalkseliciting → drafting → delivered:SELECT json_extract(metadata,'$.flow.status') AS status,json_extract(metadata,'$.flow.slots') AS slots,json_extract(metadata,'$.flow.metered') AS meteredFROM conversations WHERE id = '<CONVERSATION_ID>'; - Billing event fires once — exactly one
flow.completedrow at first Draft delivery:SELECT action, after_json, ts FROM audit_logWHERE action = 'flow.completed' AND target_id = '<CONVERSATION_ID>'; - Behaviour — the bot asked for
rental_dates+sizebefore drafting, did not claim a date is available (no date-inventory → it hands off to confirm), and refinements (“different size”) reshape the same Draft without a secondflow.completed.
Rollback
Section titled “Rollback”Instant, at any granularity:
- One tenant:
UPDATE feature_flags SET value='false' …(or delete the row) + KV purge. - One persona:
UPDATE personas SET flow = NULL WHERE id = …. - The
flowcolumn is additive/nullable — leave it in place.
Promote to prod (later)
Section titled “Promote to prod (later)”After the dev dogfood passes: enable guidedFlows in the Business/Enterprise
flag-version JSON (so it’s a plan capability, not a per-tenant override), wire the
flow.completed audit event into the completed-flow add-on meter (a follow-up
slice), and give real personas their flow specs. Do not enable prod before the
dev dogfood is green.