Keyboard shortcuts

Press ← or → to navigate between chapters

Press S or / to search in the book

Press ? to show this help

Press Esc to hide this help

Credit-Card Entry Sheet — Parity Case Spec

Problem Statement

How might we enumerate every behavioral case of the card-entry bottom sheet (open → fill → tokenize → confirm/close) as a falsifiable parity contract, so the migration is verified case-by-case instead of happy-path-plus-luck?

Origin: a 4-agent migration audit found the card-entry flow “looks complete,” but a manual read of the Confirm path surfaced a real divergence (lost toast.error on tokenization failure) that no happy-path check would catch. A case spec is the antidote.

A map-flow-style doc at apps/docs/src/content/docs/flows/payment-card-entry-sheet.md built on a state-machine spine (cases = transitions), with factored axis tables (provider, lifecycle, outcome, save-vs-temporary) instead of a Cartesian blow-up, and a provider × outcome reachability matrix as the exhaustiveness proof. The full payment leg is covered by linking the existing journey/checkout claim IDs (journey-package-booking JPB-002..005, checkout-page-package-confirm) downstream of “token produced” — not re-documenting them. Each claim row carries source sourceRef, target sourceRef, and a parity verdict (✅ match / ⚠️ divergence / 🔵 intended / 🟡 latent-in-both).

Built GB PrimePay first as a tracer bullet — it is the default provider AND the only one that supports save-to-member, so it exercises both the temporary and persisted paths. Once the structure is validated on GB PrimePay, fan out to Omise, Stripe, Xendit.

Key Assumptions to Validate

  • Source = target spec, except flagged divergences. RESOLVED for the pivotal case: source onReservationError calls toast.error(message) on web (checkOutEvents.ts:1007); monorepo stubbed it to a no-op → confirmed regression, not an intended redesign.
  • Unconditional sheet-close on failure is parity, not a bug. RESOLVED: source closes the sheet + resets the model unconditionally too (BookingPayment.ts:539-541). The earlier “regression” read (from an agent summary) was wrong.
  • Axis factoring stays exhaustive — prove via a provider × outcome matrix with no uncovered cell.
  • The spec will be consumed by a verification pass (e2e or manual QA) — else it rots. (Open Q.)

MVP Scope

In: the state-machine spine; ALL four providers listed in the reachability matrix; the lifecycle table (open / close / reopen / reset); the outcome + error cases (incl. the lost-toast gap) with GIVEN/WHEN/THEN for the high-risk ones; GB PrimePay traced fully end-to-end (temporary + save) as the tracer that proves the factoring before fan-out.

Out (this pass): re-documenting 3DS / create-booking internals (link them); the saved-card edit/delete detail page (CreditCardDetailPage — separate sheet); Omise/Stripe/Xendit deep rows (matrix-stubbed as TODO-next-pass).

Not Doing (and Why)

  • Full Cartesian matrix — ~400 rows, mostly N/A; the reachability matrix proves coverage without listing dead cells.
  • Per-provider sub-docs — duplicates shared lifecycle/error logic 4×.
  • Deep downstream payload/3DS docs — already owned by the journey docs; link to avoid drift.
  • Fixing the bugs inside this task — spec first; fixes land in a separate worktree so the contract stays the reference.

Open Questions

  • Is the no-op onReservationError an accepted web-vs-hybrid simplification, or unfinished migration? (Now leaning “regression” — source shows a web toast; @hh-pegasus/shared-lib/toast exists in the monorepo.)
  • Should this be a standalone kind: flow doc, or a step linked from journey-package-booking? (Built standalone for now.)
  • Does a Cypress/e2e pass exist for the sheet to consume these scenarios, or is verification manual for now?

Status

  • ✅ One-pager saved (this file).
  • ✅ Flow doc: all 4 providers covered at apps/docs/src/content/docs/flows/payment-card-entry-sheet.md (quote-verified vs both repos). GB PrimePay (CCS-0xx), Omise (CCS-O-xx), Stripe (CCS-S-xx), Xendit (CCS-X-xx).
  • 📌 Fan-out finding: the lost-toast regression is one root cause across all 4 providers (the onReservationError no-op). Single fix closes all. Stripe is the exception on close (stays open on failure). Xendit deferred-token failure is the highest-risk case.
  • ⬜ Fix: restore web toast.error in onReservationError.
  • ⬜ Verify: Xendit deferred-token-failure feedback at create-booking.