Skip to content

fix(upi): M4.3.4 payment provider contract determination (Outcome B) & milestone M4 closure - #34

Open
Satelink-Protocol wants to merge 3 commits into
feature/m4-3-3-provider-verificationfrom
feature/m4-3-4-contract-decision
Open

Satelink-Protocol wants to merge 3 commits into
feature/m4-3-3-provider-verificationfrom
feature/m4-3-4-contract-decision

Conversation

@Satelink-Protocol

Copy link
Copy Markdown
Contributor

Summary

This PR resolves the remaining PhonePe provider-verification contract issue and formally closes Milestone M4 with a documented, independently reviewable architectural decision (Outcome B), an authoritative 22-vector regression test suite, a full M4 system audit, and a verified pass/fail exit criteria checklist.

1. Technical Contract Determination (PhonePe API v1)

• Merchant Identity & URL Path Verification:
• Outbound S2S status queries (GET /pg/v1/status/{merchantId}/{orderId}) authenticate the caller via TLS, X-VERIFY: SHA256(path + saltKey)###saltIndex, and X-MERCHANT-ID.
• However, the HTTP response body returned by PhonePe is plain unsigned JSON (no response HMAC or signature header).
• If a provider response omits data.merchantId, relying on the request URL path requires client/adapter-side identity synthesis. Under zero-trust rules, omitted fields remain null and fail closed (missing_verified_merchant_id), strictly preventing cross-merchant substitution.
• Domestic UPI Contract vs Missing Currency Field:
• PhonePe is statutory licensed under RBI/NPCI exclusively for domestic INR transactions (denominated in paise).
• However, PhonePe's official API schema (GET status and S2S webhook callbacks) never returns a currency field.
• Under our zero-trust verification standard (applySuccessfulUpiPayment), payment confirmation requires provider-attested currency === 'INR'. Faithful extraction yields currency: null, resulting in fail-closed dispute (missing_currency).
• Injecting hardcoded defaults (currency: 'INR') inside the adapter is strictly prohibited because it manufactures evidence not present in provider payloads.
• Cryptographic Signing Analysis:
• S2S Webhooks are cryptographically signed via X-VERIFY over the base64 payload, authenticating merchantId, amount, and merchantTransactionId. Currency is omitted.
• Status GET responses are unsigned by the provider (relying solely on TLS transport security).
• Forgery & Mismatch Resistance:
• Forged or invalid webhook signatures are rejected with HTTP 401 (WebhookSignatureError).
• Amount mismatches, currency mismatches, or merchant mismatches transition payments to disputed with 0 bookings and 0 Telegram invites.


2. Safe Integration Approach Decision: Outcome B (Adopted)

• Outcome A (Rejected): Manufacturing synthetic defaults violates non-negotiable safeguard #5 and reopens vulnerability surfaces closed in M4.3.3.
• Outcome B (ADOPTED):
• PhonePe cannot currently meet the required zero-trust verification standard due to the absence of machine-verifiable currency and unsigned status responses.
• PhonePe is formally classified as SANDBOX / MOCK ONLY.
• Production live-payment capability is marked BLOCKED (ENABLE_LIVE_PAYMENTS=false preserved everywhere).
• Milestone M4 formally closes with live payments disabled and zero financial exposure.
• Recommends migrating to a modern, zero-trust compatible provider (e.g., Razorpay or Cashfree) for M5 live checkout.
• Outcome C (Rejected): Indefinite delay is unnecessary given that booking integrity, capacity holds, audit logging, and refund controls are fully operational.


3. M4.3.4 Regression Test Suite (38/38 UPI Tests Passing)

Added comprehensive regression suite in test/upi-checkout.test.js verifying:

  1. Missing & Mismatched Merchant ID: Polling missing (missing_verified_merchant_id), polling mismatched (merchant_mismatch), webhook missing (WebhookSignatureError), webhook mismatched (WebhookSignatureError).
  2. Missing Currency & Domestic INR Invariant: Real native PhonePe payload without currency (missing_currency dispute), foreign currency injection (currency_mismatch dispute).
  3. Forged & Unauthenticated Responses: Forged signature (401), missing signature (401), corrupted payload (400), gateway 502 outage (graceful pending retention).
  4. Wrong Amount & Order ID: Underpayment (disputed), overpayment (disputed), unknown order ID (404 Payment not found).
  5. Replayed Webhooks & Duplicate Polling: Idempotent duplicate delivery (duplicate: true), zero duplicate bookings or invites.
  6. Client Return URL Spoofing: Injected query params ignored, database status remains pending, 0 bookings, 0 invites.
  7. Pending, Failed, Disputed & Refunded States: Lifecycle state transitions verified; refunding revokes Telegram invites and cancels booking.
  8. Strict Gating Verification: Across all 12 unverified/negative test cases, exactly 0 bookings and 0 invite links are created.

4. Final M4 System Audit Summary

• Booking Integrity & Concurrency: Double-booking prevented at intent creation (409), confirmation (refund_pending), and guest claim (409); SQLSTATE 23505 savepoint recovery; capacity holds held under unexpired intents.
• Seat Overselling Prevention: Partial index idx_payments_active_tier_holds serializes concurrent bookings; re-checked at confirmation.
• Refunds & Reconciliation: Automated refunds for succeeded and refund_pending; authorized manual finance reconciliation with anti-placeholder validation (operator_attested: true, bankVerified: false).
• Audit Ledger Immutability: Append-only payment_audits protected by PostgreSQL trigger (no UPDATE/DELETE).
• Tenant & Guest Isolation: Multi-tenant organiser isolation strictly enforced.
• Disabled Live-Payment Safeguards: ENABLE_LIVE_PAYMENTS=false enforced across all files and environments.


5. M4 Exit Criteria Pass/Fail Checklist

  • Booking Integrity: PASS
  • Payment Verification Architecture: PASS
  • Provider Contract Evidence: PASS (Sandbox & Architecture) / BLOCKED (Live PhonePe)
  • Refund and Reconciliation Controls: PASS
  • Security Tests: PASS (38/38 UPI tests, 471/471 unit/integration tests, 157/157 Playwright E2E tests, 140/140 lint clean)
  • Documentation: PASS (UPI_PROVIDER_READINESS.md, UPI_SECURITY_AUDIT.md, PROJECT_STATE.md)
  • Production Payment Activation Prerequisites: PASS (DOCUMENTED & GATED)

Milestone M4 Verdict: FORMALLY CLOSED (Live Payments Safely Disabled).


6. Governance

• Base branch: feature/m4-3-3-provider-verification
• Head branch: feature/m4-3-4-contract-decision
• ENABLE_LIVE_PAYMENTS=false strictly preserved.
• No real payments or refunds initiated.
• PR #33, #32, #31, #30, #17 not merged.
• Stopped for independent owner review.

@vercel

vercel Bot commented Nov 5, 2026 •

Copy link
Copy Markdown

The latest updates on your projects. Learn more about Vercel for GitHub.

Project Deployment Actions Updated
strangersmeetup Ready Ready Preview Nov 5, 2026 12:35pm UTC

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant