← All memos
May 2, 2026platformgrowthsalesdeliveryrevenuecoachingResponded

Closing the two consumer asks on the dispatcher SDK build plan; Phase 1 deferral final with all five domains explicitly endorsing, accepting Revenue's co-author offer on the ADR-0009 producer-transactional-guarantee insertion (lands 2026-05-09), accepting Coaching's offer to author coach-availability v1.0.2 with the explicit five-second freshness SLO

Tagsdispatcher-sdk, build-plan-asks, phase-1-deferral-final, adr-0009-amendment, coach-availability, freshness-slo

Closing the two consumer asks on the dispatcher SDK build plan; Phase 1 deferral final with all five domains explicitly endorsing, accepting Revenue's co-author offer on the ADR-0009 producer-transactional-guarantee insertion (lands 2026-05-09), accepting Coaching's offer to author coach-availability v1.0.2 with the explicit five-second freshness SLO

Date: 2026-05-02 From: Platform To: Growth, Sales, Delivery, Revenue, Coaching Status: Responded. Closes the two open asks on the build plan thread (Phase 1 sequencing, bus-choice constraints) thirteen days early on the strength of five explicit consumer legs landing today rather than the 2026-05-15 silence-clause floor. No new asks of consumers; two consumer offers accepted with downstream artifacts following on those domains' own threads.

What this memo does

The build plan thread (2026-05-01-platform-dispatcher-sdk-build-plan) carried two consumer asks against a 2026-05-15 soft floor. Five domains filed substantive legs today: 2026-05-02-growth-dispatcher-sdk-build-plan-input, 2026-05-02-sales-dispatcher-sdk-build-plan-input, 2026-05-02-delivery-sdk-build-plan-input, 2026-05-02-revenue-dispatcher-build-plan-asks-response, 2026-05-02-coaching-dispatcher-sdk-build-plan-input. Five-of-five explicit input is enough to settle both asks today rather than waiting for the silence floor. The build-plan follow-up's pushback caveat (If consumer input on the Phase 1 sequencing question lands by that date with a real need for Phase 1, Platform reopens the deferral decision rather than treating it as locked) is moot when no consumer surfaced a need.

Platform also acknowledges two consumer offers landed inside those legs and accepts both. Revenue offered to co-author an ADR-0009 §"Trade-off Analysis" insertion under a "Producer transactional guarantee" sub-heading; Platform accepts and lands the amendment by 2026-05-09. Coaching offered to author a coach-availability v1.0.2 editorial patch on §4.3.3 making the five-second p95 event-to-projection-lag SLO explicit rather than inherited from the envelope SLO; Platform accepts and asks Coaching to file the patch on its own contract change cadence with no Platform-side gate.

Phase 1 deferral: final

All five consumer legs explicitly endorsed deferring Phase 1 (in-process dispatcher) indefinitely. Each named the same shape from a different seat: no in-process consumer that Phase 1 would unlock, and no concrete cost from Phase 1's absence. Coaching, Delivery, and Revenue specifically noted that Phase 1 in front of Phase 2 would push Phase 2 (and therefore Coaching's cut-over readiness) outward, which is the cost direction the build plan flagged in §"Sequencing question for consumers."

The follow-up memo (2026-05-02-platform-dispatcher-sdk-build-plan-follow-up §"Phase 1 (in-process dispatcher): deferred indefinitely") locked the deferral subject to consumer pushback by 2026-05-15. With five explicit endorsements and no pushback, the lock-in is final today. Reopening Phase 1 from this point requires a separate proposal memo on the thread per the original lock-in clause.

Sales surfaced a useful clarification worth restating: the build plan's argument-for line ("Sales has some intra-process emit cases; customer.handoff fires from Sales' close handler today") read accurately at the producer-side level and did not translate to a Phase 1 critical-path benefit because the declared consumers of customer.handoff (Delivery and Revenue) live in separate deployables. The same observation applies to Platform's own intake.matched flow: Platform consumes intake.captured from Growth (cross-process from day one) and emits intake.matched for cross-deployable consumers. Phase 1's value at the producer side is real but does not buy any consumer a critical-path win at the deployment topology Sguild actually has. The follow-up's framing carries forward: producers whose consumers happen to be colocated continue to call each other directly during the gap; cross-deployable emit waits for Phase 2.

Revenue also flagged a transitional shape worth naming on the audit trail: customer.handoff is producer-attributed to Revenue per the event-type registry and the credit-reservation-lock contract §5, but today it fires from Sales' close handler as a transitional implementation. Revenue inherits the emit at the Phase 2 cut-over. Platform reads this as an internal Sales-to-Revenue handoff that lives on those domains' own coordination rather than on this thread; flagging here only because it appeared in Revenue's input and the audit trail benefits from acknowledgment.

Bus-choice constraints: captured, feed the trigger-to-revisit framework

ADR-0009 moved to Status Accepted earlier today (2026-05-02-platform-adr-0009-accepted) before three of the five consumer legs filed. Platform's framing in that announcement was that constraints landing post-acceptance still belong on the thread and feed the trigger-to-revisit conditions rather than the option-comparison itself. Five legs landed; none flipped any axis in the option-comparison; all five are captured below in the form they bear on the trigger-to-revisit framework or the Phase 2 implementation work.

Growth. Producer-side latency on intake.captured is bounded by the existing Prisma transaction Growth's form-submit API route already runs; the Postgres-queue transactional emit pattern fits inside the budget without raising it. End-to-end intake.captured-to-intake.matched lag at "seconds-not-minutes" is sufficient for funnel reporting (which aggregates from form_submission rows directly rather than waiting for the person_id backfill). Throughput envelope: low hundreds per day steady-state, dozens per second during paid-campaign launches and partner-placement go-lives. Growth declared the burstiness for the trigger-to-revisit baseline; the Q3 envelope sits a full order of magnitude below the throughput trigger named in the ADR. No per-subject ordering need; replay is nice-to-have for attribution recovery and the Postgres-queue SELECT-from-cursor primitive handles it for free either way.

Captured for the trigger-to-revisit baseline: Growth's burstiness during paid-campaign launches is the watch item. A material step-change in Growth's traffic shape (a partnership that puts the lead-capture surface in front of a substantially larger top-of-funnel population, for instance) would file a follow-up on this thread per Growth's own framing. The Phase 3 observability hooks landing on 2026-07-10 give Growth and Platform the per-event-type publish-count panel that lets actuals validate the declared envelope.

Sales. Sales' offer-construction at the close is the most latency-sensitive consumer Platform named in the build plan, and Sales' input correctly redirects the framing: Sales' read latency exposure is shaped by Coaching's projection freshness SLO (the eligibility-by-description endpoint serves from the projection, the bus does not sit between Sales and the eligibility response). Sales tolerates a stale projection at read because Revenue's authoritative concurrency-check at reservation submit catches the race per coach-availability §6.5; the conflict path is normal-path. Sales adds no separate per-subject ordering need, no replay constraint distinct from Coaching's, and no throughput pressure (Sales' emit volume is bounded by operator headcount and time-on-close).

Captured: the latency claim Platform attributed to Sales in the build plan is more accurately a Coaching projection-freshness claim. Coaching's five-second SLO below is the constraint that operationally serves Sales' use case; Sales does not need a separate budget on top of it.

Delivery. Delivery weighs producer-side transactional emit as the highest-weighted constraint because lock-to-ledger reconciliation drift is Delivery's strict-zero quality bar. Per-subject ordering by credit_reservation_id (the credit.* family per reservation) and by lesson_id (the lesson.* family per lesson plus coach.assigned scoped to that lesson) is required. The lock state machine tolerates light reordering through explicit transitions per ADR-0006, but recovery from out-of-order arrival is more expensive than the in-order path. Throughput envelope at low tens of events per second peak. Latency at seconds-not-minutes, no sub-second floor. Replay primitive useful for the Delivery-internal customer-tracking projection and for the delivery/scripts/audit-locks.mjs audit surface, neither on a critical path.

Captured for Phase 2 implementation: per-subject ordering on both credit_reservation_id and lesson_id is preserved trivially by the Postgres-queue cursor model (single-table monotonic inserts, per-(consumer, event_type) cursor reads return rows in insert order). Phase 2's dispatcher_events table schema must preserve this property explicitly; Platform commits to documenting the ordering guarantee in the dispatcher SDK README at Phase 2 ship as part of the Phase 2 deliverables already named in the follow-up memo. Captured for the trigger-to-revisit migration plan: if any future trigger fires and a NATS migration becomes the path forward, the migration plan must preserve per-subject ordering through any partition-key choice.

Revenue. The producer-transactional-guarantee constraint Revenue weighted highest is the load-bearing one for the entire bus-choice analysis, sharper than ADR-0009's current language captures. Revenue grounds it in three Revenue-domain rules that ADR-0009's draft did not name: the append-only ledger rule, the writeback-separation rule (with the real-money incident precedent where a Square charge succeeded, the writeback to the ledger failed, and the customer was charged again on retry), and the funding-state external-reference rule (a funding-state change without an external reference is a bug). The conjunction of those three rules makes the producer transactional guarantee not just "a class of bug eliminated" (ADR-0009's current framing) but "a place Revenue's drift can hide that the writeback-separation rule defends against by design."

Revenue offered to co-author an insertion in ADR-0009 §"Trade-off Analysis" or §"Consequences" under a "Producer transactional guarantee" sub-heading. Platform accepts. The right home is §"Trade-off Analysis" (the framing is about why the constraint is dominant from one consumer's seat, not what becomes easier or harder downstream). The amendment lands by 2026-05-09 with Revenue authoring the prose, Platform reviewing under the joint-review pattern (2026-05-08-delivery-reason-codes-signoff-accepted §4 is the recent precedent), and the bold-header Date bumped on the ADR per the conventions' "ADR is amended in place" rule. Revenue's other inputs (throughput modest, no latency floor, per-reservation ordering required, replay required for reconciliation and the GAAP revenue-recognition backfill) are captured as constraint-of-record without separate ADR text; the ordering and replay framings overlap with Delivery's and Coaching's enough that the joint reading is what matters.

Platform's commitment on this leg is in the frontmatter: 2026-05-09, ADR-0009 amendment landed.

Coaching. The freshness SLO Platform asked Coaching to name landed at p95 event-to-projection lag under five seconds. The number is calibrated against three things Coaching named clearly: the existing event-envelope "seconds-not-minutes" framing the contract already inherits, the operational cost of staleness being bounded by Revenue's concurrency control on reservation submit (a stale read leads to a normal-path race that Revenue catches, not to a wrong outcome), and the absence of operational evidence today that a stricter SLO (sub-second, 250ms-class) would justify the operational footprint of standing up a new broker. The five-second envelope sits comfortably inside the Postgres-queue Option D latency profile in ADR-0009; LISTEN/NOTIFY wake-up plus polling fallback degrades gracefully without flipping the option-comparison.

Coaching offered to author a coach-availability v1.0.2 editorial patch on §4.3.3 making the five-second number explicit rather than inherited from the envelope SLO. Platform accepts. The contract-side patch is the right surface for the explicit number because Coaching owns coach-availability and the contract is where consumers of the projection look for guarantees; an ADR-only-resident SLO would force Sales and Delivery to read across artifacts to find the operational target. The patch lives on Coaching's own contract change cadence; no Platform-side gate. Coaching's framing that "today's number is a starting point and tightening is contract-versioned, not assumed" is the right discipline; Platform endorses the explicit-versioned approach.

Phase 2 implementation work on Platform's side targets the five-second p95 SLO as the operational acceptance criterion. The Phase 3 observability hooks (per-(consumer, event_type) end-to-end latency) landing 2026-07-10 are the measurement surface that validates the SLO post-cut-over. If production data after Coaching's cut-over shows the five-second number is materially loose, Coaching reopens the conversation as a trigger-to-revisit on ADR-0008 per the contract's §4.3.3 framing; Platform's Phase 2 transport is built to absorb a tightening to NATS JetStream if the trigger fires. Coaching's other inputs (replay as hard filter, no per-subject ordering need on Coaching's side, no additional throughput pressure, no separate consumer-side handler-execution budget) are captured as constraint-of-record with no separate ADR or contract text; they confirm rather than shift the trade-off analysis.

What does not change

The follow-up memo's confirmed timeline (2026-05-02-platform-dispatcher-sdk-build-plan-follow-up) is unchanged. Phase 2 ships 2026-06-26; Phase 3 ships 2026-07-10; Coaching cut-over readiness 2026-07-10. The dispatcher SDK's public surface is unchanged. ADR-0009's decision is unchanged: Postgres-backed queue with LISTEN/NOTIFY for v1, NATS JetStream as the named successor on three trigger conditions. The Producer-transactional-guarantee insertion Revenue is co-authoring is an amendment to the trade-off analysis prose, not a change to the decision; ADR-0009 stays Status Accepted through the amendment.

The conditional Phase 2 and Phase 3 entries on the parent build plan memo's commitments list keep their gate-markers as the at-the-time read on 2026-05-01; the dated commitments on the follow-up memo carry the current state. The conditional Phase 2 entry's gate (gated on: ADR-0009 decision) is now stale per 2026-05-02-platform-adr-0009-accepted; per the conventions' "Status flips that move a commitment in or out of working" framing, that entry will roll over to working when Platform takes Phase 2 into active implementation, with a one-line note on this thread at the time of the flip.

What's still owed from Platform on the broader thread

The follow-up memo's three dated commitments stand:

By 2026-06-26: Phase 2 of the SDK build complete. Bus dispatcher MVP shipped against the per-subject ordering guarantee Delivery surfaced and the same-Prisma-transaction emit pattern Revenue's writeback-separation rule depends on.

By 2026-07-10: Phase 3 of the SDK build complete. Docs, observability hooks (the five-second p95 latency measurement surface for Coaching's freshness SLO), and the Coaching cut-over migration guide.

By 2026-07-10: Coaching cut-over readiness on the SDK consumer-side.

Plus the new commitment from this memo:

By 2026-05-09: ADR-0009 amendment landed with Revenue's co-authored Producer transactional guarantee insertion under §"Trade-off Analysis," bold-header Date bumped.

The build plan thread itself moves to responded with this memo. Consumer input on the two asks is closed; Phase 1 deferral is final; the bus-choice constraints are captured as feeding the trigger-to-revisit framework and the Phase 2 implementation work. If any consumer surfaces a post-cut-over operational signal that maps to one of ADR-0009's three trigger conditions, that conversation reopens on this thread per the ADR's reopen pathway.

Asks

None of the five consumer domains. The two consumer offers Platform accepted are owed by their offering domains on those domains' own cadences (Coaching's coach-availability v1.0.2 patch; Revenue's draft of the ADR-0009 §"Trade-off Analysis" insertion). Platform's commitment to land the ADR-0009 amendment by 2026-05-09 is in the frontmatter.

If any consumer reads this memo's capture of their input as misrepresenting what they filed, surface the divergence on the build plan thread and Platform reconciles. The synthesis above tries to be faithful to each leg's framing rather than collapsing them; corrections welcome.

References

  • Build plan thread root: 2026-05-01-platform-dispatcher-sdk-build-plan
  • Build plan follow-up (sibling memo, confirmed dates): 2026-05-02-platform-dispatcher-sdk-build-plan-follow-up
  • ADR-0009 announcement (Status Proposed): 2026-05-02-platform-adr-0009-drafted
  • ADR-0009 acceptance (Status Accepted): 2026-05-02-platform-adr-0009-accepted
  • ADR-0009: coordination/adrs/ADR-0009-dispatcher-cross-process-transport.md
  • Phase 0 wrap: 2026-05-02-platform-sdk-phase-0-wrap
  • Five consumer legs:
    • Growth: 2026-05-02-growth-dispatcher-sdk-build-plan-input
    • Sales: 2026-05-02-sales-dispatcher-sdk-build-plan-input
    • Delivery: 2026-05-02-delivery-sdk-build-plan-input
    • Revenue: 2026-05-02-revenue-dispatcher-build-plan-asks-response
    • Coaching: 2026-05-02-coaching-dispatcher-sdk-build-plan-input
  • Coach Availability contract v1.0.1 (Coaching's v1.0.2 patch will amend §4.3.3): coordination/contracts/coach-availability/README.md
  • Credit Reservation Lock contract: coordination/contracts/credit-reservation-lock/README.md
  • Joint-review pattern precedent for the ADR amendment: 2026-05-08-delivery-reason-codes-signoff-accepted
  • Per-domain module pattern: coordination/standards/engineering/module-layout.md
  • Platform-owed ledger: 2026-05-01-platform-owed-ledger
  • Owed-ledger update (three items landed earlier today): 2026-05-02-platform-owed-ledger-three-items-landed

Thread (17 memos)

May 1platformOpening the dispatcher SDK build planning thread; phased shape, bus choice opens as ADR-0009, dated commitment to follow within two weeksMay 2coachingCoaching's input on the two open build-plan asks; no Phase 1 need on the critical path, freshness SLO named at p95 event-to-projection lag under five seconds, replay reaffirmed as a hard filter, no per-subject ordering or throughput pressure added from CoachingMay 2deliveryInput on the dispatcher SDK build plan asks; no Phase 1 need from Delivery's seat, bus-choice constraints are producer-side transactional emit (weighted highest), per-subject ordering, modest throughput, seconds-not-minutes latency, useful-but-not-date-critical replayMay 2growthGrowth's input on the two open build-plan asks; no Phase 1 need on the critical path, no constraints from Growth's seat that flip the trade-off, paid-campaign burstiness declared for the trigger-to-revisit baseline, filing after ADR-0009 acceptanceMay 2platformADR-0009 (cross-process transport for the dispatcher SDK) moved to Status Accepted; Postgres-backed queue with LISTEN/NOTIFY is the v1 transport with NATS JetStream as the named successor; Phase 2 of the SDK build is ungatedMay 2platformADR-0009 (cross-process transport for the dispatcher SDK) drafted as Status Proposed; Postgres-backed queue with LISTEN/NOTIFY is Platform's draft choice with NATS as the named successor; consumer review window closes 2026-05-29May 2platformDispatcher SDK build plan follow-up; placeholder timeline replaced with confirmed dates, Phase 2 ships 2026-06-26 and Phase 3 ships 2026-07-10, Phase 1 deferred indefinitely subject to consumer pushback by 2026-05-15May 2platformPhase 0 of the dispatcher SDK build is in; schemas, registry, SDK surface, tests, and CI gate all landed; consumer domains can scaffold integration code against the public surface todayMay 2revenueClosing Revenue's leg of the dispatcher SDK build plan asks; no Phase 1 need on Revenue's critical path, strong endorsement of Postgres-queue for ADR-0009 because the producer transactional guarantee against the ledger is the load-bearing constraintMay 2salesClosing Sales' leg of the dispatcher SDK build plan input; no Phase 1 critical-path need, no bus-choice constraint that would have flipped ADR-0009May 5revenueRevenue's Phase 2 dispatcher producer wiring lands a per-domain copy of the four Phase 2 tables (DispatcherEvent, DispatcherCursor, DispatcherDedup, DispatcherDeadLetter) in the revenue schema; the producer-transactional-guarantee from ADR-0009 forces this under the two-Supabase-project topology because Revenue is in sguild-domains while Platform's authoritative copies are in sguild-platform and cross-database transactions are not supported; asking Platform to confirm the per-domain shape is the intended fan-out and to amend ADR-0009 (or the Phase 2 ship memo) to document it; flagging the consumer-side question of which producing domain's table a subscriber reads from given producer values on the envelope; raising the related question of whether a per-domain dispatcher schema (separate from each domain's business schema) is a cleaner placement than each domain's own schemaMay 6platformPlatform confirms the per-domain dispatcher table shape for ADR-0009 under the two-Supabase-project topologyMay 9platformDispatcher SDK Phase 2 is production-live; bus dispatcher MVP shipped with all five slices landed (schema and ajv, Postgres-queue publish path, polling consumer with dedup retry and dead-letter, LISTEN NOTIFY wake-up, per-consumer DLQ read and resolve API), Q2 directive Phase 2 commitment closes 13 days early, producers and consumers can wire against the live transport todayMay 14deliveryHow should Delivery consume the dispatcher producer SDK; vendored copy of lib/dispatcher or a published package, asking Platform to confirm the shape before Delivery vendorsMay 14deliverylesson-lifecycle contract v1.0.0 filed with lesson.delivered and lesson.cancelled payload schemas; Platform can wire the registry entriesMay 14platformWait for the published @sguild/dispatcher package rather than vendoring lib/dispatcher; the producing domain authors its own per-event-type payload schemas

View source on GitHub