Skip to main content
This is the current payment-truth contract on the Development Engine. The ownership doctrine is unchanged from the Payment Truth Foundation (dated 2026-06-19): the Engine owns payment truth, Stripe is what actually moved, the durable ledger is what survives a restart, and the Admin renders Engine truth. What is new since September is that the Admin now executes real Stripe doors on the owner’s tap, and the truth closes the step.
Quinn Salas, named in the examples below, is a synthetic guest of the private test world that plays Villa Valentin against Development, not a real person. The Stripe objects behind that guest are real test-mode objects. The founder’s direction that opened this lane (2026-09-06): “Test now → flip to live.” and “unless we tackle this head-on we’re going to be beating around the bush and ‘pretending’ when in reality, we should be perfecting the UX around how the property owner/manager/employee actually works the ‘payment.’”

Real Stripe, declared mode

Development runs in test mode with real Stripe test-mode objects (Quinn Salas’s deposit and declined balance are real PaymentIntents in the test account). Live becomes possible, never on: the live flip is one variable on a production service set by the founder’s hand, plus the live webhook endpoint registered by the founder; no code path differs between modes (LUCI-215 phase 01, 2026-09-06). No production service exists and no live flip is evidenced. The Admin shows a quiet “Test mode” footer while in test. The word “sandbox” left the product with this contract; the historical ledger value stays readable so old rows keep their meaning.

One truth function

Payment truth is resolved per obligation (deposit, balance) from the Stripe ledger and the owner’s own rows, by one function that every reader uses: the Algorithm, the Focus house pack, the payment-status read and every money door (LUCI-215 phase 01b, engine dev e0c869f and 5af7703, 2026-09-06).
The event-order rule closes the defect where a paid deposit read as fully paid (Deposit paid reads as fully paid, ALGO-24, engine dev 31fce1c, 2026-09-03; founder: “ship”). ALGO-24’s “round two” (the Postgres ledger as the only financial truth in durable mode) is named on that record as the production gate and is not started. A lying balance field on a booking record cannot move a charge: every money door computes its amount from the ledger.

The money story, in owner words

The Engine serves the record’s words; the Admin reads them, never composes them (Payment page speaks as one, LUCI-242, engine dev 1f7d773, 2026-09-09):
History rows carry kinds (payment-history-kinds/v1, LUCI-245, engine dev e2166b8): card_failed, money_in, asked, refund, dispute, recorded_by_owner, other. The kind is attached from the ledger event that produced the row, never inferred from the sentence (no keyword guardrails); an unmapped row is other, never null. The founder’s ask (2026-09-09): “for anything historical or timeline-ish like this, we should copy Linear with this flowing, connected, vertical element.” Every time word is the property’s own (America/Bahia_Banderas), never a zone name, never a year.

The doors

Each door is a real Stripe action executed on the owner’s tap and never before it. Every tap carries a fresh client_reference, which is the idempotency identity; a network retry of the same tap reuses the same Stripe idempotency key and never mints a second object. The generic create-checkout-session endpoint is retired (LUCI-215 round 2): it trusted the client’s amount and became live-capable with the mode contract. Only the payment-status reads remain on that router. When there is no card on file, the record says so in words: “There’s no card on file for Quinn, so this link asks for one and keeps it for next time.”

Lucia’s draft, one brain

The payment request is drafted by one gateway task, payment_request_draft, pinned to claude-fable-5-1 on Development with no fallback (Lucia asks Quinn for a new card, LUCI-210, 2026-09-06): if Fable cannot draft, the step says so and offers Copy link only. The draft names the guest, the amount and the moment, carries the live checkout link, never a year, never an engine word; the owner’s own edits are never rewritten. Three buttons, no Save: Send email (Resend), Send text (Twilio, only when the record has a phone), Copy link. The draft reports its stages (payment-draft-stages/v1, LUCI-233, Completed 2026-09-09): reading → linking → composing → ready, streamed as data-only server-sent events when the caller asks for them; a reused link omits linking; never a timer, never a percentage. Founder: “Narration during loader is MUCH more helpful.” The draft’s honest face was proved and fixed on 2026-09-07 (Lucia couldn’t write the payment ask, LUCI-220, engine dev e2dc3d8): the composer had been refusing before any provider was asked because of a string-versus-number booking id at the hand-off. The per-task no-fallback env line for this task (LUCIA_FALLBACK_MODEL_PAYMENT_REQUEST_DRAFT=none) is not evidenced set on api-dev and remains an open founder item on that record; the source default already yields no fallback for the task at e2166b8.

The truth closes the step

A payment item on the arrival readiness feed is done only when the applied truth for the stay reads confirmed_paid, owner-recorded rows included; it re-opens when the truth leaves confirmed_paid. “Nothing else closes it — not a send, not a note, not a tap.” (Payment step is the payment record, LUCI-219, shape accepted 2026-09-07; engine dev 5c3ca1b and 63b5546, admin dev 814d90f.)
The payment record is the step: the arrival flow’s “payment check” opens the record with its doors, wearing the arrival frame (“Back to Quinn’s arrival”), and Lucia stands beside it (LUCI-211). The founder’s ruling that set this (2026-09-05): “the truth closes the step, not a Save button.”

Doctrine, unchanged

Not current

  • Live mode: possible by contract, not on. No production service, no live keys evidenced, no live webhook registered.
  • ALGO-24 round two (the Postgres ledger as sole financial truth in durable mode): the production gate, not started.
  • Engine migrations ride the deploy (LUCI-146): Planned; the September Stripe migrations were applied by hand before their code was pushed.
  • Founder proofs still open on the record: the rebuilt payment record (LUCI-215 phase 02, admin dev 81ab08f), the self-closing step (LUCI-219), the history rail’s icons (LUCI-245).
  • The admin surface’s own words and layout are documented separately (wave 2).

See also