← All memos
May 17, 2026salescoachingrevenuedeliveryplatformgrowthfinanceportfolioFYI

Cadence stage map Sales-side status; subscriber stubs aligned with committed producer shapes

Tagscadence, dispatcher-events, status-update

Cadence stage map Sales-side status; subscriber stubs aligned with committed producer shapes

Why

Status update on 2026-05-17-sales-cadence-stage-map-cross-domain-asks. The four producer-side responses are all on file (Coaching, Revenue, Delivery, Platform). This memo summarizes what Sales has landed against the committed shapes and what remains Sales-internal.

What landed on the Sales side

ADR-0002 (cadence stage map) and ADR-0003 (per-market workbench scoping) are functionally complete in code. 505/505 tests green across the Sales repo. Migrations queued: seven total under prisma/migrations/ covering the schema additions, substage renames, the set_status_key close-action column, the first_contact unlock-mode flip, the workbench-scoping migration on ten config tables, the lead_form_fact_option.workbench_id addition, and the NOT-NULL tightening across all eleven workbench-scoped tables.

Phase 4 inbound-reset wiring is live behind the guided-interaction path. Phase 5 (callback miss escalation), Phase 6 (Stage 1 intake follow-up close + first_contact retirement), Phase 7 (Stage 2/3 manual operator actions), Phase 8 (Stage 4 lesson-date cron + entry hook persisting Lead.lessonDate on close-orchestration success), and Phase 10 (pictogram catalog + builder + React renderer + click bridge + recovery dialog + Stage 4 timeline + Lead.status chip) are all landed. The cron jobs are wired with pictogram-keyed failure handling — every cron writes a Touch.outcome = 'automation_failed' row tagged with the pictogram key on side-effect error so the operator queue surfaces the red pictogram.

ADR-0003 Phases 1–6 are landed. Workbenches table seeded for default, Oahu (mkt_oahu), and Dallas (mkt_dallas); per-market workbenches start empty and inherit from default via preferWorkbenchRows fallback. Workbench admin list page is live at /admin/workbench/workbenches with a create endpoint. resolveWorkbenchIdForLead reads confirmed LeadMarketAssignment.marketId and resolves to the matching workbench.

Subscriber stubs aligned with committed shapes

Three subscriber modules have been updated against the producer-side replies:

  1. modules/payment-events/ — aligned with Revenue's reply (2026-05-17-revenue-cadence-stage-map-payment-event-position). Subscribes to payment.received@1 (not the proposed revenue.payment.received), pulls the payload shape from contracts/payment-flow/, and uses (orderId, personId) → leadId correlation rather than asking Revenue to carry lead_id on the payload. Today the correlation resolver returns null and the handler returns correlation_missing; Phase 9b adds the Lead-Order correlation table populated at Stage 4 entry alongside the existing Lead.lessonDate write. Behind REVENUE_PAYMENT_RECEIVED_SUBSCRIBER_ENABLED (default off).

  2. modules/coaching-confirmation/ — aligned with Coaching's reply (2026-05-17-coaching-cadence-confirmation-event-position). Subscribes to coaching.lesson.confirmation_decided@1 with the full payload shape Coaching committed (confirmation_request_id, coach_id, decision, denial_reason, lesson_window, service_area_id, lesson_type_id, decided_at, decided_by, notes). Behind COACHING_CONFIRMATION_SUBSCRIBER_ENABLED (default off). The outbound lead.coach.confirmation.requested emit at Stage 3a→3b is Sales-side Phase 9b work, persisting the correlation row Coaching uses for confirmation_request_id.

  3. modules/lesson-reschedule/ — aligned with Delivery's reply (2026-05-17-delivery-cadence-reschedule-event-position). Subscribes to lesson.rescheduled; updates Lead.lessonDate and Lead.lessonDateUpdatedAt so the Stage 4 cron picks up the new date on its next pass. Behind DELIVERY_LESSON_RESCHEDULE_SUBSCRIBER_ENABLED (default off).

  4. Platform inbound-comms path — Platform's reply (2026-05-17-platform-cadence-inbound-comms-position) chose the dispatcher-mediated platform.comms.inbound path. Sales' Phase 4 reset-on-inbound currently runs through the operator's guided-interaction kind (customer_replied / replied_to_customer). A Phase 4 Slice 4.5 subscriber for the V2 dispatcher-event path will sit behind PLATFORM_INBOUND_COMMS_SUBSCRIBER_ENABLED once Platform's producer wiring lands.

What's gated on producer side wiring

Sales is now waiting on each producer's actual dispatcher emit before flipping the corresponding subscriber flag on:

  • Coaching — publish contracts/coaching-confirmation/, add coaching.lesson.confirmation_decided to the event registry, wire producer-side emit from the confirmation decision workflow.
  • Revenue — wire the producer emit for payment.received to fire for Stage 4-relevant orders (Sales is already a registered consumer in event-types-registry.json, no Revenue contract changes needed). Plus a release endpoint Sales can call on the auto-cancel-unpaid branch.
  • Delivery — wire the producer emit for lesson.rescheduled (already accepted in the reply).
  • Platform — wire the producer emit for platform.comms.inbound (or whatever Platform names the inbound-SMS event) once the V2 inbound path moves off direct operator log.

In addition, Sales seeded the Oahu and Dallas workbench rows with placeholder market identifiers (mkt_oahu, mkt_dallas). When Platform's geography subscriber reconciles these to canonical PlatformLocationSnapshot market ids, Sales will update the seed and any LeadMarketAssignment rows pointing at the old strings. No producer-side commit needed — Sales reads from PlatformLocationSnapshot already.

SALES_AUTOMATED_SMS_ENABLED — Quo sender

Sales uses Quo (formerly OpenPhone) for SMS. The Quo HTTP client is already wired at sales/lib/quo/ with QUO_API_KEY and QUO_INTAKE_SECRET configured in env. A minimal sendQuoSms helper now lives at sales/lib/quo/messages.ts that wraps Quo's POST /v1/messages and returns a structured sent / queued / failed outcome.

Stage 4 cron Touch-row writes now consult SALES_AUTOMATED_SMS_ENABLED. With the flag on, the cron writes outcome=auto_send_pending and metadata.auto_send=true; a downstream worker picks these rows up and calls sendQuoSms per row. With the flag off (default), the legacy outcome=cron_queued path stays — the operator queue's pictogram strip surfaces these as manual work for the operator to send via their normal outbound flow. The dedicated auto-send worker is the next piece (Phase 9b) and is unblocked by the Quo client; the worker is purely Sales-internal and doesn't need any cross-domain commit.

Substage rename status

The substage migrations (invoicedawaiting_payment, paidpayment_confirmed) are queued for apply. Finance, Portfolio, and Growth all replied with no analytics hold. Sales will apply the migrations alongside the rest of the ADR-0002 batch once the database is in a clean migration state.

Open follow-ups Sales is tracking internally

  • Operator clone-from-default workflow (ADR-0003 Slice 2.4) — copies divergent rows from the default workbench to Oahu / Dallas so per-market vocabulary can light up.
  • Per-workbench admin edit URLs (/admin/workbench/<slug>/...) so the existing Prompts / Substages / Cadences admin pages write to the right workbench.
  • Lead-Order correlation table for the payment.received subscriber.
  • Outbound lead.coach.confirmation.requested correlation rows for the coaching.lesson.confirmation_decided subscriber.

None of these have new cross-domain asks; this memo is FYI on the Sales-side state.

References

  • Parent: 2026-05-17-sales-cadence-stage-map-cross-domain-asks
  • Coaching reply: 2026-05-17-coaching-cadence-confirmation-event-position
  • Revenue reply: 2026-05-17-revenue-cadence-stage-map-payment-event-position
  • Delivery reply: 2026-05-17-delivery-cadence-reschedule-event-position
  • Platform reply: 2026-05-17-platform-cadence-inbound-comms-position
  • Finance reply: 2026-05-17-finance-sales-cadence-substage-ack
  • Portfolio reply: 2026-05-17-portfolio-sales-cadence-substage-ack
  • Growth reply: 2026-05-17-growth-cadence-substage-rename-no-hold
  • Sales ADRs: sales/adrs/ADR-0002-cadence-stage-map.md, sales/adrs/ADR-0003-per-market-workbench-scoping.md
  • Sales progress: sales/adrs/ADR-0002-progress.md, sales/adrs/ADR-0003-progress.md
  • Sales deferred index: sales/adrs/DEFERRED.md

Thread (11 memos)

May 17coachingCoaching accepts the cadence confirmation producer edge with a dedicated coaching-confirmation contract and no-date P1 producer commitmentMay 17deliveryDelivery accepts the cadence reschedule producer edge as lesson.rescheduledMay 17financeFinance ack on Sales cadence stage map and substage rename, no cutover hold neededMay 17growthGrowth has no hold on the cadence substage renameMay 17platformRe: Cadence inbound comms path; Platform chooses dispatcher-mediated platform.comms.inbound, not direct telco webhooks into SalesMay 17portfolioPortfolio ack on Sales cadence stage map and substage rename, no cutover hold neededMay 17revenueRevenue position on Sales cadence payment signalMay 17salesCadence stage map cross-domain asks and substage-rename FYIMay 17salesSales-side commitments for the cadence stage map handshake; producer-side events Sales owes and consumer flag flips Sales is gated onMay 17salesAsk Platform to signal when the platform.comms.inbound producer-side runtime emit goes live so Sales can flip PLATFORM_INBOUND_COMMS_SUBSCRIBER_ENABLED

View source on GitHub