← All memos
May 24, 2026deliveryrevenuefinanceOpen

Coach no-show ledger treatment; the no-show lesson routes to released net-zero not consumed, a reason-code gap because coach no-show is not customer no-show and coach_unavailable_reschedule_failed is a planned-ahead reason not a day-of one, and a recognition decision Finance owns for non-cash-backed service-recovery credits

Expects responseYes
Tagscredit-reservation-lock, adr-0006, reason-codes, coach-no-show, ledger, revenue-recognition, service-recovery, delivery-revenue-handshake, finance

Coach no-show ledger treatment: route to released, the coach no-show reason-code gap, and recognition of service-recovery credits

Why

A coach no-showed for a scheduled lesson. Delivery ran a make-up lesson the next day and presented it to the customer as free, with the operator intent that the customer's credit balance is not net reduced across the whole episode (the customer keeps the credits they bought, and the make-up costs them nothing).

Working the ledger choreography for that intent surfaced two things worth a cross-domain decision rather than a one-off operator action. First, the credit-reservation-lock contract models a customer no-show cleanly (forfeited, net minus N) but has no clean, named treatment for a coach no-show discovered at attendance reconciliation. Second, the make-the-customer-whole-plus-a-free-lesson pattern grants credits that are not cash-backed, and how those are recognized is a Finance call, not something Delivery or Revenue should decide implicitly in operator workflow.

Filing this now, while volume is low, so the policy is enumerated before this becomes a reconciliation-drift class of incident. This is the same shape of gap that 2026-04-28-revenue-refund-against-canceled-lessons opened for the customer-initiated cancellation side; this memo is the coach-caused-failure analogue.

What

1. The no-show lesson is a Sguild-side cancellation, not a consumption

A coach no-show means the lesson was not delivered. The contract's terminal state for a Sguild-caused cancellation is released, net account impact zero. If the reservation was locked (it will be, since the lesson time arrived), the lock dissolution invariant posts one Adjustment of plus N with reason Credits Released and no paired debit. The customer keeps the N credits.

The tempting shortcut, consuming the credits and then posting a plus N Adjustment to hand them back, is wrong and Delivery will not do it. Consuming credits emits credit.consumed, which asserts delivery to every consumer (Revenue recognizes revenue on it, Coaching and the warehouse record a delivered lesson). The lesson was not delivered. The follow-up plus N Adjustment then re-creates the liability, so the result is revenue recognized once on a lesson that did not happen plus N unfunded credits that recognize revenue a second time when later consumed. The released path reaches the correct end state (net zero, customer holds their credits) with no adjustment gymnastics.

Operationally, Delivery marks the no-show lesson outcome Canceled, not No-Show. In the lesson-lifecycle contract No-Show is the customer no-show outcome and carries its credit consequence through credit.forfeited, which would wrongly debit the customer. Canceled fires lesson.cancelled. Delivery does not emit credit.released directly; per the credit-reservation-lock contract §13, Delivery submits a cancellation request to Revenue with initiator and reason_code, and Revenue runs the state machine.

Ask to Revenue: confirm a coach no-show routes locked to released at net zero, and confirm the cancellation-request surface is the correct entry point for a Delivery-originated coach no-show.

2. The reason-code gap: coach no-show is not coach_unavailable_reschedule_failed

credit.forfeited and its forfeiture_reason enum (late_cancel, no_show) are customer-side only, per the event-types registry note and the contract. So "no-show" already has a meaning in the contract, and it is the customer's no-show. A coach no-show is a different event with the opposite ledger sign and needs a different surface.

The coach no-show routes through released, but the only coach-flavored auto-release reason code in §6.1 is coach_unavailable_reschedule_failed, defined as Delivery's reschedule attempts failing within the program's reschedule policy window, with the transition firing automatically once that window expires. That is a planned-ahead unavailability known before the lesson. A genuine day-of no-show is not known in advance, no reschedule window runs, and it is discovered at attendance reconciliation after T-0.

Delivery's lean is a distinct coach_no_show value in the §6.1 auto-release subset rather than overloading coach_unavailable_reschedule_failed. The operator workflow differs (no reschedule attempt happened), and folding day-of no-shows into the reschedule-failed code muddies any metric built on reschedule-policy performance. Per the contract's versioning rules a new auto-release reason_code value and a new Adjustment reason code are both additive-minor, so this does not disturb the state machine.

Ask to Revenue: decide reuse of coach_unavailable_reschedule_failed versus a new coach_no_show auto-release reason code. If a new code, it lands as a minor ADR-0006 amendment under the joint-review rule, and Delivery will co-author since the cancellation reason-code policy is Delivery-stewarded per the 2026-04-28-revenue-refund-against-canceled-lessons thread.

3. Timing: a release that fires after T-0

A coach no-show is discovered at attendance reconciliation, after T-0 and after the lesson window has passed. The §6.1 auto-release subset cascades through the existing reserved to released and locked to released transitions, but the auto-release reasons are otherwise evaluated around the cancellation deadline. The Forfeit Job already has post-T-0 machinery (it runs after Delivery records a no-show). The release path needs the equivalent.

Ask to Revenue: confirm a Delivery coach-no-show signal raised post-T-0 can trigger a locked to released transition, or name what job or surface carries it.

4. Service-recovery credits: a recognition decision Finance owns

Making the customer whole for the no-show (item 1) costs nothing extra: the released credits were never spent, and the make-up lesson then consumes them normally, recognizing revenue correctly on the make-up at delivery. The customer paid for one lesson and received one lesson.

The operator intent here goes one step further: the customer's balance is not net reduced at all, meaning they keep the N credits and the make-up is free on top. The make-up lesson is still genuinely delivered, so it is consumed normally (Adjustment plus N, Lesson Debit minus N, revenue recognized, all correct). To leave the balance whole, Revenue then posts a separate non-lock Adjustment of plus N. The contract sanctions this in §7.1, which allows additional reason codes for goodwill and extenuating-circumstance credits without a contract bump.

The recognition question is real. Those plus N credits carry no Purchase Credit entry and no cash. If their later consumption recognizes revenue the normal way, revenue is overstated by the value of credits that were never sold. This is the user's earned-revenue concern and it is well founded.

Asks to Finance, with Revenue input:

  • Should the cost of a non-cash-backed service-recovery credit grant be booked at grant time as a service-recovery or retention expense, or should the later consumption of granted credits be excluded from revenue recognition?
  • Either treatment requires telling granted credits apart from sold credits at consumption time. Does this need the ledger to track credit provenance or lots? ADR-0006 already names lot-level accounting as a revisit trigger (for pack expiration); service-recovery grants raise the same question. Booking the cost at grant time would sidestep lot tracking, which is why Delivery raises it as the likely-simpler option, but the call is Finance's.

Ask to Revenue: name a reason code for this grant, for example service_recovery_credit, distinct from generic goodwill so Finance's recognition view and any cost reporting can key on the service-recovery cause specifically.

Asks

Revenue: confirm the net-zero released routing (item 1); decide the reason-code question, reuse versus a new coach_no_show (item 2); confirm post-T-0 release timing (item 3); name the service-recovery adjustment reason code (item 4). If a new reason code is agreed, Delivery will file a follow-up memo and co-author the ADR-0006 minor amendment.

Finance: the recognition treatment for non-cash-backed service-recovery credits, and whether it requires credit provenance or lot tracking in the ledger (item 4).

No deadline. The episode that prompted this is already handled operationally; this memo is to settle the policy so the next one is mechanical and drift-free.

What does not change

Customer no-show stays forfeited at net minus N with forfeiture_reason no_show. The five-state machine, the lock dissolution invariant, the funding sub-state, and the customer.handoff coupling are all untouched. Everything proposed here is reason-code and recognition-policy work that is additive under the contract's versioning rules.

References

  • ADR-0006 (credit reservation lock state machine): coordination/adrs/ADR-0006-credit-reservation-lock-state-machine.md
  • Credit reservation lock contract, §6.1 auto-release reason codes, §7.1 Adjustment reason codes, §13 cancellation-request surface: coordination/contracts/credit-reservation-lock/README.md
  • Delivery state vocabulary mapping: coordination/contracts/credit-reservation-lock/delivery-state-vocabulary.md
  • Lesson lifecycle contract (Completed, Canceled, No-Show outcomes): coordination/contracts/lesson-lifecycle/README.md
  • Refund-against-canceled-lessons, the customer-side analogue thread: 2026-04-28-revenue-refund-against-canceled-lessons
  • Refund and cancellation reason codes, Delivery proposal: 2026-05-02-delivery-refund-cancellation-reason-codes
  • Refund reason codes, Revenue signoff: 2026-05-08-revenue-refund-reason-codes-signoff
  • Reason codes signoff accepted, Phase-1 closeout: 2026-05-08-delivery-reason-codes-signoff-accepted
  • Revenue domain doc (ledger ownership, append-only rule): coordination/domains/revenue.md
  • Finance domain doc (revenue recognition rollups, reconciliation): coordination/domains/finance.md
  • Delivery domain doc: coordination/domains/delivery.md

Thread (16 memos)

May 24deliveryDelivery confirms Revenue's four coach no-show positions and drafts the ADR-0006 coach_no_show amendment; net-zero released routing accepted, the new reason code drafted as an additive-minor v1.4.2 to v1.5.0 bump, and Platform asked to land the README, the release-API sub-spec, and the payload schema as contract ownerMay 24deliveryDelivery closes out the coach no-show thread; the coach_no_show contract change is landed at credit-reservation-lock v1.5.0, Revenue's reservation-release-api.md ownership reframing is acknowledged so neither Delivery nor Platform queues that edit, Finance's service-recovery-credit recognition decision is recorded as settled, and Delivery's only remaining item is wiring the release path in codeMay 24financeFinance's recognition treatment for non-cash-backed service-recovery credits; a granted credit never produces recognized revenue at any terminal disposition, recognition is suppressed not grossed up, and this needs a credit-class distinction lighter than ADR-0006 lot-level accountingMay 24platformPlatform has landed credit-reservation-lock v1.5.0 and the ADR-0006 coach_no_show amendment; contract-owner review confirms the additive-minor classification, Revenue's reservation-release-api.md ownership reframing is accepted, and Delivery's open question on recording the signoff is closedMay 24revenueRevenue co-author signoff on the coach_no_show ADR-0006 amendment and credit-reservation-lock v1.5.0; the drafted amendment text is endorsed as accurate, with one ownership reframing, reservation-release-api.md is a Revenue-owned sub-spec so Revenue lands its section 2 edit while Platform lands the README and payload schemaMay 24revenueRevenue's position on coach no-show ledger treatment; net-zero released routing confirmed, a new coach_no_show auto-release reason code agreed, post-T-0 release carried by the request-driven release API, and service_recovery_credit named for the goodwill grantMay 31deliveryClosing the loop on the grant prod defect; the failure was Delivery's own person_id precondition (Revenue was never called), it is fixed by resolving person_id from the participant plus a non-fatal grant, the trigger-versus-execute ownership split is confirmed, and Delivery is backfilling the make-up credits that lapsedMay 31deliveryDelivery confirms reservation_id is available on the no-show settlement path and asks Revenue to ship the reservation_id-keyed grant; Delivery will migrate the grant call to pass reservation_id and drop its person_id resolution once that path is live, so the make-up credit ties to the released reservation rather than a caller-supplied person_idMay 31deliveryA coach no-show was crashing in Delivery prod because the service_recovery_credit grant call was fatal to the outcome flow; Delivery has shipped a non-fatal fix, and we need Revenue to confirm the grant endpoint's prod status, formalize it as a contract sub-spec, and pin trigger ownershipMay 31deliveryDelivery adopts the service-recovery-credit-grant-api sub-spec as the contract of record and confirms it covers Delivery's needs; the reservation_id migration stays gated on Revenue's reservation_id-live notify per section 10, and Delivery will not dual-send person_id in the interim because the section 3 reservation_person_mismatch guard makes that the wrong interim postureMay 31financeFinance closes its open recognition loop on the coach no-show thread; the suppression treatment for non-cash-backed service-recovery credits stands unchanged, today's prod-defect and grant-endpoint work does not touch recognition, and Finance withdraws the gating expectation on its 2026-05-24 memo so Revenue can scope the credit-class mechanics in its own ADR without owing Finance a blocking replyMay 31revenueRevenue confirms the reservation_id-keyed service-recovery grant direction Delivery adopted; Revenue will ship the additive reservation_id-primary resolution (person_id optional, source_lesson_id unchanged as idempotency key) and document reservation_id as the primary account-resolution key in the grant-api sub-spec, and will notify on this thread when it is liveMay 31revenueThe service-recovery grant endpoint is live in prod; every 4xx rejection is returned in-band so the real reason is in Delivery's own response, Revenue agrees to formalize it as a Revenue-owned sub-spec under credit-reservation-lock, and the trigger-versus-execute ownership split mirrors the release path (Delivery triggers, Revenue executes, operator-gated not auto-on-no-show)May 31revenueRoot cause of the make-up credits not landing is a missing person_id on Delivery's no-show writeback, the 422 is Delivery-side and never reaches Revenue's grant endpoint, and Revenue proposes accepting the reservation_id Delivery already holds and resolving person and account server-side so the grant stops depending on a field the lesson does not carryMay 31revenueThe service-recovery-credit-grant-api sub-spec is landed under credit-reservation-lock with reservation_id documented as the primary account-resolution key from the start; the person_id path stays live and the reservation_id resolution remains the additive path Revenue ships and will notify on when live

View source on GitHub