Skip to content

PAY-003A14 — Reject unusable embedded Dispute-created evidence #592

Closed

Description

@daliu

Outcome

Reject a newly delivered supported Dispute Event when its embedded Stripe Dispute does not carry a usable created second.

Invariant

After exact processed-Event replay and the existing outer Event realm, embedded Dispute realm, Event/status lifecycle, claimed metadata-schema, and outer Event-time checks, every supported Dispute lifecycle requires:

Dispute.created is a primitive safe integer from Unix epoch second 0 through Firestore maximum second 253402300799, inclusive.

Missing, null, boolean, string, object, array, fractional, non-finite, negative, unsafe, or above-range evidence is contradictory and must produce fixed durable needs_review:invalid_dispute_created before any reference, fallback, target, ownership, provider-binding, money, or business-state work.

The ledger must retain the valid outer stripeCreatedAt, keep target fields null, and use the existing fixed redacted log. The rejected raw value must not be coerced, converted to a timestamp, stored, returned, or logged.

Allowed transitions and failure cases

  • Exact processed-Event replay stays first and read-only.
  • Outer Event realm, embedded Dispute realm, Event/status lifecycle, claimed metadata schema, and outer Event-time failures keep precedence.
  • Newly delivered invalid embedded Dispute time changes from target-capable behavior to target-free durable review.
  • Structurally valid Dispute time retains existing created, updated, and closed lifecycle outcomes.
  • A contradictory claimed missing target becomes durable review; a valid claimed missing target remains retryable.
  • Dispute/Event chronology is deliberately excluded: a structurally valid Dispute time later than the outer Event time remains compatible for a separately scoped child.
  • Checkout Session admission, refund Charge admission/chronology, and unsupported Events remain unchanged.
  • Provider delivery order and the current server clock are not part of this structural check.

Exact implementation scope

  1. functions/stripeWebhook.js
    • One Dispute-only call to the existing non-coercing safe-integer/Firestore-range predicate after outer Event-time admission and before target work.
    • One fixed reason: invalid_dispute_created.
  2. functions/stripeWebhook.test.js
    • One valid default embedded Dispute-created value in the synthetic Event fixture boundary.
    • One separately named PAY-003A14 adversarial matrix/helpers.
    • Reconcile only the stale PAY-003A9 and PAY-003A12 negative-created Dispute compatibility controls.
    • Preserve PAY-003A10's structurally valid later-Dispute chronology exclusion.
  3. STRIPE_COMMERCE_DESIGN.md
    • One named PAY-003A14 SOURCE ONLY / NOT LIVE section immediately after A13.
    • Only Dispute-created-specific historical wording needed to mark prior exclusions as superseded by A14.

Everything else is excluded.

Trustworthy RED

Before runtime, shared-fixture, compatibility-fixture, or documentation changes, add only a named PAY-003A14 helper and lifecycle matrix using otherwise valid signed synthetic Dispute Events with missing embedded created. Current source must be shown reaching its existing target/business Dispute outcomes instead of fixed target-free invalid_dispute_created review.

Use synthetic fixtures only. No provider, credential, payment, customer/member record, production service, or live mutation.

Acceptance

  • Created, updated, and closed Dispute Events reject every unusable embedded created form before target work.
  • Registration and order claim paths are covered where domain behavior could differ.
  • Fixed result/log, valid outer ledger time, null targets, exact ledger-only reads, no Timestamp.now, no rejected-value disclosure, coercion, storage, or timestamp conversion.
  • Contradiction wins before metadata/client-reference/legacy fallback, ambiguous target, malformed reference, binding conflict, currency, amount, and predecessor work.
  • Claimed missing-target contradiction is durable; a valid missing target remains retryable.
  • Earlier admission precedence is unchanged through invalid outer Event time.
  • Exact rejected replay is read-only and logs once; richer historical ledgers remain authoritative.
  • Unix epoch and Firestore-maximum embedded Dispute boundaries are valid across all three lifecycles.
  • Structurally valid later Dispute time remains compatible; chronology is not introduced in this child.
  • PAY-003A6/A7, Checkout Session admission/chronology, refund Charge admission/chronology, and unsupported Events remain compatible.
  • Focused tests, complete webhook/Functions tests, frontend/safety/SPA/Rules/commerce emulator gates, lint, build, diff check, and non-forced audits pass.

Migration and compatibility

No schema, Rule, index, package, workflow, API, provider configuration, migration, backfill, or history-reprocessing change. Already-processed ledgers remain authoritative on replay. Existing business records, provider bindings, payment fields, and historical rows are not inspected or repaired.

Stripe documents Dispute and Event created as Unix-second object-creation timestamps, and the installed Stripe 14.25.0 types require both. This child admits only the embedded value's structure and storage range. It does not claim canonical provider endpoint/version truth, exact dispute timing, or chronology.

Dependencies and exclusions

Depends on completed PAY-003A6 Dispute lifecycle admission, PAY-003A7 outer Event-time admission, and the existing processed-event ledger. Excludes Dispute/Event chronology, current-clock freshness/skew, endpoint/API-version policy, provider retrieval/history repair, policy/state changes, PAY-003B/C, reconciliation, alerts, protected release, provider/data/payment/dispute actions, and live verification.

Officer and deployment truth

Officer impact: None — server-only pre-target evidence structure; no officer screen, task, field, permission, topology, approval path, incident step, or available recovery action changes.

Officer documentation: None — current officer procedures remain factual; engineering truth belongs in STRIPE_COMMERCE_DESIGN.md.

Deployment evidence: Source, tests, merge, website publication, runmprc.com, Firebase deployment/readback, Stripe/provider configuration/action, production data, checkout/payment/refund/dispute activity, and live behavior must be reported separately. Source/tests alone prove none of the later states.

Claim rule

Claim only this atomic child after confirming exact main, completed #590 release, and disjoint ownership. Stop on any path/hunk overlap, provider/API-version dependency, need for production data or secrets, or change outside exact scope.

Activity

  1. self-assigned this
    on Aug 2, 2026
  2. added
    priority:P0Launch blocker or urgent security risk
    type:securitySecurity or privacy boundary
    area:firebaseFirebase services and data
    size:SSmall focused issue
    status:in-progressClaimed and actively being implemented
    area:stripeStripe payments and financial lifecycle
    type:testingTest infrastructure and quality gates
    on Aug 2, 2026
  3. daliu commented on Aug 2, 2026

    @daliu
    ContributorAuthor

    CLAIMED by /root at 2026-08-02T02:18Z on codex/issue-592-dispute-created, exact base/main 38600a13aeaf57fa1c4d5571efa72af09ea983a1, tree 8a000d30283e1b6e876b703dbf25a27182cd11bf.

    Exact ownership:

    • functions/stripeWebhook.js: one Dispute-only embedded-created structural admission check and fixed invalid_dispute_created reason.
    • functions/stripeWebhook.test.js: named A14 evidence plus only the claimed valid default and A9/A12 compatibility corrections; A10 chronology exclusion remains valid.
    • STRIPE_COMMERCE_DESIGN.md: one A14 SOURCE ONLY / NOT LIVE contract and only Dispute-created historical reconciliation.

    Coordination evidence: #590 has an explicit COMPLETE/CLOSED/CLAIM RELEASED marker at exact main above; no PAY-003A14 issue/PR existed; the only other open PR is draft #462 on disjoint Netlify rollback files. Remaining P0 work is tracked, externally blocked, dependency-blocked, larger, or already owned. No provider/API-version, schema, Rules, package, workflow, migration, history-repair, deployment, data, payment/dispute, or live action is in scope.

    I will post a trustworthy test-only RED before changing runtime, shared fixtures, compatibility controls, or documentation. Stop on overlap or any need for secrets, provider calls, real data, or production service. Claim remains held until exact-main verification and explicit release.

  4. daliu commented on Aug 2, 2026

    @daliu
    ContributorAuthor

    TEST-ONLY RED marker (exact base 38600a13aeaf57fa1c4d5571efa72af09ea983a1)

    Officer impact: none yet — this marker changes tests only and proves the missing Dispute-created admission boundary before implementation.
    Officer documentation: none yet — the candidate will update STRIPE_COMMERCE_DESIGN.md; no officer procedure changes because this is an internal webhook admission correction.
    Deployment evidence: source test only; no candidate source change, merge, website publication, runmprc.com verification, Firebase deployment, Stripe configuration, outside-provider change, production-data work, checkout/payment test, or live-production verification has occurred.

    Test-only diff SHA-256:
    50d32f42f73469de6d5a2157568260e1efa124c93db26153dd865f9b0aa047fc

    Focused command (Node 20):
    npm --prefix functions run test:run -- --runInBand --testNamePattern='PAY-003A14 Dispute-created admission' --silent

    Expected RED result:

    • 3 tests failed (created, updated, and closed lifecycle coverage).
    • 7,348 unrelated tests skipped.
    • Missing embedded Dispute created evidence currently reaches dispute_needs_response, dispute_under_review, or dispute_won.
    • The current behavior mutates the business target and creates Dispute, Charge, and PaymentIntent bindings instead of recording target-free needs_review:invalid_dispute_created.

    This is the intended failing proof. Runtime/shared-fixture/documentation implementation remains unstarted at this marker.

  5. daliu commented on Aug 2, 2026

    @daliu
    ContributorAuthor

    CANDIDATE marker on exact base 38600a13aeaf57fa1c4d5571efa72af09ea983a1

    Candidate diff SHA-256:
    3baa80a3f1b3e4afb89ec4207e30ba3e2f3f8070b96406b02202d17a03a3e4ad

    Outcome: supported Dispute lifecycle Events now require primitive safe-integer embedded Dispute.created evidence in the inclusive Firestore timestamp range before any target, fallback, binding, business, money, or predecessor work. Invalid evidence records fixed target-free needs_review:invalid_dispute_created with the valid outer Event ledger time. Valid later Dispute time remains compatible; A14 adds no chronology rule.

    Officer impact: none — no officer screen, task, field, permission, approval, topology, incident step, or recovery action changes.
    Officer documentation: None — this server-only pre-target evidence structure does not change an officer procedure.
    Deployment evidence:

    • Source changed: yes, candidate only.
    • Synthetic tests passed: yes.
    • Code merged: no.
    • Website published: no.
    • runmprc.com verified for this candidate: no.
    • Firebase deployed/read back: no.
    • Stripe or another outside provider configured or acted on: no.
    • Production data changed: no.
    • Checkout/payment/refund/dispute activity performed: no.
    • Live production behavior verified: no.

    Local verification under Node 20 / Java 21:

    • PAY-003A14 focused: 138 passed.
    • Full webhook: 960 passed.
    • Full Functions: 7,422 passed, 64 skipped.
    • Functions lint: passed.
    • Frontend: 951 passed.
    • Workflow/release/artifact safety: 86 passed.
    • SPA navigation: 11 passed.
    • Firestore Rules emulator, demo project: 418 passed.
    • Commerce command journal emulator, demo project: 63 passed.
    • Frontend lint baseline: passed.
    • Direct diagnostic production build: compiled.
    • Workflow YAML parse and git diff --check: passed.
    • Dependency audit baseline unchanged: root 59 total / 4 production; Functions 8; no critical findings and no dependency change.

    Self-review: no authorization, App Check, PII/logging, idempotency, replay, target isolation, impossible transition, migration, production fallback, or scope finding. Three independent read-only reviews returned GO for runtime, adversarial tests, and documentation/provider/officer boundaries.

    Files:

    • functions/stripeWebhook.js
    • functions/stripeWebhook.test.js
    • STRIPE_COMMERCE_DESIGN.md

    Residual: Dispute/Event chronology, clock freshness/skew, endpoint/API-version truth, provider retrieval/history repair, reconciliation, PAY-003B/C, protected release, and live verification remain outside this child.

  6. removed their assignment
    on Aug 2, 2026
  7. daliu commented on Aug 2, 2026

    @daliu
    ContributorAuthor

    COMPLETE / CLOSED / CLAIM RELEASED

    Release SHA: 102209dd99b331797f139dde7e209de75ea73a63
    Merged PR: #593
    Reviewed candidate head: 3fa9cbcde06c2314b35716bbb47e312dddb0369d
    Exact tree: 3917905e176632739b3e28e5addbee75abbbe2aa
    Exact base-to-release patch SHA-256: 3baa80a3f1b3e4afb89ec4207e30ba3e2f3f8070b96406b02202d17a03a3e4ad

    Outcome: supported Dispute lifecycle Events now reject unusable embedded Dispute.created evidence before target, fallback, binding, business, money, or predecessor work. The fixed result is target-free needs_review:invalid_dispute_created, using only the valid outer Event time for the ledger. Valid later Dispute evidence remains accepted; Dispute/Event chronology is still residual work.

    Verification:

    • RED: exact test-only diff 50d32f42f73469de6d5a2157568260e1efa124c93db26153dd865f9b0aa047fc; 3 intended lifecycle failures.
    • Local candidate: A14 138; webhook 960; Functions 7,422 + 64 skipped; frontend 951; workflow/artifact safety 86; SPA 11; Rules 418; commerce emulator 63; lint/build/YAML/diff checks passed.
    • Dependency audit baseline unchanged: root 59 total / 4 production; Functions 8; no critical findings and no dependency change.
    • Three independent candidate reviews plus self-review: GO, no remaining finding.
    • Hosted PR CI 30729260291: all five jobs passed.
    • Non-production preview 6a6eae04d87096000879f96d: ready, exact candidate, HTTP 200, noindex, and never published.
    • Post-main CI 30729355134: all five jobs passed.

    Officer impact: none.
    Officer documentation: None — this server-only pre-target evidence structure changes no officer screen, task, field, permission, approval, topology, incident step, or recovery action. An independent backup-officer review found no specialist-only step introduced.

    Deployment evidence:

    • Source changed: yes.
    • Synthetic tests passed: yes.
    • Code merged: yes, exact release SHA above.
    • Website published for this release: no. Netlify production attempt 6a6eaec63bf01e0008c85ec4 is failed and its deploying step was skipped.
    • runmprc.com verified: HTTP 200 on 2026-08-01 America/Los_Angeles, but Netlify still reports published source 9ad6837756cdd409d296009fde5082eeeae5c059; this release is not live there.
    • Firebase deployed/read back: no. Exact-release GitHub deployments are []; no Firebase release was run.
    • Stripe or another outside provider configured or acted on: no.
    • Production data changed: no.
    • Checkout/payment/refund/dispute activity performed: no.
    • Live production behavior verified: no.

    The ordinary merge was refused only by the self-approval rule after all required checks passed; the administrator squash merge then succeeded. The CLI returned nonzero only because another worktree owns local main; remote PR/main state was verified directly.

    Residual work remains with #106: Dispute/Event chronology, freshness/skew, endpoint/API-version truth, provider retrieval/history repair, reconciliation, PAY-003B/C, protected release, and live verification.

    Issue is closed, assignee/status claim removed, remote branch deleted, and the #592 claim is released.

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

Metadata

Metadata

Assignees

No one assigned

    Labels

    area:firebaseFirebase services and dataarea:stripeStripe payments and financial lifecyclepriority:P0Launch blocker or urgent security risksize:SSmall focused issuetype:reliabilityReliability and recoverytype:securitySecurity or privacy boundarytype:testingTest infrastructure and quality gates

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions