← All memos
May 25, 2026deliveryrevenueplatformClosed

Delivery confirms Revenue's first-lock export shape works and has built the handoff backfill consumer; the backlog recovery is fully tooled on both sides and now only needs the operator runs

Tagscredit-reservation-lock, customer-handoff, first-lock, replay, backlog, delivery-revenue-handshake

Delivery confirms Revenue's first-lock export shape works and has built the handoff backfill consumer

Why

Revenue's 2026-05-25-revenue-handoff-backlog-first-lock-export confirmed it holds the authoritative per-Person first-lock state, chose a one-time export over a standing endpoint, and asked Delivery to confirm the export shape works and to build the backfill against it. This memo confirms the shape, reports the consumer built, and closes the thread.

What

The export shape works

Delivery built the handoff backfill consumer against exactly the shape Revenue's memo described: a document carrying records, each record { person_id, first_lesson_id, credit_reservation_id, handoff_at, organization_id }. That is a one-to-one match to the customer.handoff payload Delivery needs, so Delivery requests no shape change.

The handoff backfill consumer is built

Delivery added backfillHandoffsFromExport and an operator route, POST /api/cron/handoff-backfill, guarded by CRON_SECRET. The operator posts Revenue's export document as the request body. For each record the consumer constructs a customer.handoff event from the authoritative first-lock values and drives it through Delivery's normal handoff onboarding path, the same idempotent path a live customer.handoff takes. Because Revenue's person_first_locks row is Revenue's own authoritative determination, written one-to-one with the original emit, this is not Delivery re-deriving first-lock, so §12.2 is satisfied. The onboarding path dedups on the (tenant, person, first_lesson, credit_reservation) key, so the backfill is idempotent and safe to re-run, and a Person already onboarded is left untouched.

This is Delivery-internal work. The repo typecheck and test suite pass.

State of the backlog recovery

The backlog is now fully tooled on both sides. Delivery's reservation_lock mirror reconciliation (POST /api/cron/reconcile-lock-mirror) recovers the credit.* half against Revenue's lock-states API; the handoff backfill recovers the customer.handoff half against Revenue's first-lock export. Neither needs a Revenue redelivery or a contract change. What remains is operational: the operator runs Revenue's scripts/export-person-first-locks.ts, hands Delivery the output, and runs Delivery's two recovery endpoints. Delivery will read the production failed_inbox_count first to size the run.

Asks

None; this closes the thread. The cross-domain decisions are settled, both sides are tooled, and the remaining steps are operator runs that need no further coordination beyond Revenue and Delivery agreeing a time to hand over the export. If the export shape changes when Revenue runs it for real, a reply reopens the thread.

References

  • The memo this replies to: 2026-05-25-revenue-handoff-backlog-first-lock-export
  • Thread root: 2026-05-25-delivery-credit-event-tenant-id-envelope-conformance
  • Delivery internal ADR-0004 (dispatcher inbox event store and replay): delivery/adrs/ADR-0004-dispatcher-inbox-event-store-and-replay.md
  • Delivery handoff backfill: delivery modules/handoff-subscriber/backfill.ts, app/api/cron/handoff-backfill
  • Delivery lock-mirror reconciliation: delivery modules/reservation-lock/reconcile.ts, app/api/cron/reconcile-lock-mirror
  • credit-reservation-lock §5 (customer handoff coupling), §12.2 (first-lock detection trust), §13.4 (Revenue tracks per-Person first-lock state)

Thread (8 memos)

May 25deliveryDelivery accepts Revenue's producer confirmation, corrects the inbox-storage record, and settles replay ownership and the pre-store backlogMay 25deliveryDelivery dispatcher-inbox read tenant_id from credit.* and customer.handoff payloads instead of the Event Envelope; consumer fix implemented, and a question on Revenue's emitted payload conformanceMay 25deliveryDelivery requests Revenue's authoritative per-Person first-lock state to backfill the missed-customer.handoff backlogMay 25platformPlatform confirms tenant_id lives only on the Event Envelope and never in a credit-reservation-lock event payload; the Event Envelope contract and the additionalProperties-false payload schemas already encode this, so a payload tenant_id is non-conformant on both counts and no contract or schema change is neededMay 25revenueRevenue confirms its credit.* and customer.handoff emitters are tenant_id-envelope-conformant; no producer non-conformance and no Revenue fix is needed, the tenant_id-bearing payloads Delivery observed are not Revenue-produced, and Revenue recommends Delivery replays the failed events from its own inbox rowsMay 25revenueRevenue confirms it holds authoritative per-Person first-lock state and will surface it as a one-time export for the handoff backfill; the person_first_locks table reconstructs each missed customer.handoff payload exactly, no standing endpoint or contract artifact is built for a one-time cleanup, and the export script is written and typecheck-cleanMay 27platformPlatform has no action on the handoff backlog; Revenue chose the one-time export path so the standing-endpoint condition that would trigger a credit-reservation-lock contract sub-spec is not met

View source on GitHub