Skip to content

PAY-005A2: validate Stripe refund results - #205

Merged
daliu merged 1 commit into
mainfrom
codex/issue-204-refund-response-validation
Jul 14, 2026
Merged

daliu merged 1 commit into
mainfrom
codex/issue-204-refund-response-validation

Conversation

@daliu

@daliu daliu commented Jul 14, 2026 •

Copy link
Copy Markdown
Contributor

Closes #204

Outcome

Both current admin refund Functions now reject an invalid stored refund target before constructing Stripe. After one refund request, they record local success only from a plain, final succeeded Refund bound to the expected PaymentIntent, usd currency, and permitted amount.

A partial must return the exact requested cents. A full action still omits amount and records Stripe's validated remaining cents. Provider uncertainty and local-save uncertainty return the same fixed do-not-retry message without provider or storage detail.

The local-save boundary is explicit:

  • rejected or unclear Stripe result: no local success write is attempted;
  • Firestore error or lost acknowledgement after a valid Stripe result: local state is unknown, no success response is returned, and reconciliation is required.

Officer continuity

Officer impact: Refunds cannot be recorded as successful from malformed, mismatched, pending, action-required, failed, cancelled, or unknown provider results. An unclear outcome tells the officer not to retry and to escalate.

Officer documentation: docs/officers/EVENTS_SHOP_MEMBERS.md, OPERATIONS_RUNBOOK.md, SECURITY.md, GITHUB_ISSUES.md, and GITHUB_ISSUE_SLICES.md.

Deployment evidence: Source, tests, and commit are proven. Website publication, runmprc.com verification, Firebase Functions deployment, Stripe provider configuration/request, production data behavior, and live refund behavior are not performed or proven. The officer procedure remains NOT AVAILABLE YET.

Safety invariants

  • Stored PaymentIntent, original cents, and currency fail closed before Stripe construction.
  • PAY-005A1 partial-amount validation remains unchanged.
  • Stripe is called at most once.
  • Only a bounded plain Refund with object: refund, status: succeeded, matching primitive PaymentIntent/currency, and permitted positive safe-integer cents can reach the local write.
  • Only the validated refund ID and actual returned cents enter the response, status update, ID array, or audit.
  • Rejected Stripe results cause no local success write attempt.
  • A local write error never returns success, but its state is treated as unknown because a commit acknowledgement may have been lost.
  • No request body, provider object/detail, member/customer data, or secret is logged.

Verification

Exact reviewed head: fbc9494c60b22f25c3c30134580f4bd93a02a715
Exact base: 2c7332ca547ba98a57863a6f2f41849ffb386e9f
Diff SHA-256: f193a0b8b9e4731ff92d20f141e889e2abe345fbf3cea46107cd87397f46ca42

Red proof:

  • 46 dual-endpoint stored-target/provider-result cases exposed unsafe old behavior.
  • Two cases exposed raw pre-commit local-storage errors after provider success.
  • A commit-then-error case proves why lost acknowledgement leaves local state unknown.

Green local proof on Node 20:

  • npm --prefix functions run lint
  • Focused: 2 suites / 174 tests
  • Full Functions: 18 passed suites, 2 emulator-only skipped; 1,180 passed, 32 skipped
  • Frontend: 11 suites / 198 tests
  • SPA callback: 11/11
  • Firestore Rules: 4 suites / 348 tests
  • Artifact safety: 22/22
  • Workflow/release safety: 12/12
  • Diagnostic frontend build passed
  • git diff --check passed
  • 15 relative links across changed Markdown resolve
  • Three independent security, test, and officer-documentation reviews approved with no findings

Remaining risk

This is immediate containment, not the complete safe refund system. It does not add durable refund commands, Stripe idempotency keys, remaining-balance retrieval, concurrency fences, webhook-finalized totals, reconciliation, finance capabilities/MFA/recent-auth, approved policy, protected Firebase deployment, or provider/live proof. Never retry an ambiguous result blindly.

Stripe references:

Exact-head hosted evidence

  • CI run 29300450776 passed all five jobs at fbc9494c60b22f25c3c30134580f4bd93a02a715: frontend lint/build/Jest/SPA/workflow checks, Functions lint/tests, Firestore Rules, artifact scrubber, and commerce-journal emulator.
  • Netlify deploy preview 6a559ad0a9ece400087af1cf succeeded for PR review only.
  • The preview is not a production publication and cannot prove Firebase Functions or Stripe refund behavior.

@netlify

netlify Bot commented Jul 14, 2026 •

Copy link
Copy Markdown

✅ Deploy Preview for luminous-fox-7c393f ready!

Name Link
🔨 Latest commit fbc9494
🔍 Latest deploy log https://app.netlify.com/projects/luminous-fox-7c393f/deploys/6a559ad0a9ece400087af1cf
😎 Deploy Preview https://deploy-preview-205--luminous-fox-7c393f.netlify.app
📱 Preview on mobile
Toggle QR Code...

QR Code

Use your smartphone camera to open QR code link.

To edit notification comments on pull requests, go to your Netlify project configuration.

@daliu
daliu marked this pull request as ready for review July 14, 2026 02:13
@daliu
daliu merged commit 0dbac06 into main Jul 14, 2026
9 checks passed
@daliu
daliu deleted the codex/issue-204-refund-response-validation branch July 14, 2026 02:13
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.

PAY-005A2 — Validate Stripe refund results before recording success

1 participant