Repository navigation
PAY-003A14 — Reject unusable embedded Dispute-created evidence #592
Description
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
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.
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.
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
createdform 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
daliu commentedon Aug 2, 2026
CLAIMED by /root at 2026-08-02T02:18Z on
codex/issue-592-dispute-created, exact base/main38600a13aeaf57fa1c4d5571efa72af09ea983a1, tree8a000d30283e1b6e876b703dbf25a27182cd11bf.Exact ownership:
functions/stripeWebhook.js: one Dispute-only embedded-created structural admission check and fixedinvalid_dispute_createdreason.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.
daliu commentedon Aug 2, 2026
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:
50d32f42f73469de6d5a2157568260e1efa124c93db26153dd865f9b0aa047fcFocused command (Node 20):
npm --prefix functions run test:run -- --runInBand --testNamePattern='PAY-003A14 Dispute-created admission' --silentExpected RED result:
createdevidence currently reachesdispute_needs_response,dispute_under_review, ordispute_won.needs_review:invalid_dispute_created.This is the intended failing proof. Runtime/shared-fixture/documentation implementation remains unstarted at this marker.
daliu commentedon Aug 2, 2026
CANDIDATE marker on exact base
38600a13aeaf57fa1c4d5571efa72af09ea983a1Candidate diff SHA-256:
3baa80a3f1b3e4afb89ec4207e30ba3e2f3f8070b96406b02202d17a03a3e4adOutcome: supported Dispute lifecycle Events now require primitive safe-integer embedded
Dispute.createdevidence in the inclusive Firestore timestamp range before any target, fallback, binding, business, money, or predecessor work. Invalid evidence records fixed target-freeneeds_review:invalid_dispute_createdwith 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:
runmprc.comverified for this candidate: no.Local verification under Node 20 / Java 21:
git diff --check: passed.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.jsfunctions/stripeWebhook.test.jsSTRIPE_COMMERCE_DESIGN.mdResidual: 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.
fix(stripe): validate dispute created evidence (#592) (#593)
daliu commentedon Aug 2, 2026
COMPLETE / CLOSED / CLAIM RELEASED
Release SHA:
102209dd99b331797f139dde7e209de75ea73a63Merged PR: #593
Reviewed candidate head:
3fa9cbcde06c2314b35716bbb47e312dddb0369dExact tree:
3917905e176632739b3e28e5addbee75abbbe2aaExact base-to-release patch SHA-256:
3baa80a3f1b3e4afb89ec4207e30ba3e2f3f8070b96406b02202d17a03a3e4adOutcome: supported Dispute lifecycle Events now reject unusable embedded
Dispute.createdevidence before target, fallback, binding, business, money, or predecessor work. The fixed result is target-freeneeds_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:
50d32f42f73469de6d5a2157568260e1efa124c93db26153dd865f9b0aa047fc; 3 intended lifecycle failures.6a6eae04d87096000879f96d: ready, exact candidate, HTTP 200, noindex, and never published.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:
6a6eaec63bf01e0008c85ec4is failed and its deploying step was skipped.runmprc.comverified: HTTP 200 on 2026-08-01 America/Los_Angeles, but Netlify still reports published source9ad6837756cdd409d296009fde5082eeeae5c059; this release is not live there.[]; no Firebase release was run.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.