You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Newly delivered supported Checkout Events now reject an embedded Checkout Session that claims it was created after the Event carrying that Session, before any target or business work.
After exact processed-Event replay and the existing Checkout realm, lifecycle, metadata, outer Event-time, and Session-time structure checks:
Checkout Session.created <= Event.created
Equality is valid because both provider fields use whole seconds. A later Session second produces fixed durable needs_review:invalid_checkout_session_event_chronology with:
valid outer stripeCreatedAt;
null target fields;
fixed redacted logging;
no Session-time timestamp conversion, storage, response detail, or logging;
no reference/fallback query, provider binding, business read/mutation, money check, or transition.
Equal and earlier chronology preserve existing lifecycle outcomes. Valid claimed missing targets remain retryable. Exact replay remains read-only and authoritative.
Changes
functions/stripeWebhook.js: one Checkout-only strict chronology comparison and fixed reason after both time-shape checks.
functions/stripeWebhook.test.js: one named 62-test PAY-003A13 matrix/helpers and only three inherited chronology-valid fixture corrections in PAY-003A8, A10, and A11.
STRIPE_COMMERCE_DESIGN.md: one PAY-003A13 SOURCE ONLY / NOT LIVE contract and chronology-specific A12 historical reconciliation.
No schema, Rule, index, package, workflow, API, provider configuration, migration, backfill, history repair, or live change.
Trustworthy RED
On the exact base, the test-only four-lifecycle × two-domain matrix failed 8/8 because later Session time reached normal target/business processing and recorded payment_confirmed, payment_failed, or payment_expired instead of fixed target-free review.
Dependency audits, unchanged by this no-package patch: root full 59, root production 4, Functions 8; no forced upgrade
A discarded diagnostic inherited shell-default Node 22 and reproduced a known Error-own-surface mismatch in an unrelated projection suite. Under the required Node 20 runtime, that suite passed 25/25 and the complete Functions suite passed as listed.
Three independent exact-diff reviews returned GO: runtime/security, tests/compatibility, and design/backup-officer continuity.
Self-review
Authorization/App Check: no callable, authorization, or browser-write surface changed.
Input bounds/coercion: comparison occurs only after both values pass the existing primitive safe-integer and inclusive Firestore-range checks.
PII/secrets/logging: Session time is never stored, returned, converted, or logged; review logs remain fixed and redacted.
Idempotency/replay: the existing processed Event remains first, byte-preserving, and log-once.
State transitions: contradictory evidence stops before all target work; equal/earlier lifecycle outcomes remain unchanged.
Non-Checkout behavior: refund Charge chronology keeps its existing reason; all Dispute and unsupported Event behavior remains unchanged.
Production fallback: none added; no provider call or production service is used.
Exact reviewed head 8929be85a8276a02a2222c5b64e53d3723799ec4 squash-merged as exact main 38600a13aeaf57fa1c4d5571efa72af09ea983a1; tree 8a000d30283e1b6e876b703dbf25a27182cd11bf and patch SHA-256 172f0cbac9e1d461e3e34e41bf158dbbbed54152a9b4ed1470b3076eff8f0f80 remained identical. Exact-main CI 30728441536 passed all five jobs.
Officer impact: None — server-only pre-target evidence comparison.
Officer documentation: None — no officer-visible or operational procedure changed.
Deployment evidence: source/tests/merge only. No GitHub deployment, Firebase deployment/readback, Stripe/provider action, production data, checkout/payment/refund/dispute, or live verification. Netlify preview was nonproduction; the exact-main production attempt errored with no publication; the live site remains bounded #473 source 9ad6837756cdd409d296009fde5082eeeae5c059.
#590 is closed and its claim is explicitly released.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Outcome
Newly delivered supported Checkout Events now reject an embedded Checkout Session that claims it was created after the Event carrying that Session, before any target or business work.
Closes #590
Parent tracker: #106
Exact review identity
56332507f394f419616acfa6320f1bfbb16c60b58929be85a8276a02a2222c5b64e53d3723799ec48a000d30283e1b6e876b703dbf25a27182cd11bf172f0cbac9e1d461e3e34e41bf158dbbbed54152a9b4ed1470b3076eff8f0f80Invariant and failure behavior
After exact processed-Event replay and the existing Checkout realm, lifecycle, metadata, outer Event-time, and Session-time structure checks:
Checkout Session.created <= Event.createdEquality is valid because both provider fields use whole seconds. A later Session second produces fixed durable
needs_review:invalid_checkout_session_event_chronologywith:stripeCreatedAt;Equal and earlier chronology preserve existing lifecycle outcomes. Valid claimed missing targets remain retryable. Exact replay remains read-only and authoritative.
Changes
functions/stripeWebhook.js: one Checkout-only strict chronology comparison and fixed reason after both time-shape checks.functions/stripeWebhook.test.js: one named 62-test PAY-003A13 matrix/helpers and only three inherited chronology-valid fixture corrections in PAY-003A8, A10, and A11.STRIPE_COMMERCE_DESIGN.md: one PAY-003A13 SOURCE ONLY / NOT LIVE contract and chronology-specific A12 historical reconciliation.No schema, Rule, index, package, workflow, API, provider configuration, migration, backfill, history repair, or live change.
Trustworthy RED
On the exact base, the test-only four-lifecycle × two-domain matrix failed 8/8 because later Session time reached normal target/business processing and recorded
payment_confirmed,payment_failed, orpayment_expiredinstead of fixed target-free review.Test-only diff SHA-256:
027964b02b0151a1adb6c061dee22c94c231c0cd121a8f6a30cdb61cb31a1f51.Verification
Node 20.20.2 and Java 21; Firebase commands used demo projects and emulators only.
A discarded diagnostic inherited shell-default Node 22 and reproduced a known Error-own-surface mismatch in an unrelated projection suite. Under the required Node 20 runtime, that suite passed 25/25 and the complete Functions suite passed as listed.
Three independent exact-diff reviews returned GO: runtime/security, tests/compatibility, and design/backup-officer continuity.
Self-review
Officer continuity
Officer impact: None — server-only pre-target evidence comparison. No officer screen, task, field, permission, topology, approval path, incident step, or available recovery action changes.
Officer documentation: None — current officer procedures remain factual. The engineering boundary is documented in
STRIPE_COMMERCE_DESIGN.md.Deployment evidence
runmprc.comverified: no.Source and synthetic tests prove none of the unverified deployment/provider/live states.