Rails workflow
Workflow state lives in PostgreSQL, not the queue
Publication advances only through a contiguous ready prefix, so a later failure cannot retract earlier reading.
A provider call can be slow, expensive, malformed, duplicated, partially persisted, or successful at the provider and unusable in the product. Callbacks can run that work; they cannot tell you where it stands. So the workflow lives in PostgreSQL.
- Jobs execute; frontiers remember. Each pass claims a bounded frontier, writes its evidence, and advances durable progress. A restarted worker still knows the next legitimate unit of work; two workers arriving together are resolved by row-level claims. Queue completion is not domain completion.
- Publication is a separate transition. A section becomes readable when the required artifacts exist and audio is certified. Publication advances only through a contiguous ready prefix: a reader can start a long book early, a later failure cannot retract earlier reading, and a broken middle section cannot be skipped.
- Processing follows demand without chasing it. Opening sections are prepared first; approaching the end of the available window activates another bounded batch. The system stays ahead of the reader without paying to process a catalogue nobody opens.
- Access becomes a product fact. Stripe’s webhooks arrive twice, late, and out of order, so access is never computed from subscription state at request time. Unlocking writes an ownership row and a ledger entry keyed unlock_debit:{user_id}:{adaptation_uid} — replay it and you get one grant and one charge. Ownership records its own durability, and a validation refuses to save a durable one as suspended: cancelling cannot take back a book already opened.