Skip to content

PAY-003A — Harden Stripe webhook ingress and monotonic event reduction #101

Closed

Description

@daliu

Problem

The original webhook verified a signature but lacked durable Event deduplication, money and binding validation, delayed-payment handling, monotonic refund/dispute reduction, safe terminal-state behavior, and an operable review ledger.

Outcome

Land a backward-compatible safety slice that makes signed Stripe delivery duplicate-safe, validates local ownership and money/bindings, handles async payment outcomes, and reduces refunds/disputes without state regression.

Scope

  • functions/stripeWebhook.js
  • Non-promotion lifecycle/binding tests in functions/stripeWebhook.test.js
  • Active-registration compatibility hunk in functions/stripeHelpers.js
  • Webhook binds only STRIPE_WEBHOOK_SECRET
  • Excludes persistence-first checkout, command idempotency, capacity/inventory services, reconciliation worker, and provider configuration

Acceptance criteria

  • Exact Event replay has no second business effect.
  • Missing claimed target retries; malformed/conflicting targets never mutate a record.
  • Explicit livemode, Checkout mode, Session/PaymentIntent/Charge, amount, and currency checks fail closed.
  • Unpaid completion stays processing; async success/failure and expiry are represented.
  • Refunds are monotonic, refund-before-completion preserves evidence, and Charge/currency/known-total mismatches quarantine.
  • Multiple disputes are stored independently; older/equal-second events cannot regress lifecycle state; unmatched PI-null disputes require review.
  • Cancelled/fulfilled/refunded/transferred/comp states cannot be silently resurrected.
  • Functions lint and signed positive/negative/reordered tests pass.

Dependencies

This safety slice is intentionally compatible with the legacy model. Full PAY-003 remains dependent on CONFIG-001, PAY-001, PAY-002, RACE-001, MERCH-001, PAY-005, and TEST-001.

Coordination

A verified local working-tree implementation predates publication of this issue. This issue records the exact ownership boundary before any further editing or PR work. The existing diff must be isolated onto the claimed branch before review; unrelated changes and the pre-existing public/sitemap.xml modification are excluded.

Do not edit the listed paths or duplicate this outcome while the issue is assigned and has a valid timestamped CLAIMED marker.

Activity

  1. added
    priority:P0Launch blocker or urgent security risk
    type:securitySecurity or privacy boundary
    area:firebaseFirebase services and data
    size:LLarge cross-boundary issue
    status:readyDependencies complete and ready to claim
    area:stripeStripe payments and financial lifecycle
    on Jul 12, 2026
  2. self-assigned this
    on Jul 12, 2026
  3. daliu commented on Jul 12, 2026

    @daliu
    ContributorAuthor

    CLAIMED by Codex agent /root at 2026-07-12T20:50:10Z; branch codex/issue-101-stripe-webhook-ingress.

    Existing shared working-tree implementation predates issue publication. I will isolate this outcome onto the named branch serially before opening a PR; no unrelated dirty path is included.

  4. added
    status:in-progressClaimed and actively being implemented
    and removed
    status:readyDependencies complete and ready to claim
    on Jul 12, 2026
  5. daliu commented on Jul 12, 2026

    @daliu
    ContributorAuthor

    Parent tracker: #106. This claim covers PAY-003A only; canonical schema/state integration, reservation/outbox coupling, reprocessable quarantine, reconciliation, and provider rehearsal remain unclaimed tracker children.

  6. added
    status:readyDependencies complete and ready to claim
    and removed
    status:in-progressClaimed and actively being implemented
    on Jul 12, 2026
  7. daliu commented on Jul 12, 2026

    @daliu
    ContributorAuthor

    CLAIM RETAINED / EXTRACTION QUEUED at 2026-07-12T21:53:37.334Z. Assignment and the original timestamped CLAIMED marker remain authoritative. Dependencies are clear, but no issue-specific extraction has begun. Merge order is #101 before #102. #101 owns the webhook foundation/lifecycle rewrite, inbox, target/binding logic, nonNegativeInteger, base amount/currency/subtotal/total validation, address capture, refunds/disputes, and all non-adjustment tests. #102 owns only the documented adjustment-policy fragments and tests, then rebases onto merged #101. Base extraction on refreshed main containing #98. Do not duplicate this outcome.

  8. daliu commented on Jul 13, 2026

    @daliu
    ContributorAuthor

    EXTRACTION STARTED by /root at 2026-07-13T10:09:05Z; branch codex/issue-101-stripe-webhook-ingress-v2; exact base 13ccc1b67dd57f69091e808b12e1287a1bc05b2f.

    The original local branch remains untouched at its old placeholder base. I am using a fresh isolated worktree and will transplant only #101-owned webhook lifecycle, inbox/binding/refund/dispute logic, non-adjustment tests, and the active-registration helper hunk.

    #102 remains queued and immutable: no Checkout-creator change, no discount/tax/shipping policy fragment, no total-details fixtures, and no adjustment test will be retained in #101. No provider call, real payment, production data, secret, sitemap, or unrelated dirty path is in scope.

  9. added
    status:in-progressClaimed and actively being implemented
    and removed
    status:readyDependencies complete and ready to claim
    on Jul 13, 2026
  10. daliu commented on Jul 13, 2026

    @daliu
    ContributorAuthor

    EXTRACTION FINISHED by /root at 2026-07-13T10:29:43Z; draft PR #140; exact rebased source head 14d387f.

    Owned diff is exactly three paths: functions/stripeWebhook.js, functions/stripeWebhook.test.js, and the active-registration compatibility line in functions/stripeHelpers.js. #102 checkout creators and discount/tax/shipping adjustment fragments remain excluded.

    Local Node 20 evidence: focused signed webhook tests 74/74; complete Functions unit tests 107 passed plus one emulator-only skip; Functions lint and diff check passed. No real Stripe/Firebase call, provider change, secret, member data, public asset, Rules file, package file, or sitemap is included. Hosted checks and two independent exact-head reviews are pending, so the PR remains draft. Source is not merged or deployed.

  11. added
    status:in-progressClaimed and actively being implemented
    and removed
    status:in-progressClaimed and actively being implemented
    on Jul 13, 2026
  12. daliu commented on Jul 13, 2026

    @daliu
    ContributorAuthor

    COMPLETED / SOURCE CLAIM RELEASED by /root at 2026-07-13T10:40:51Z.

    PR #140 merged as exact main commit 87bd121. Exact-head CI run 29243337795 and post-merge CI run 29243458623 both passed frontend, Functions, and Firestore Rules groups. The signed webhook suite is 81/81 locally under Node 20; the complete Functions unit suite is 114 passed plus one emulator-only skip. Two independent exact-head security/adversarial reviews approved with no findings.

    Deployment truth: this merge triggered CI only. No protected release ran, no Firebase Function was deployed, no Stripe setting or live/test payment was changed, and no website production artifact was published by this outcome. Firebase release is intentionally held until dependent #102 is merged so an unmodeled-promotion window is not deployed; protected release authority and staged/provider verification remain #105/#106 work.

    Officer impact: no current officer procedure changed. Commerce remains NOT AVAILABLE YET.
    Officer documentation: none for this internal source-only slice; current unavailable-state guides remain accurate.
    Deployment evidence: source merged and CI proven; website/Firebase/Stripe production behavior unproven.

    The three owned paths are released after refresh to 87bd121. #102 may now extract its separate creator and adjustment-policy scope.

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

Metadata

Metadata

Assignees

Labels

area:firebaseFirebase services and dataarea:stripeStripe payments and financial lifecyclepriority:P0Launch blocker or urgent security risksize:LLarge cross-boundary issuetype:reliabilityReliability and recoverytype:securitySecurity or privacy boundary

Type

No type

Projects

No projects

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions