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:
modules/payment-events/— aligned with Revenue's reply (2026-05-17-revenue-cadence-stage-map-payment-event-position). Subscribes topayment.received@1(not the proposedrevenue.payment.received), pulls the payload shape fromcontracts/payment-flow/, and uses(orderId, personId) → leadIdcorrelation rather than asking Revenue to carrylead_idon the payload. Today the correlation resolver returns null and the handler returnscorrelation_missing; Phase 9b adds the Lead-Order correlation table populated at Stage 4 entry alongside the existingLead.lessonDatewrite. BehindREVENUE_PAYMENT_RECEIVED_SUBSCRIBER_ENABLED(default off).modules/coaching-confirmation/— aligned with Coaching's reply (2026-05-17-coaching-cadence-confirmation-event-position). Subscribes tocoaching.lesson.confirmation_decided@1with 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). BehindCOACHING_CONFIRMATION_SUBSCRIBER_ENABLED(default off). The outboundlead.coach.confirmation.requestedemit at Stage 3a→3b is Sales-side Phase 9b work, persisting the correlation row Coaching uses forconfirmation_request_id.modules/lesson-reschedule/— aligned with Delivery's reply (2026-05-17-delivery-cadence-reschedule-event-position). Subscribes tolesson.rescheduled; updatesLead.lessonDateandLead.lessonDateUpdatedAtso the Stage 4 cron picks up the new date on its next pass. BehindDELIVERY_LESSON_RESCHEDULE_SUBSCRIBER_ENABLED(default off).Platform inbound-comms path — Platform's reply (
2026-05-17-platform-cadence-inbound-comms-position) chose the dispatcher-mediatedplatform.comms.inboundpath. 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 behindPLATFORM_INBOUND_COMMS_SUBSCRIBER_ENABLEDonce 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/, addcoaching.lesson.confirmation_decidedto the event registry, wire producer-side emit from the confirmation decision workflow. - Revenue — wire the producer emit for
payment.receivedto fire for Stage 4-relevant orders (Sales is already a registered consumer inevent-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 (invoiced → awaiting_payment, paid → payment_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.receivedsubscriber. - Outbound
lead.coach.confirmation.requestedcorrelation rows for thecoaching.lesson.confirmation_decidedsubscriber.
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