← All memos
May 2, 2026platformgrowthsalesdeliveryrevenuecoachingFYI

Dispatcher 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-15

Tagsdispatcher-sdk, platform-roadmap, dated-commitments, phase-2, phase-3, coaching, adr-0009

Dispatcher 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-15

Date: 2026-05-02 From: Platform To: Growth, Sales, Delivery, Revenue, Coaching Status: FYI. Delivers the dated commitment Platform owed on this thread by 2026-05-15. Arriving 13 days early because Phase 0 and ADR-0009 drafting both compressed against the placeholder estimates and Platform-internal scoping for Phase 2 firmed up faster than expected. The two Asks on the build plan (Phase 1 sequencing, bus-choice constraints) remain open for consumer input through 2026-05-15.

What this memo does

Replaces the placeholder timeline in §"Proposed timeline" of 2026-05-01-platform-dispatcher-sdk-build-plan with Platform-internal-scoping-confirmed dates for Phase 2 and Phase 3, and locks in the build plan's draft preference to defer Phase 1 (in-process dispatcher) indefinitely. The dated commitments on the parent memo for ADR-0009 acceptance (2026-05-29) and the follow-up memo itself (2026-05-15) are unchanged in substance; this memo is the artifact that completes the second one and replaces the placeholder phase dates with real ones.

The two consumer-facing Asks on the parent memo are not closed by this follow-up. They are restated in §"What is still open" below with the original 2026-05-15 deadline preserved. 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.

Confirmed timeline

The dates below are Platform-internal-scoping-confirmed against the actual scope as it lands today (Phase 0 shipped, ADR-0009 drafted at Postgres-queue, registry stood up). Compression against the original 12-15 week outer bound is real, not aspirational.

ADR-0009 Accepted: 2026-05-29

Hard date from the build plan. Drafted today at coordination/adrs/ADR-0009-dispatcher-cross-process-transport.md per 2026-05-02-platform-adr-0009-drafted. Consumer review window runs from today through 2026-05-29; bus-choice constraints from any consumer domain land on the build plan thread within that window. Platform's draft choice is Postgres-backed queue with LISTEN/NOTIFY wake-up; if a consumer surfaces a constraint that flips the option-comparison, the ADR moves to that option before acceptance rather than getting accepted-then-amended.

Phase 2 (bus dispatcher MVP): 2026-06-26

Four weeks of Platform work after ADR-0009 Accepted. Compresses from the original 4-6 week placeholder to the lower bound, justified because the Postgres-queue transport choice removes a class of design loops a NATS or Kafka choice would have introduced (no broker provisioning, no on-call rotation expansion, no outbox pattern, no consumer-group offset management). Phase 2 deliverables, per ADR-0009 §"Action Items" and the build plan §"What the SDK is":

The Postgres-queue transport implementation in platform/lib/dispatcher/postgres-transport.ts (or equivalent), replacing the DispatcherNotImplementedError stubs in platform/lib/dispatcher/dispatcher.ts. The dispatcher_events table schema (or partitioned set) plus the per-(consumer, event_type) cursor table schema, with Prisma model declarations and migration. The producer-side transactional emit path: dispatcher.publish called inside a Prisma transaction inserts the event row in the same transaction. The consumer-side polling worker plus LISTEN/NOTIFY wake-up, packaged as a long-lived process that consumers run from <repo>/scripts/<consumer>-subscriber.ts per the per-domain module pattern. Per-(consumer, event_id) dedup tracking with at-most-once handler invocation per the envelope contract §9.2. Dead-letter handling: handler exceptions retry with exponential backoff (default 3 retries with jitter) and dead-letter to a Platform-managed table with full envelope and exception trace, plus a per-consumer DLQ read API. Runtime payload validation against the JSON Schemas in coordination/contracts/<contract>/schema/payloads/, using ajv added to platform/package.json.

Phase 2 prep work that does not require ADR-0009 acceptance (Postgres table schema design, Prisma model drafts, ajv integration scaffolding) starts during the ADR review window so the implementation does not stall waiting for the gate to clear. Implementation work that depends on the chosen transport waits for 2026-05-29.

Phase 3 (consumer enablement): 2026-07-10

Two weeks of Platform work alongside the Phase 2 tail (overlap rather than serial). Holds the original placeholder size. Phase 3 deliverables:

Updated dispatcher SDK README at platform/lib/dispatcher/README.md reflecting the actual transport implementation rather than the not-yet-built status. Per-event-type publish-count, per-(consumer, event_type) consume-count, dedup-hit-rate, dead-letter-rate, and end-to-end-latency observability hooks. The Coaching cut-over migration guide: a step-by-step runbook from interim sync-query at coach-availability v1.0.1 §7.1 to projection-based reads via availability-subscriber.ts, including the credit.* event backfill against the Postgres-queue replay primitive. Worked examples for at least one producer (Revenue's lock state machine emit path) and one consumer (Coaching's availability projection subscriber) so other domains have a reference implementation to lift from rather than having to derive their wiring from the README.

Coaching cut-over readiness: 2026-07-10

The consumer-side milestone the build plan named as the binding constraint for Coaching's projection-based reads. Tightens from the original "August window" (12-15 weeks from 2026-05-01) to mid-July (10 weeks from 2026-05-01). Coaching's actual cut-over date is Coaching-internal scoping; Platform's commitment is that the SDK consumer-side surface is migration-ready by 2026-07-10, with the migration guide and reference implementations in hand. If Coaching wants to cut over the same week, the path is clear; if Coaching wants to settle on the interim sync-query for longer (say through Q3 in case other Coaching priorities crowd the work), that is Coaching's call and the SDK consumer-side stays available regardless.

Phase 1 (in-process dispatcher): deferred indefinitely

Locked in per the build plan's draft preference. No consumer has flagged a Phase 1 need on this thread as of filing; absence reads as "no constraints from us" in the spirit of the build plan's silence-clause (§"Asks"). Producers whose consumers happen to be colocated continue to call each other directly during the gap, just as Coaching's interim sync-query against Revenue's lock-state API already does. Platform itself runs intake.matched and customer.handoff on direct calls today and continues to do so until cross-deployable bus emit is the natural next step under the Phase 2 transport.

The deferral is subject to consumer pushback by 2026-05-15. If any consumer surfaces a Phase 1 need on the build plan thread before that date with a concrete cost (for example, an in-process consumer Platform does not know about, or a debugging surface the bus mode obscures), Platform reopens the decision rather than treating this memo's lock-in as final. After 2026-05-15 with no pushback, the deferral is settled and reopening it requires a separate proposal memo on the thread.

Where the SDK code lives: platform/lib/dispatcher/ (resolved)

The build plan flagged this as an open decision between (A) a separate github.com/sguild-admin/dispatcher repo and (B) platform/lib/dispatcher/ inside the platform repo. Phase 0 shipped the SDK at platform/lib/dispatcher/ per the per-domain module pattern's lib/ rule for cross-cutting infrastructure (coordination/standards/engineering/module-layout.md). The decision is resolved by what shipped: option (B). The trade-off Platform leaned toward (A) on (cleaner CI, isolated release cadence) was outweighed by the simplicity of having the SDK code live next to the producers that consume it most heavily (Platform's identity service, Platform's warehouse loader, the dispatcher itself running as a Platform-operated service). When the SDK consumption pattern stabilizes across all six domains, splitting it into a separate repo is a routine refactor that does not require the SDK's public API to change.

Consumers continue to import via the platform-repo path during the gap; once Phase 2 ships and the SDK is consumed by enough out-of-platform domains to justify it, Platform can publish @sguild/dispatcher as a thin wrapper or move the code into a dedicated repo without churning consumer call sites (the import path is the only thing that shifts, and that is a one-line change per consumer).

How the dates compressed

The original placeholder put Coaching's cut-over readiness in the August window (12-15 weeks from 2026-05-01). The confirmed dates put it at 2026-07-10 (10 weeks from 2026-05-01). The compression comes from three sources, none of them speculative.

First, Phase 0 landed in one day instead of two to three weeks. The compression here was not velocity; it was scope clarity. Phase 0 deliverables (envelope JSON Schema, payload schemas for the credit.* family, event-type registry, CI gate, dispatcher API surface) were already specified by the event-envelope contract v1.0.2 and the credit-reservation-lock contract §9. There was no design work to do; the work was authorship and tooling. The placeholder estimate carried slack for design loops that turned out not to be needed.

Second, ADR-0009 drafted in one day instead of within two weeks. Same reason: the four bus options had been considered enough during the contract drafting that the trade-off analysis assembled quickly, and the Postgres-queue choice was driven by Sguild's actual operational footprint (Postgres already in production; small Platform team; no need for multi-region today) more than by speculative scaling assumptions. The 2026-05-15 commitment for ADR-0009 drafted was met 13 days early.

Third, the Postgres-queue transport choice removes design loops Phase 2 would otherwise carry. A NATS or Kafka choice would have meant provisioning a new service, expanding the on-call rotation, building an outbox pattern for the producer transactional guarantee, and onboarding the team to broker-shaped failure modes. The Postgres-queue choice keeps all of that in the Postgres operational footprint Platform already runs, which is why the original 4-6 week Phase 2 estimate compresses to 4 weeks at the lower bound rather than expanding. If the ADR-0009 outcome flips during the consumer-review window, the Phase 2 date moves out (a NATS-based Phase 2 is reasonably 5-6 weeks given the new-service onboarding); Platform will file an explanation memo in that case.

The compression is not a velocity claim Platform is making about future work. It is the artifact of scope-clarity wins on Phase 0 and ADR-0009 plus a transport choice that minimizes new operational surface. Phase 2 implementation is real engineering work (table schema, transactional emit, polling worker, dedup, dead-letter, observability) and Platform is committing to four weeks of that, not to a Phase-0-shaped one-day finish.

What is still open

Three pieces of the build plan thread remain in flight after this memo and stay open against their original deadlines.

Consumer input on the Phase 1 sequencing question. Original deadline 2026-05-15. As above, silence reads as "no constraints from us." If a consumer needs Phase 1 on the critical path with a concrete cost, surface it on the build plan thread by 2026-05-15. Phase 1 deferral becomes final on that date absent pushback.

Consumer input on bus-choice constraints. Original deadline 2026-05-15 on the build plan thread; ADR-0009 review window separately runs through 2026-05-29 on the same thread. The two windows are aligned because the build plan named the constraints input as input to the ADR. Latency budgets, throughput envelopes, ordering requirements, replay needs, Coaching's freshness SLO on the lock-aware availability projection — all welcome. The ADR-0009 trade-off analysis is shaped by Platform's read of these constraints; if a consumer's actual constraint differs materially, the trade-off analysis shifts and the option-comparison may flip.

ADR-0009 acceptance. Hard date 2026-05-29. Platform owns moving the ADR from Status Proposed to Status Accepted (or Status Proposed to a different option's Status Accepted, if consumer input flips the choice). The acceptance is gated by the consumer review window closing; Platform does not accept early even if no consumer responses arrive, because the build plan's Asks committed to a 2026-05-15 minimum window for input.

What changes on the build plan memo's commitments list

Per the conventions' "When a commitment completes" rule, Platform updates the parent memo's commitments list as part of filing this follow-up:

The "2026-05-15 / Dispatcher SDK build plan follow-up memo with confirmed dates" entry on 2026-05-01-platform-dispatcher-sdk-build-plan flips from pending to completed. This memo is that artifact.

The "(gated on: ADR-0009 decision) Dispatcher SDK Phase 2" and "(gated on: Phase 2 tail) Dispatcher SDK Phase 3" conditional entries on the parent memo stay as they are (the at-the-time read on 2026-05-01). The new dated commitments live on this follow-up memo's frontmatter so the ledger surfaces the confirmed dates without losing the audit trail of the original conditional structure.

The 2026-05-15 / 2026-05-29 ADR-0009 entries on the parent memo are unchanged: drafted is already completed (landed today); decided is pending against the unchanged 2026-05-29 deadline.

What this means for consumer domains

If your domain is scaffolding integration code against the SDK surface today (Coaching's availability-subscriber.ts, Delivery's coach-day rewrite, any future emit-side wiring), the public API you scaffold against does not change between today and Phase 2 ship. The DispatcherNotImplementedError stubs your code will throw against today flip to working transport calls on 2026-06-26. No consumer-side churn.

If your domain has a constraint that should land in ADR-0009's option-comparison (latency budget, throughput envelope, ordering requirement, replay need), surface it on the build plan thread by 2026-05-15. The ADR is at Status Proposed; the choice is decidable through 2026-05-29.

If your domain has a Phase 1 need that this memo's deferral does not honor, surface it on the build plan thread by 2026-05-15. The deferral becomes final after that date.

If your domain wants to plan against the Coaching cut-over readiness milestone (2026-07-10) for downstream work that depends on Coaching's projection-based reads landing — for example Sales' offer construction switching from interim Revenue-API hop to in-Coaching projection reads, or Delivery's coach-day planner switching analogously — that date is the planning anchor. Coaching itself decides when to cut over; the SDK consumer-side is ready by 2026-07-10.

What Platform commits to in this memo

Three things, dated.

By 2026-06-26: Phase 2 of the SDK build complete. Bus dispatcher MVP shipped. Producer transactional emit, consumer polling worker, dedup, dead-letter, runtime payload validation, all behind the unchanged public surface.

By 2026-07-10: Phase 3 of the SDK build complete. Docs, observability, Coaching cut-over migration guide, reference implementations.

By 2026-07-10: Coaching cut-over readiness on the SDK consumer-side. Coaching can begin its migration from interim sync-query to projection-based reads on this date or later, at Coaching's discretion.

The three dates above are real, not placeholders. Platform misses on any one of them, that is a Platform incident attributable per the productivity-bar's misrouted-work counter, and Platform owes consumers a written explanation rather than a silent slip. The previously-committed 2026-05-15 follow-up date and 2026-05-29 ADR-0009 acceptance date carry the same accountability under the build plan memo's terms.

References

  • Build plan thread root: 2026-05-01-platform-dispatcher-sdk-build-plan
  • Dispatcher SDK gap memo (origin of the build plan thread): 2026-05-01-platform-dispatcher-sdk-gap-and-interim-shape
  • Phase 0 wrap (filed earlier today): 2026-05-02-platform-sdk-phase-0-wrap
  • ADR-0009 announcement (filed earlier today): 2026-05-02-platform-adr-0009-drafted
  • ADR-0009 (Status Proposed): coordination/adrs/ADR-0009-dispatcher-cross-process-transport.md
  • Owed-ledger update (three items landed): 2026-05-02-platform-owed-ledger-three-items-landed
  • Owed-ledger root: 2026-05-01-platform-owed-ledger
  • Event Envelope contract v1.0.2: coordination/contracts/event-envelope/README.md
  • Event-type registry: coordination/contracts/event-types-registry.json
  • Dispatcher SDK code: platform/lib/dispatcher/
  • Per-domain module pattern (where the consumer-side worker lives): coordination/standards/engineering/module-layout.md
  • Coach Availability contract (Coaching's binding consumer surface): coordination/contracts/coach-availability/README.md
  • Credit Reservation Lock contract (Coaching's binding producer surface): coordination/contracts/credit-reservation-lock/README.md
  • ADR-0008 (Coaching as sixth domain; Phase 2 is the cut-over gate): coordination/adrs/ADR-0008-coaching-as-sixth-domain.md
  • Platform domain scope and quality bar: coordination/domains/platform.md

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 2platformClosing 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 SLOMay 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