Skip to content

PAY-002B2C2 — Persist pre-POST Stripe send evidence and stop unsafe retries #182

Closed

Description

@daliu

Officer impact: None. This adds an unused server safety boundary and tests; it does not change any current officer task, website page, payment flow, or production system.

Officer documentation: None — no officer-visible or operational behavior becomes available.

Deployment evidence: Closure must distinguish source, tests, merge, website publication, Firebase deployment, Stripe/provider configuration, and production behavior. This issue must not deploy or contact Stripe.

Outcome

Add an unused server-only transaction boundary that records durable evidence immediately before a possible Stripe POST and refuses unsafe automatic retries.

Invariant

A retry may reuse only provider attempt 1, the exact immutable PAY-002B2C1 plan, parameters, account, mode, API version, endpoint, operation, and deterministic Stripe key. It is permitted only inside a fixed source-owned safe window that is strictly shorter than 24 hours. At or after the deadline, or when the first-send time is missing or untrustworthy, the result is reconciliation_required. This child never advances to attempt 2.

Timeout, connection loss, Stripe 5xx, a missing object reference, or an incomplete search never prove that Stripe did not execute the POST.

Exact scope

  • functions/commerceCommandJournal.js
  • functions/commerceCommandJournal.test.js
  • functions/commerceCommandJournal.emulator.test.js
  • tests/firestore-rules/shop-and-locked.test.js
  • STRIPE_COMMERCE_DESIGN.md
  • SYSTEM_DESIGN.md
  • SECURITY.md
  • IMPLEMENTATION_PLAN.md
  • GITHUB_ISSUES.md
  • GITHUB_ISSUE_SLICES.md

Explicitly excluded: stripeWebhook.js, checkout creators, commerceState.js, functions/index.js, packages/lockfiles, workflow files, Firestore Rules source, provider configuration, real data, and officer procedures.

Required behavior

  • Recompute and validate the complete PAY-002B1 identity and exact PAY-002B2C1 plan.
  • Require the exact active PAY-002B2B lease holder and fence.
  • Atomically create first-send evidence and its deterministic audit before returning a fixed send_permitted result.
  • Bind every retry to provider attempt 1 and the identical immutable plan.
  • Use one trusted transaction timestamp and a fixed retry deadline strictly under 24 hours.
  • Accept an exact retry only before the deadline.
  • At deadline equality, after the deadline, on clock rollback, or with absent/malformed send time, return reconciliation_required.
  • Never infer non-execution from timeout, network loss, 5xx, missing provider reference, or incomplete search.
  • Preserve B2A, B2B, and C1 records byte-for-byte.
  • Add no Stripe/network call, endpoint export, runtime adopter, deployment, or provider configuration.

Required tests

  • First pre-send marker and deterministic audit commit together.
  • Twenty-four concurrent calls create one marker and one audit.
  • Exact same-plan retry is permitted only inside the fixed window.
  • Boundary checks immediately before, exactly at, and after cutoff.
  • Timeout, connection-loss, and 5xx fixtures remain ambiguous and never advance attempts.
  • Changed plan/key/account/mode/version/parameters conflict.
  • Wrong holder/fence, expired lease, terminal lifecycle, and clock rollback fail closed.
  • Missing, orphaned, malformed, future-version, or preseeded partner records remain untouched.
  • Commit failure produces no half-record.
  • Transaction reruns reuse prepared immutable values and one trusted timestamp.
  • Raw key, account, parameters, caller, UUID, PII, provider response, and hostile canaries never enter storage, output, errors, logs, or audits.
  • Anonymous, member, and browser-admin clients cannot access the path.
  • Static boundary proves no endpoint/index import and no Stripe, network, logger, random, environment, or attempt-advancement API.
  • Focused tests, full Functions suite/lint, hosted journal emulator, Rules, frontend/SPA/build, artifact scrubber, and diff checks pass.

Dependencies

Complete: #157, #161, #163, #165, #167, #169, #173, #175, and #177.

#110 blocks retention/deletion policy, not this additive unused record. #113 blocks real inventory/adoption, not synthetic source-only validation.

Coordination

This is the live child for PAY-002B2C2. Do not create a duplicate. The parent PAY-002 design remains partial after this issue: B2C3 reconciliation/attempt advancement and every runtime checkout adopter stay open.

Do not begin until assigned and a timestamped CLAIMED marker names the agent, branch, base commit, and exact paths.

Activity

  1. self-assigned this
    on Jul 13, 2026
  2. added
    priority:P0Launch blocker or urgent security risk
    type:securitySecurity or privacy boundary
    area:firebaseFirebase services and data
    size:MMedium multi-file issue
    status:readyDependencies complete and ready to claim
    area:stripeStripe payments and financial lifecycle
    status:in-progressClaimed and actively being implemented
    and removed
    status:readyDependencies complete and ready to claim
    on Jul 13, 2026
  3. daliu commented on Jul 13, 2026

    @daliu
    ContributorAuthor

    CLAIMED by Codex agent /root at 2026-07-13T21:04:52Z on branch codex/issue-182-pay-002b2c2-presend from exact base 97ec6ee. Ownership is limited to functions/commerceCommandJournal.js, functions/commerceCommandJournal.test.js, functions/commerceCommandJournal.emulator.test.js, tests/firestore-rules/shop-and-locked.test.js, STRIPE_COMMERCE_DESIGN.md, SYSTEM_DESIGN.md, SECURITY.md, IMPLEMENTATION_PLAN.md, GITHUB_ISSUES.md, and GITHUB_ISSUE_SLICES.md. Excluded runtime/provider/workflow/package/Rules-source/officer paths remain immutable. One unused source/test outcome only.

  4. daliu commented on Jul 13, 2026

    @daliu
    ContributorAuthor

    EXTRACTION FINISHED — 2026-07-13T21:36:35Z

    Branch: codex/issue-182-pay-002b2c2-presend
    Base: 97ec6eeccc99e27d00ca271a0c874cbba9f36420

    The staged index contains exactly the 10 claimed paths. No runtime/index import, Stripe/network call, package/lock/workflow change, Firestore Rules source change, provider configuration, production data, or officer procedure is included.

    Safety result:

    • Both pre-send partners bind one command-bound digest of every immutable C1 plan field.
    • A valid delete/recreate of the parent C1 plan cannot reuse a surviving child marker.
    • The transaction validates holder/fence/leased state; a second trusted-time check downgrades if the call returns at/after the captured lease expiry or retry deadline, or if the clock rolls back.
    • Timeout, connection loss, and Stripe 5xx cannot enter this API or create attempt 2.

    Verification on Node 20 / Java 17:

    • focused journal unit: 190/190
    • real Firestore journal emulator: 31/31
    • full Functions: 15 suites, 945 passed, 32 skipped
    • full frontend: 10 suites, 133/133
    • full Firestore Rules: 4 suites, 317/317
    • workflow/release/SPA/artifact guards: 48/48
    • Functions lint and diagnostic production build: passed
    • staged diff check and secret-shaped pattern scan: clean

    Three independent read-only reviews (security, test/coverage, and documentation/status) approve the exact staged diff with no findings.

    Deployment evidence: source and synthetic tests only. Website, runmprc.com, Firebase, Stripe/provider settings, and production behavior were not changed or claimed.

  5. added a commit that references this issue on Jul 13, 2026
    95be260
  6. daliu commented on Jul 13, 2026

    @daliu
    ContributorAuthor

    COMPLETE / CLAIM RELEASED — 2026-07-13T21:40:55Z

    PR #183 was admin squash-merged from exact reviewed head db70adc610d55c4a5c8e04e2279b5ebf4fa5ee37 as main commit 95be260d08377b7e931dd3526da91b59c5fbf755.

    Exact-head CI run 29287012581 passed Frontend, Functions, Firestore Rules, Test artifact scrubber, and the 31-case Commerce command journal emulator. Post-merge main CI run 29287130585 passed the same five jobs, including the named real Firestore concurrency suite.

    The issue closed through the merged PR and status:in-progress is removed. The 10-path claim is released for work refreshed from 95be260 or later.

    Release truth: source/tests/docs are merged. This API is deliberately not imported by any runtime endpoint. No website publication, runmprc.com verification, Firebase deployment, Stripe/provider configuration, production data action, or live behavior occurred. PAY-002B2C3 reconciliation and all runtime adoption remain open.

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:MMedium multi-file issuetype:reliabilityReliability and recoverytype:securitySecurity or privacy boundary

Type

No type

Projects

No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions