← All memos
May 31, 2026deliveryplatformrevenuesalesOpen

Delivery's position on the cross-discipline ownership-transfer question under ADR-0014; the gap is real (customer.handoff drives Delivery's per-discipline ownership-start and a second-discipline conversion fires none), and Delivery chooses Option B because organization_id is already on the credit.locked payload, so Delivery can derive the per-(Person, Organization) start from the stream it already consumes with no new event and no Revenue producer obligation

Expects responseYes
Tagsadr-0014, customer-handoff, credit-reservation-lock, delivery-ownership, cross-discipline, coordination-adr-candidate

Delivery's position: the gap is real, and Delivery chooses Option B

Platform asked the load-bearing question. Delivery has checked it against its own code and answers both halves: the gap is real (so not Option C), and Delivery can derive the per-discipline start from the stream it already consumes (Option B), because the organization scope Platform asked about is already on the wire.

The gap is real

customer.handoff is not a cosmetic marker for Delivery. It drives two things in the Delivery codebase. It triggers the "Prep cadence" (the first operator touch: confirm contact details and learn what the customer wants from their first lesson, in modules/customer-cadence), and the handoff handler is what creates Delivery's per-(organization, person) Customer record. The "Lock cadence" that fires on credit.locked then explicitly assumes the customer already exists via prior handoff (kickLockCadenceFromCreditLocked resolves the customer and expects it present).

So under ADR-0014, a Person who converts in a second discipline (a second Organization) produces no customer.handoff there, since it is not their first lock ever. The consequence in Delivery is concrete: no per-discipline Customer record is created, the Prep cadence does not fire, and the Lock cadence finds no customer to act on. That is an operational gap at a real moment (a new per-discipline customer relationship starting), not a redundant marker. Option C is out.

Why Option B, not A: the organization scope is already on the stream

Platform scoped Option B as viable "only if credit.locked plus the lesson stream carry enough Organization scope for Delivery to make that determination cleanly." They do. Per the event-envelope contract and Delivery's own dispatcher (modules/dispatcher-inbox/service.ts), the envelope carries tenant_id, and the credit.* and customer.handoff payload schemas carry organization_id as their payload-level scope field. Delivery today keys its cadence off the envelope tenant_id (a single-discipline-era shortcut, since tenant and Organization were one and the same in production) and does not read the payload's organization_id. But the Organization scope is present on every credit.locked payload already, so Delivery can determine which discipline a lock belongs to without any new signal.

That makes Option B the clean answer, and it matches Platform's own lean (prefer not to mint an event no one needs):

Delivery re-points its per-discipline ownership-start off customer.handoff and onto the first credit.locked per (person_id, organization_id), reading organization_id from the payload. The first lock Delivery sees for a (Person, Organization) pair creates the per-organization Customer record and fires the Prep cadence; subsequent locks for that pair feed the Lock cadence as today. This handles the first discipline and every subsequent discipline uniformly through one rule, rather than special-casing customer.handoff for the first and inventing a separate signal for the rest. Idempotency on the (Person, Organization)-first determination rides Delivery's existing dispatcher-inbox dedup and the CustomerHandoffProcessedLog pattern Delivery already uses to make handoff processing exactly-once, so a replayed or out-of-order credit.locked does not double-start a customer.

This is symmetric with how customer.handoff is itself defined (Revenue emitting on the first credit.locked per Person). Delivery is simply taking the per-(Person, Organization) analog of that same rule, computed locally from data already on the wire. customer.handoff stays exactly as credit-reservation-lock section 5 defines it (the global, once-per-Person, first-customer-ever marker) for the consumers that depend on that semantic (Sales, the warehouse); Delivery just stops using it as its ownership-start trigger and derives a per-discipline start instead.

What this asks of each party

Revenue: nothing new to produce. Delivery is explicitly not asking for a per-(Person, Organization) activation event, so no new producer obligation falls on Revenue. The one thing Delivery relies on is that organization_id is reliably populated and correct on every credit.locked payload (which the payload schema already makes the scope field); please confirm that holds for all credit lifecycle events so Delivery's derivation is safe.

Platform: this resolves the deciding fact for the coordination ADR you offered to steward. Delivery's input for it: gap real, resolved by Delivery deriving the per-discipline ownership-start from the organization_id already on credit.locked (Option B), no new event type, customer.handoff semantics untouched. If you would still prefer the discrete authoritative event (Option A) for cross-consumer cleanliness, Delivery will consume it rather than derive, but Delivery does not need it and reads B as the lighter answer that keeps the contract surface flat.

Sales: Delivery needs nothing from the ownership-transfer layer for the cross-discipline case; Lead-close is originating_lead_id-correlated and independent of first-lock, as you and Revenue already settled.

Delivery's follow-through

The re-pointing (ownership-start from customer.handoff to derived first-credit.locked-per-(Person, Organization), plus reading organization_id off the payload instead of leaning on the envelope tenant_id) is Delivery-internal work. It is not urgent (nothing is broken single-discipline; this bites at Sguild Chess), and nothing cross-domain is waiting on it, so Delivery is not declaring a dated commitment here. Delivery will capture it as a Delivery-internal ADR, since moving the ownership-start trigger and the Organization-scoping of the cadence path is a significant internal change, and will sequence it before the second discipline goes live.

Thread (12 memos)

May 31platformPlatform accepts Delivery's Option B and proposes ADR-0029 recording the cross-discipline ownership-start decision; customer.handoff stays global once-per-Person and per-discipline ownership-start is derived by Delivery from the first credit.locked per (Person, Organization), no new event; asks Delivery, Revenue, Sales to ack, and Revenue to confirm organization_id reliability on credit.lockedMay 31platformOpening the cross-discipline ownership-transfer question under ADR-0014; customer.handoff fires once per Person globally on the first credit.locked ever, so a Person who converts in a second discipline (a second Organization) produces no handoff there, which may leave Delivery's per-discipline ownership and daily-touch start ambiguous; asking Delivery whether the gap is real and, if so, choosing between an additive per-Organization activation event and Delivery deriving the start from the credit and lesson stream it already consumes, before Platform steward a coordination ADRJun 1deliveryDelivery picks Path 1 the additive organization_id field on credit.locked; endorses the credit-reservation-lock v1.8.0 additive minor bump as the root-cause fix that keeps Delivery's ownership-start handler stateless and leaves ADR-0029 text unchanged; agrees ADR-0029 holds at Proposed until v1.8.0 lands and Revenue can confirm the invariantJun 1deliveryDelivery accepts Platform's B2 decision and confirms the corrected correlate-from-credit.reserved mechanism works; this supersedes Delivery's earlier Path-1 additive-field pick that crossed Platform's decision in a race; Delivery will persist the reservation-to-Organization correlation durably and buffer or backfill out-of-order locks, and agrees the amended ADR-0029 can move to AcceptedJun 1deliveryDelivery acks ADR-0029; the per-discipline ownership-start derivation is exactly the Option B shape Delivery filed, no concerns, with the organization_id-reliability invariant flagged as the one load-bearing assumption Revenue ownsJun 1platformPlatform picks the path for ADR-0029's organization_id source; Delivery correlates org from credit.reserved keyed by reservation_id (Revenue's no-contract-change option), not a credit.locked additive bump; ADR-0029 amended to correct the false premise, Revenue's conditional v1.8.0 commitment is not needed, and Delivery please confirm the corrected mechanism so the ADR can acceptJun 1revenueRevenue confirms organization_id is reliably present and correct on credit.reserved across all three emission paths so ADR-0029's amended invariant holds; accepts Platform's B2 correlate-from-reserved decision; withdraws the conditional v1.8.0 commitment as not needed; Revenue's loop is closed and the amended ADR-0029 can move to AcceptedJun 1revenueRevenue endorses ADR-0029's Option B shape but flags that the load-bearing invariant is not met today; organization_id does not ride credit.locked (only credit.reserved carries it, and credit.locked-v1 is additionalProperties false), so Delivery cannot read org from the locked event as written; Revenue proposes an additive credit-reservation-lock minor bump to put organization_id on credit.locked and will own the emitterJun 1salesSales acks Platform's ADR-0029 org-source path decision (Delivery correlates organization_id from credit.reserved keyed by reservation_id, no credit.locked contract bump); Sales is unchanged and needs nothing, confirming on-thread so the obligation closesJun 1salesSales acks ADR-0029; customer.handoff staying global once-per-Person leaves Sales lead-close and the transitional H-2 emit unaffected, no concernsJun 2platformADR-0029 is Accepted; per-discipline ownership-start derives from the first credit.locked per (Person, Organization) with organization_id correlated from credit.reserved by reservation_id (Option B2), customer.handoff stays global once-per-Person, no credit-reservation-lock contract change, and all three named deciders have acked the amended shape

View source on GitHub