# Hardening Phase 2 — Money-path mock integrity (no fake success on real data) > Sever the dangling cross-imports the phase-4 de-mock left behind — the refunds and BNPL mocks still > read retired in-memory stores keyed by REAL server ids — split the seams whose real halves are > already live (verification nurse flow, nurse earnings), and stop discarding the delivered > `bookingId`. After this phase, nothing in the money path can show a fake success against real data. > **Track:** frontend · **Depends on:** Phase 0 · **Unlocks:** Phase 5 > **Before you start, read [_shared/agent-operating-rules.md](../../phases/_shared/agent-operating-rules.md).** ## 1. Context — where this sits Fixes **H-06 … H-10** from [issues.md](issues.md). Refinement-phase-4 flipped 14 domains to real but left 7 mocked; two of the mocked ones (`refunds`, `bnpl`) still hard-import the **mock modules** of now-real sibling domains (`bookings`, `bookingRequests`), whose fixture stores no longer correspond to anything — so a real customer's cancel 404s and the BNPL wizard either 404s or fabricates a client-side "booking" while the real request expires unpaid. Meanwhile two seams hold real, shipped backend halves hostage to a single flag (`verification` nurse flow — which silently breaks nurse discoverability because the real search gate needs the real `is_verified`; `payouts` nurse reads — REQ-025 is live). **What already exists (do not rebuild):** the per-domain seam pattern (`apis/index.ts` selects mock/real), all the real `clientApi.ts` implementations named below, the b6 verification endpoints, the REQ-025 nurse payout endpoints (`NursePayoutsController.cs:33-48`), and the REQ-017 `bookingId` on `BookingRequestDto`. ## 2. Required reading (do this first) - [issues.md](issues.md) H-06/H-07/H-08/H-09/H-10 — full evidence; don't re-audit. - `client/CLAUDE.md` → "The services/{domain} reference pattern" + the de-mock status block. - The files cited per finding (refunds/bnpl/bookings/bookingRequests mockApis + constants, checkout pages, `PublishGate.tsx`, `MyServicesList.tsx`, payment `clientApi.ts`/`invalidations.ts`, payouts/verification services). - `dev/shared-working-context/reports/mocks-registry.md` — you will update the affected rows. ## 3. Scope — build this 1. **H-06 — refunds mock must see real bookings.** While `USE_REFUNDS_MOCK=true` (its REQs land in Phase 4), rewire `services/refunds/apis/mockApi.ts` to resolve the booking through the **selected** `bookingsApi` (the seam, real today) instead of importing `mockGetBookingForRefund` from the bookings mock module. The mock computes the policy preview locally off the real booking's status/sessions/amounts and simulates the cancel/refund state machine on top. A real booking id must produce a coherent preview + cancel flow (mock-side state), never a 404. 2. **H-07 — BNPL must not fake success.** Two parts: - Derive the checkout BNPL CTA visibility instead of the bare `BNPL_ENABLED=true` (`services/payment/constants.ts:23`, used at `checkout/page.tsx:214`): hide the branch whenever `USE_BNPL_MOCK` is true while `bookingRequests`/`payment` are real (mixed state = the dangerous combination). An honest absent button beats a fabricated booking. - For the dev/demo path that remains reachable (both mocked, e.g. Testing), rewire `services/bnpl/apis/mockApi.ts:5-8` to go through the **selected** `bookingRequestsApi`/ `bookingsApi` seams, never the raw mock modules. 3. **H-08 — split the verification seam; make the nurse trust flow real.** - Split `VerificationApi` selection per half: nurse-facing methods (status, start, identity, Shahkar, bank, document upload, credentials, trust badge) go **real** now — the clientApi is already 1:1 per the mocks registry; admin-facing methods (queue, case, decideStep, signed doc URL) stay mocked until REQ-034 (Phase 4). Follow whatever per-method selection shape is cleanest under the existing seam pattern (two flags, or a composed api object) and record it in the registry. - Wire `PublishGate.tsx` to the real status (its CTA currently calls nothing — `:59-68`), and gate the variant-activation affordance in `MyServicesList.tsx` on real verification status with an honest explainer, so a nurse can no longer "publish" into invisibility. Remove/dev-gate the `__mockApproveAll` simulator button accordingly. 4. **H-09 — split the payouts seam.** Nurse reads (`earnings_balance`, `earnings`, `{id}` detail, history) go real (`payouts/apis/clientApi.ts:163-187` already implements them); admin batch methods stay mocked until REQ-036. Same split mechanics as verification. 5. **H-10 — stop nulling `bookingId`.** `services/payment/apis/clientApi.ts:55-75`: read `bookingId` off the wire (drop the `Omit`/`bookingId: null` and the stale REQ-017-pending comments in `clientApi.ts` and `types.ts:98-110`); confirm `invalidations.ts` now receives it and the confirmation page renders the booking + invoice deep links. ## 4. Mocks & seams in this phase Touches the `refunds`, `bnpl`, `verification`, `payouts` seams (splits/rewires; flags flipped only for the halves whose backend is live). Update each row in `dev/shared-working-context/reports/mocks-registry.md` — including correcting the stale "reads the shared f7 store" descriptions. ## 5. Critical rules you must not get wrong - **A mock may only reach sibling data through the selected seam** (`services/{domain}/apis/index.ts`), never by importing a sibling's `mockApi.ts` — that's the root cause you're eradicating. Grep for remaining cross-mock imports before finishing. - Money is served IRR digit-strings, BigInt-safe — the refunds mock's local preview must reuse the existing money utils and reconcile (refund + fee = captured), never float math. - Verified-only search, two-stage disclosure, and "client never computes what the server owns" invariants all still hold; the verification split must not let the client write `is_verified`. - A 409 on the money path is benign convergence, never a toast (existing rule). - Keep i18n complete for any new copy (both message files); `npm run check` owns the gate. ## 6. Definition of Done - Real journey (seeded world, real server): create booking request → accept → pay → **cancel** → policy preview renders with reconciling numbers (no 404). - BNPL CTA absent on real checkout while the domain is mocked; the D1-D5 wizard is unreachable with a real request id (and works fully in the all-mock dev mode). - Fresh nurse: real verification wizard drives the real b6 endpoints; variant activation is gated until the real status approves; after approval + activation the nurse appears in real search. - Nurse earnings screen shows real amounts from the live endpoints. - Payment confirmation shows working "view booking" + "download invoice" deep links after a real capture. - `npm run check` + `npm run test:ci` green; no `services/*/apis/mockApi` imports across domain boundaries (grep-proof in the report). ## 7. How to test (human) 1. Full customer journey per §6 against the RUNBOOK setup; screenshot the cancel preview. 2. `grep -r "apis/mockApi" client/src/services --include=*.ts | grep -v "own domain"` → empty. 3. Nurse persona 09120000003 (unverified): services page shows the gated state; run the real verification flow; confirm search visibility flips after approval. ## 8. Hand off & document - Tick H-06…H-10 in [issues.md](issues.md) with commit hashes. - Update `client/CLAUDE.md` de-mock status block + `mocks-registry.md` rows. - Write `dev/shared-working-context/reports/hardening-phase-2-report.md`; file new REQs if a split exposed a missing server read (append to `for-backend.md`, Phase 4 picks them up).