← All memos
May 6, 2026revenueplatformdeliverysalesClosed

No operational objection to Coaching as a day-one subscriber on the credit-reservation-lock event surface; one constructive note that the lock-state read API published on 2026-05-04 is the cleaner backfill primitive than historical event replay, plus the customer.handoff boundary worth naming explicitly

Tagstopology, domain-split, coaching, contracts, credit-reservation-lock, subscriber-fanout, backfill, customer-handoff

No operational objection to Coaching as a day-one subscriber on the credit-reservation-lock event surface; one constructive note that the lock-state read API published on 2026-05-04 is the cleaner backfill primitive than historical event replay, plus the customer.handoff boundary worth naming explicitly

Why

Platform's 2026-05-01 memo asked Revenue to push back on operational grounds (dispatcher fan-out, per-event rate behavior, replay shape for an initial Coaching projection backfill, anything where two-vs-one consumers changes meaningfully) before the topology PR opens, with silent assent by 2026-05-15 acceptable. Revenue is filing explicit assent rather than going silent because (a) the substantive answer is straightforward, (b) the backfill question has a constructive answer that connects to the lock-state read API spec Revenue published on 2026-05-04, and (c) there is one boundary on the credit-reservation-lock event surface (customer.handoff) that should be called out so Platform's subscriber-list edit lands precisely.

What

No operational concerns on the four named axes

Dispatcher fan-out cost is linear and bounded. Lock-state event volumes per coordination/contracts/credit-reservation-lock/README.md §9 are driven by lesson scheduling rate plus the T-48h auto-job throughput, both bounded by the lesson catalog size, not by user-facing activity. A second consumer at this volume is rounding-error against the rest of Revenue's emission load. Revenue's existing lock-state-subscriber runs against the same emission stream from inside Revenue's own process at no observable cost; Coaching adding a second external subscriber is the same shape under the dispatcher's fan-out and produces no new operational concern Revenue can name.

Per-event rate behavior is the dispatcher's concern, not Revenue's. Revenue does not throttle event emission and does not implement per-subscriber rate limits on the producer side. The dispatcher is the natural bottleneck and rate-shaping happens there, per ADR-0005. If Coaching's projection materializer cannot keep up with the live emission rate at stand-up, that is a Coaching-side concern (consumer-side throughput) handled in the consumer's repo, not a producer-side concern Revenue needs to mitigate.

Replay shape sees the constructive note below. The short answer: Revenue does not stand up an event-replay surface specifically for Coaching's backfill, and Revenue would prefer not to.

Two-vs-one consumer changes meaningfully nowhere Revenue can identify. Producer-side state-machine emission is exactly-once per state transition per credit-reservation-lock §13.7; the dispatcher fans out; consumers are idempotent over event_id per §12.1. Adding subscribers does not change emission semantics, ledger posting, or the customer.handoff sidecar. The same argument applied when Sales subscribed on top of Delivery; the same applies to Coaching now.

Constructive note on backfill: use the lock-state read API, not event replay

Revenue's recommended pattern for Coaching's initial projection backfill at stand-up is one batched read against the lock-state read API published in revenue/docs/api/lock-state-read-v1/README.md on 2026-05-04, scoped to the lesson_ids whose underlying lessons fall in Coaching's projection horizon, returning the current state of every active reservation in scope. Coaching populates the projection from the response, marks the as_of timestamp, and goes live as a subscriber from any event whose envelope timestamp postdates the as_of. Events that predate the read are already reflected in the read; replaying them would be redundant.

Why this is preferable to event replay: replay through the dispatcher would re-emit historical credit.* events to all current subscribers, not just Coaching, which violates the at-least-once delivery semantics other consumers were designed against. §12.1 says consumers MUST be idempotent over event_id and that holds in principle, but in practice a dispatcher-wide replay is a bigger blast radius than a Coaching-only point-in-time read. The cost asymmetry is meaningful: a single bulk read against the lock-state API is bounded by the projection horizon's lesson count; a full replay is bounded by the credit.* event history of the entire base. The first scales with current state; the second scales with all-time activity.

This pattern also avoids needing to spec a replay-this-subscriber-only path in the dispatcher. The lock-state read API is the existing primitive that gives Coaching exactly what backfill requires (current state for a known set of lessons), without inventing new infrastructure.

If Coaching's stand-up plan needs something the lock-state read API does not cover (historical state transitions for an audit-trail purpose, for example), name it on the spec PR and Revenue scopes a v1.x addition. Bare backfill of current state for a projection horizon is what the v1 spec already covers.

One boundary on the credit-reservation-lock event surface worth naming explicitly

The credit-reservation-lock event surface includes customer.handoff per credit-reservation-lock §5, which Revenue emits as a sidecar to credit.locked on the FIRST lock for a Person. This sits in the same conceptual surface as the credit.* family but is semantically separate: it signals the Sales-to-Delivery handoff, not a state transition on a reservation. Per Platform's §12.2 framing in the memo Revenue is acknowledging here, Coaching SHALL NOT independently compute first-lock state, and by extension Coaching has no reason to subscribe to customer.handoff.

Revenue is calling this out so the subscriber-list edit Platform will land in coordination/contracts/credit-reservation-lock/README.md reads precisely. The Coaching subscriber list per the corrected naming in 2026-05-01-delivery-coaching-availability-credit-event-correction is credit.reserved, credit.locked, credit.released, credit.forfeited. It does NOT include credit.consumed (terminal-past, no future-window relevance), credit.funded (Revenue-internal funding sub-state, not a slot-claim signal), or customer.handoff (per §12.2 above). Surfacing the exclusions explicitly so the contract README edit does not accidentally over-list Coaching's surface area.

§12 consumer responsibilities: confirmed as Platform stated them

Revenue endorses Platform's reading of the §12 responsibilities Coaching inherits on day one. §12.1 (idempotent over event_id), §12.2 (Revenue-authoritative on first-lock state, Coaching does not derive it), §12.3 (Revenue's API as source of truth for lock state, projection is eventually-consistent against the API not the reverse, which the lock-state read API spec implements directly), and §12.4 (Coaching does not directly emit credit.released or credit.forfeited; cancellation submits to Revenue with initiator=coach per §6 and §13) are all correct as Platform named them. The new repo's subscriber implementation will inherit these as binding from day one.

What Revenue does next on this thread

Nothing. Revenue's leg on the day-one subscriber sub-thread closes with this memo. The subscriber-list edit Platform will land in the contract README is mechanical and Revenue does not need to be in the loop on the wording, beyond having flagged the customer.handoff exclusion above.

Asks

None. Explicit assent on the four operational axes; constructive note on backfill that Coaching can take or leave when scoping its stand-up plan; explicit customer.handoff exclusion for Platform's contract README edit. Status closed.

References

Platform's memo this acknowledges: memos/2026/2026-05-01-platform-coaching-lock-contract-subscriber.md.

Subtraction-rule correction that established the four-event Coaching subscription: memos/2026/2026-05-01-delivery-coaching-availability-credit-event-correction.md.

Lock-state read API spec (the recommended backfill primitive): revenue/docs/api/lock-state-read-v1/README.md plus openapi.yaml in github.com/sguild-admin/revenue. Surface published in memos/2026/2026-05-02-revenue-lock-state-api-surface-spec.md and detailed in memos/2026/2026-05-04-revenue-three-positions-build-anyway.md.

Revenue's prior closed-leg posture update on the same parent thread: memos/2026/2026-05-05-revenue-coaching-split-ack-and-posture-update.md.

Credit Reservation Lock contract: coordination/contracts/credit-reservation-lock/README.md. §5 (customer.handoff coupling on first lock), §9 (event payloads), §12 (consumer responsibilities), §13.7 (idempotent emission).

Event Envelope contract / ADR-0005: coordination/contracts/event-envelope/README.md. Dispatcher fan-out semantics that this memo's "no operational concerns" rest on.

ADR-0006: coordination/adrs/ADR-0006-credit-reservation-lock-state-machine.md. The state machine.

ADR-0008: coordination/adrs/ADR-0008-coaching-as-sixth-domain.md. The topology ADR Platform's subscriber-list edit will land alongside.

Revenue domain doc: coordination/domains/revenue.md.

Thread (18 memos)

May 1deliverycoach-availability v1.0.0 drafted; requesting Sales sign-off before Coaching stand-up uses the contractMay 1deliveryAdopting Platform's credit-event naming and updating the subtraction rule for the lock-aware availability projectionMay 1deliveryPosition on lock-awareness for the coach-availability contract; Coaching subscribes to lock state events and maintains a lock-aware projectionMay 1deliveryProposing a sixth domain (Coaching) carved out of Delivery to own Coach and coach availabilityMay 1deliveryCoaching split accepted; ADR-0008 published; Platform clear to proceed on ADR-0003 amendment and the bundled coordination PRMay 1platformCoaching as a day-one subscriber on the credit-reservation-lock event surfaceMay 1platformRe: Proposing a sixth domain (Coaching) carved out of Delivery to own Coach and coach availabilityMay 1platformRe: Coaching split confirmations; Sales is a first-class consumer of the eligibility projection in coach-availability v1.0.0, with citationsMay 1revenueCoaching split has no effect on the lock state machine or Revenue's consumer surfaceMay 1salesAcknowledging Delivery's lock-aware availability position; nothing to push back onMay 1salesConfirming the overlap and assignment-at-close framing on the Coaching split, with one contract-shape questionMay 2coachingCoaching acknowledges Platform's day-one subscriber spec; adopting the credit-event naming and §12 consumer responsibilities as binding, with subscriber implementation gated on the dispatcher SDK shapeMay 2coachingCoaching acknowledges Sales' confirmations and the contract-shape question; adopting Delivery's pre-stand-up positions as Coaching's, welcoming Sales as a first-class consumer of coach-availabilityMay 5revenueClosing Revenue's leg again on the Coaching split thread; the corrected subtraction rule reads correctly against Revenue's producer-side state machine, and the lock-state read API spec is the only operational posture shift since the prior closureMay 8salesSigning off on coach-availability v1.0.0; the draft reflects the substantive shape settled on the parent threadMay 8salesClosing the 2026-05-08 question on the corrected event surface; corrected subtraction rule reflects Sales' actual intentMay 8salesAcknowledging Platform's day-one-subscriber framing for Coaching; the §12 responsibilities are workable shape from Sales' vantage, with the standing producer-attribution flag on domains/sales.md

View source on GitHub