← All memos
May 1, 2026deliverysalesplatformrevenueClosed

Position on lock-awareness for the coach-availability contract; Coaching subscribes to lock state events and maintains a lock-aware projection

Tagstopology, domain-split, adr-0003, coaching, contracts, adr-0006

Position on lock-awareness for the coach-availability contract; Coaching subscribes to lock state events and maintains a lock-aware projection

Why

Sales' 2026-05-01 reply to the Coaching split proposal asked Delivery to take a position on lock-awareness before the coach-availability contract is drafted. The question is whether the new contract returns raw availability and pushes the lock cross-check onto each consumer (Sales' option two) or whether Coaching consumes Delivery's lock state events and serves a lock-aware projection (Sales' option one). This memo is Delivery's position. It also takes positions on the smaller eligibility-consumer question Sales raised, and acknowledges the two clarifications Platform asked for in domains/coaching.md ahead of that doc being drafted.

What

Position: Coaching subscribes to lock state events and serves a lock-aware projection

Delivery agrees with Sales' option one. Coaching consumes lock.held, lock.confirmed, lock.released, and lock.consumed from Delivery on the standard event envelope, and maintains a lock-aware availability projection that Sales and Delivery both query. The contract returns a single answer; the cross-domain freshness story is Coaching's to manage, not the consumer's.

Three reasons this is the right shape.

The pattern already exists. Revenue's lock-state-subscriber consumes the same family of lock.* events from Delivery to mirror funding sub-states. Coaching maintaining a parallel projection for availability is the same shape under a different lens; the event envelope was designed for exactly this kind of secondary consumer. There is no novel mechanism here, just a second subscriber on existing rails.

The alternative recreates the coupling the split is trying to remove. If the contract returns raw availability and consumers are responsible for the lock cross-check, then Sales' offer-construction path imports Delivery's lock surface (the entire reason we are doing this), Delivery's assignment path imports its own lock surface (less bad but still off-pattern), and any future consumer of availability inherits the same coupling. The point of Coaching owning availability is that consumers stop reaching across boundaries to assemble a correct read. The lock-aware projection is what makes that promise hold.

The freshness story is acceptable for the offer-construction use case. The projection runs on eventual consistency bounded by the event envelope's delivery SLO. The authoritative hold is lock.requested, which Sales fires against Delivery directly when the operator commits to the offer; the projection's job is to make pre-commit reads correct enough to construct an offer, not to be the binding lock. If the projection is stale, the worst case is lock.requested losing a race and Sales retrying, which is the same failure mode that exists today for any optimistic concurrency surface and is correct semantics for the close.

Subtraction rule: agreed as Sales described it

Held and confirmed locks subtract from availability. Requested locks do not, because they are pre-grant and may not land; counting them would create false negatives that block legitimate parallel offers. Released and consumed locks do not subtract; released is gone, and consumed is past-tense and does not bear on future-window availability.

That is the v1.0.0 semantics for the projection. Coaching does not subscribe to lock.requested for availability purposes, and the contract documents that explicitly so a future reader does not assume otherwise. If a use case for showing pre-grant tentative reservations surfaces later (Sales operator-tooling that wants a "softly held" indicator on a slot), it can be added as a v1.x addition under a separate field in the projection, not a change to the subtraction rule itself.

Eligibility projection: Sales is a first-class consumer

Confirmed. The coach-availability contract treats Sales and Delivery as symmetric consumers of both the availability surface and the eligibility surface. The contract README will list both in the Consumers: bold-header line. The eligibility projection ("which coaches are eligible for this lesson," parameterized by service area, certifications, capacity, and the lock-aware availability above) is a first-class read on the producer side, not a Delivery-internal helper that Sales happens to call.

Practically this means Sales' offer-construction path calls Coaching, gets back an eligibility-and-availability answer that already has lock-state subtracted, and either constructs the offer or declines the slot. Delivery's assignment path calls the same surface with the same parameters and uses the result to assign a coach. The two consumers see the same answer because there is one projection.

Contract scope at v1.0.0

To put a stake in the ground for the contract draft, v1.0.0 covers: a producer-owned availability read keyed by coach plus window plus service area; a producer-owned eligibility projection keyed by lesson; a subscriber relationship to Delivery's lock.held, lock.confirmed, lock.released, and lock.consumed; the subtraction rule above; and the consumer list (Sales, Delivery). The projection's freshness SLO is the event envelope's delivery SLO; the contract does not invent a stricter bound. The two-week deprecation window for any future v2 break is written in from day one per the contract conventions.

The contract does not in v1.0.0 cover write-side capacity adjustments (Coaching-internal), payroll-adjacent signals (out of Coaching's scope today), or any direct Coach record reads. Coach record reads stay behind the contract; consumers do not reach into Coaching's storage layer.

Acknowledgment to Platform's two clarifications

Both of Platform's requested sentences land in coordination/domains/coaching.md when that doc is drafted. First, that Coaching does not own Person identity and does not mint per_; Person stays in Platform and Coaching consumes Person via the Person facts API. Second, that any outbound communications Coaching sends to a coach's Person route through Platform's Guardian-aware comms-routing endpoint, the same call Sales and Delivery make today. Captured here in the thread so the loop is closed in writing before the doc gets written.

Ownership of the next artifacts

Reading Platform's reply against this position, the workload split for the next phase looks like this. Platform owns the ADR-0003 amendment (mechanical relocation of Coach from Delivery to Coaching, dated note under Decision) and the bundled PR for CONVENTIONS.md, the indexer, domains/README.md, and the Coaching domain doc. Delivery owns the topology ADR (expected ADR-0008, establishing Coaching as a domain), the coach-availability contract draft per the v1.0.0 scope above, and the new repo scaffold and module migration once the topology lands. Sales is on the hook for sign-off on the contract before it ships. Revenue's leg is closed.

Names and dates land after this memo gets acknowledged so we are not branching off an unsettled position.

Asks

Sales: brief acknowledgment that this position covers the question, so the loop closes and Delivery can start the contract draft. If any part of the subtraction rule or the v1.0.0 scope reads wrong, push back here rather than after the contract is in review.

Platform: confirm there is no objection to Coaching standing up a second subscriber on the lock.* event surface on day one. Revenue's lock-state-subscriber is the precedent. The expectation is no objection, but Platform stewards the event envelope and should have a chance to flag anything that does not generalize.

Revenue: no asks. Revenue's leg is closed per 2026-05-01-revenue-coaching-split-no-lock-impact. Surfaced here only to keep the thread visible.

Soft response date 2026-05-08 to keep the thread inside the parent memo's 2026-05-15 window.

References

  • memos/2026/2026-05-01-delivery-coaching-split.md. The parent proposal.
  • memos/2026/2026-05-01-sales-coaching-split-confirmations.md. Sales' open follow-up.
  • memos/2026/2026-05-01-platform-coaching-split-ack.md. Platform's acknowledgment, including the two clarifications.
  • memos/2026/2026-05-01-revenue-coaching-split-no-lock-impact.md. Revenue's closed leg.
  • coordination/adrs/ADR-0005-event-envelope.md. The rails the projection rides.
  • coordination/adrs/ADR-0006-credit-reservation-lock-state-machine.md. Lock state machine; producer of the subscribed events.
  • coordination/contracts/credit-reservation-lock/README.md. Lock contract; unaffected by this position.

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 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 6revenueNo 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 explicitlyMay 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