ADR 037 Reservation Booking Party Authority Binding
Context
Section titled “Context”The legacy customer web carries mutable numeric user and reservation identifiers through session state, hidden fields, and controller-specific comparisons. That proves legacy behavior but cannot identify the target reservation beneficiary, booker, or payer. A browser-supplied party list or revision would let stale UI state become booking authority.
ADR-035 provides one backend-owned customer account link. P04 also has an accepted draft revision, final-review projection revision, and contract-acceptance lineage. Before this decision, those facts were not frozen with the booking row.
Decision
Section titled “Decision”The browser submits no party or revision authority
Section titled “The browser submits no party or revision authority”The public reservation-start request rejects
reservationPartyAuthorityBinding, including a forged object or null.
Only the trusted internal workflow-start payload can carry the closed binding
after orchestration resolves it.
For the current direct-mother P04 path, the backend creates one party with
mother, booker, and payer roles. It binds:
- the exact Member Management account-link proof and profile revision;
- the accepted contract id;
- the accepted draft and final-review projection revisions; and
- expected reservation revision
1for the new booking.
This decision does not invent family-sponsored party rules. A sponsored booking must later provide its own accepted authority through the same consumer contract.
Reservation Booking owns the consumer contract
Section titled “Reservation Booking owns the consumer contract”application/reservation_operations/features/reservation_booking owns
ReservationBookingPartyAuthorityBinding. Member Management remains the owner
of account and family authority. The cross-context bridge belongs to
orchestration/reservation_operations/features/customer_reservation_creation.
domain/member_management/features/family_account← application/member_management/features/customer_authenticated_session \ orchestration bridge /application/reservation_operations/features/reservation_booking← adapters/reservation_operations/features/reservation_bookingThe bridge fails closed when the account proof is absent or its member differs from the accepted operational mother. Feature implementations do not import one another directly, and no global command/query folder is introduced.
Booking and authority snapshot persist atomically
Section titled “Booking and authority snapshot persist atomically”When the command has a party binding, the Supabase adapter calls
sanmopia_save_reservation_booking_result_with_party_authority. The wrapper
invokes the existing booking-result RPC and inserts
sanmopia_reservation_party_authority_snapshots in the same PostgreSQL
transaction. Other booking commands without this P04 binding continue to call
the existing RPC.
The wrapper rechecks workflow request mother/branch lineage, the booking’s
actual revision, and the member-profile mapping. A stale expected revision,
request drift, identity drift, or non-exact replay raises SQLSTATE 40001, so
the booking, payment, and snapshot roll back together.
The snapshot is private and append-only:
- forced RLS;
- no
anonorauthenticatedaccess; service_rolereceives onlySELECTandINSERT;- update and delete are rejected by an immutable trigger with
55000; and - exact replay returns the existing booking without another mutation.
Consequences
Section titled “Consequences”- P04 booking parties and expected new-booking revision now have one frozen backend source.
- The public browser contract stays actor-free.
- Accepted draft/review/account lineage travels through Restate’s trusted internal payload and is revalidated at the database write boundary.
- Existing non-P04 booking commands remain compatible with the previous RPC.
- This closes the reservation-party/revision gap. It does not close P04 legal acceptance, production-source completeness, finalized booking readiness, provider payment, or current browser evidence.
Implementation Evidence
Section titled “Implementation Evidence”Backend 35f67ff912d32c92e4772e60895bf1da45014437 implements the application
contract, orchestration bridge, trusted Restate payload, conditional Supabase
adapter path, append-only snapshot migration
20260718170000_customer_booking_party_authority_binding.sql, and public-input
rejection.
The repository Supabase CLI replayed the complete current migration chain in a disposable tmpfs PostgreSQL container and applied the new migration. Actual SQL acceptance proved:
- initial save and exact replay return the same booking id;
- replay drift raises
40001and leaves the booking amount unchanged; - expected revision
2raises40001and rolls back booking, payment, and authority snapshot; - update raises the immutable-trigger
55000; - persisted cardinality is booking
1, payment1, snapshot1; and anon/authenticatedcannot read or execute, whileservice_rolecan read/insert and execute but cannot update/delete.
Supabase DB lint completed with no errors in the new functions. The disposable database was removed and unused images were pruned after verification.
Focused reservation, HTTP, Restate, adapter, migration, and smoke regression
reports 76 passed. The complete backend suite reports 7028 passed. Tach
exact dependency/interface/external checks report zero diagnostics. Vulture at
confidence 100 reports zero candidates on the changed production paths. Ruff
and diff checks pass.
No new Chromium, screenshot, animated WebP, stage, production database, or online deployment evidence was created. Existing P04 visual packs remain historical relative to this backend revision.
Revision History
Section titled “Revision History”- 2026-07-18: accepted and implemented backend-owned reservation party and expected new-booking revision binding.