Skip to content

PAY-002B2C3B — Persist immutable Stripe reconciliation evidence #206

Closed

Description

@daliu

Officer impact: None. This child adds an unused server-only evidence record and tests. It changes no current checkout, payment, refund, page, or officer procedure.

Officer documentation: None — no public page, officer duty, provider account, deployment, or production behavior changes.

Deployment evidence: None at issue creation. Closure must report source, tests, merge, website, runmprc.com, Firebase, Stripe/provider, production data, and live behavior separately. A green workflow proves none of the outside surfaces.

Problem

PAY-002B2C3A #184 freezes a pure closed classifier. Its new_attempt_candidate result is deliberately not persistence, authorization, or permission to send. No durable record currently proves which exact attempt-1 evidence the trusted verifier classified, and C3C must never act on a caller-held transient classification.

The next boundary must append one immutable reconciliation evidence record and one deterministic audit partner without changing any earlier command, lease, provider plan, pre-send marker, or audit. It must not create or authorize provider attempt 2.

Atomic outcome

Add one unused recordInitialStripeReconciliationEvidence(input) journal API. It validates the exact B1/B2A/B2B/C1/C2 chain, passes the exact closed attempt-1 evidence object to the unchanged C3A classifier, and atomically creates one deterministic reconciliation record/audit pair only when C3A returns new_attempt_candidate.

flowchart TD
    V["Trusted verifier produces exact closed attempt-1 evidence"] --> C{"Unchanged C3A result"}
    C -- "existing_attempt_found or reconciliation_required" --> N["Write nothing; do not advance"]
    C -- "new_attempt_candidate" --> J{"Exact B1 through C2 chain valid and bound?"}
    J -- "No" --> F["Fail closed; write nothing"]
    J -- "Yes" --> P["Atomically create one immutable evidence record and one audit"]
    P --> R["Return fixed persisted-candidate result"]
    R --> X["Still no send, attempt 2, or advancement authority"]
Loading

Text alternative: Only a complete candidate from the unchanged classifier and an exact existing command/plan/pre-send chain may create one immutable evidence and audit pair. Every other result writes nothing. The saved candidate still cannot send or create attempt 2.

Exact input boundary

The root is one exact plain data object containing:

  • the existing B1 command identity fields: db, environment, caller scope, command ID/type/schema, and canonical payload;
  • the existing C1 Stripe plan identity fields: account ID, mode, API version, fixed checkout-session-create operation/path, and canonical provider parameters;
  • one exact reconciliationEvidence object accepted by the unchanged C3A policy.

It accepts no caller timestamp, record path, document ID, provider object ID, Stripe idempotency key, hash/commitment, attempt number, lease/send flag, free text, URL, response, or attempt-2 field. This persistence step does not require or imply an active lease; C3C must obtain a fresh lease separately.

Invariants

  • functions/commerceProviderReconciliation.js remains byte-identical.
  • Only exact C3A new_attempt_candidate may be persisted. existing_attempt_found, reconciliation_required, malformed evidence, and hostile input write nothing.
  • The transaction validates the existing command/registration audit, lifecycle/current audit history, exact attempt-1 provider plan/audit, and exact C2 pre-send record/audit before reading or writing C3B.
  • C3B requires an existing structurally and chronologically valid C2 pair. Missing, orphaned, future, malformed, time-unknown, or conflicting C1/C2 evidence fails closed without repair.
  • The new record is under attempt 1 at one deterministic path. Its audit uses one deterministic ID. Both are created in the same transaction after every required read.
  • The record binds to command identity, provider attempt 1, the exact C1 plan commitment, a command-bound commitment to the exact C2 pair, the C3A policy version, all closed evidence enums, the fixed candidate classification/state, revision 1, and one trusted server timestamp.
  • The audit binds to the same command, attempt, plan/send commitments, policy version, candidate classification, evidence revision, environment/mode/operation, and exact timestamp.
  • No raw caller/command UUID, provider account/object ID, idempotency key, canonical parameters, PII, free text, response body, or secret is stored, returned, logged, or copied into an error.
  • Exact retry is read-only and returns the same fixed frozen result. Any different valid evidence under the same deterministic identity is a conflict. An orphan in either direction is invalid and is never repaired.
  • Transaction retry reuses one prepared timestamp and one deterministic pair. Commit failure leaves neither partner. A forged transaction return is rejected.
  • Every B1/B2A/B2B/C1/C2 record and audit remains byte-for-byte unchanged.
  • The fixed result contains no provider object, evidence values, ID/hash/path, send/execute/replay/advance flag, attempt 2, or business transition.
  • No Stripe SDK/network call, endpoint/index import, logger, random value, environment read, production record, migration, provider setting, or deployment is added.
  • Browser access remains denied by the existing nested checkoutRequests and auditEvents rules; add explicit read/write/list/collection-group denial proof without changing firestore.rules.

Acceptance criteria

  • The unchanged C3A classifier is the only classification authority and is imported only by the still-unused journal library.
  • Exact candidate evidence creates one deterministic immutable record/audit pair atomically after all foundation reads.
  • The saved record/audit are bound to the exact C1 plan and exact C2 send evidence without storing raw sensitive values.
  • Exact retry is read-only; one changed evidence enum conflicts and never overwrites.
  • Existing-attempt, reconciliation-required, invalid, incomplete, hostile, and accessor/proxy evidence writes nothing and exposes one fixed non-identifying error boundary.
  • Missing/orphan/future/malformed/conflicting C3B partners and any invalid C1/C2 foundation fail closed without repair.
  • Transaction retry, commit failure, forged return, and lost-response retry preserve atomicity and immutability.
  • Twenty-four identical emulator calls create exactly one pair; conflicting candidates race to one immutable winner.
  • Static tests prove no attempt-2 path/document, provider/network/logger/random/runtime/index adoption, or mutable earlier evidence.
  • Browser anonymous/member/admin read, create, update, delete, list, and collection-group access remains denied.
  • Focused mock and emulator suites, full Functions/lint, Rules, frontend/SPA/build, and workflow/artifact checks pass on Node 20/Java 17.
  • Security, concurrency/test, and documentation/dependency reviews approve the exact diff.
  • Source, tests, merge, Firebase deployment, Stripe/provider state, website publication, and production behavior are reported separately.

Exact owned paths

  1. functions/commerceCommandJournal.js
  2. functions/commerceCommandJournal.test.js
  3. functions/commerceCommandJournal.emulator.test.js
  4. functions/commerceProviderReconciliation.test.js
  5. tests/firestore-rules/shop-and-locked.test.js
  6. STRIPE_COMMERCE_DESIGN.md
  7. SYSTEM_DESIGN.md
  8. SECURITY.md
  9. IMPLEMENTATION_PLAN.md
  10. GITHUB_ISSUES.md
  11. GITHUB_ISSUE_SLICES.md

Dependencies and coordination

Explicitly out of scope

  • Editing functions/commerceProviderReconciliation.js or changing the C3A matrix.
  • Provider verification or trusting how evidence was gathered; inputs remain synthetic in tests.
  • C3C fresh lease, business-transition authorization, attempt-2 plan/key/document, provider request, checkout/webhook/runtime adoption, response replay, or repair.
  • firestore.rules, Functions index/endpoints/webhooks/refunds, workflow, package/lock, provider configuration, production data, migration, deployment, and officer procedures.

Claim protocol

Creation is not a claim. Before editing, assign the issue, post CLAIMED by <canonical agent> at <UTC>; branch <branch>, re-read live comments, and keep every excluded path untouched.

Activity

  1. 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 14, 2026
  2. self-assigned this
    on Jul 14, 2026
  3. daliu commented on Jul 14, 2026

    @daliu
    ContributorAuthor

    CLAIMED by /root at 2026-07-14T02:21:14Z; branch codex/issue-206-reconciliation-evidence.

    Exact base: 0dbac066a49837e31af72c9821c8044d287035fc.
    Exact ownership is the 11 paths in the issue body. The unchanged C3A source, Firestore Rules source, runtime/index/endpoints/webhooks/refunds, workflow, package/lock, provider, production-data, migration, deployment, and officer paths are excluded.

    Invariant: persistence is not authorization. This child may save only an exact attempt-1 new_attempt_candidate plus its deterministic audit. It cannot create attempt 2, send to Stripe, advance business state, or prove provider/live behavior.

  4. daliu commented on Jul 14, 2026

    @daliu
    ContributorAuthor

    IN-SCOPE CONCURRENCY ADDENDUM — 2026-07-14T02:25Z

    Design review found one required ordering gate: C3B must not freeze a candidate while C2 can still permit attempt 1. Candidate persistence therefore requires the one prepared trusted timestamp to be at or after C2's stored 23-hour automatic-retry deadline (C2 already stops at equality) and the current leased lifecycle to be expired. A valid candidate before either cutoff writes nothing and returns the unchanged frozen C3A new_attempt_candidate / requires_persistence_and_authorization result. A later exact call can persist it after the gates.

    This adds no new path or authority. It closes a race between a still-sendable attempt 1 and immutable reconciliation evidence. C3B still makes no provider call and C3C must separately obtain a fresh lease and authorization. Tests will cover deadline-minus-1ns, equality, active takeover, expiry equality, and terminal lifecycle denial.

  5. daliu commented on Jul 14, 2026

    @daliu
    ContributorAuthor

    EXTRACTION FINISHED by /root at 2026-07-14T03:11:54Z.

    Ready PR: #207
    Exact source commit: e6eb363632f89f4af333507bb1c20891d6847ac6
    Exact pre-commit diff SHA-256: 56c56e32dc60b164fe23b5490e15a7f7e2ba328d7da40ef79456f92ec91809f7
    Scope: exactly the 11 claimed paths; working tree clean.

    Independent security, code, concurrency/test, and dependency/documentation reviews approved the exact diff with no findings. Local Node 20 / Java 17 proof: focused 253/253, real reconciliation emulator 38/38, Functions lint + 1198 passed / 39 skipped, Rules 357/357, frontend 198/198, SPA 11/11, frontend lint baseline, production diagnostic build, exact path/exclusion/secret/link/diff checks all pass.

    Status is in review. No website, runmprc.com, Firebase, Stripe/provider, production-data, migration, or live-behavior change has been made or claimed. Merge waits for exact-head hosted checks.

  6. daliu commented on Jul 14, 2026

    @daliu
    ContributorAuthor

    COMPLETED by /root at 2026-07-14T03:15:53Z.

    • PR: PAY-002B2C3B: persist immutable reconciliation evidence #207, admin squash-merged after exact-head required checks passed.
    • Exact reviewed source head: e6eb363632f89f4af333507bb1c20891d6847ac6.
    • Exact main merge: 1730977eca65dc7df59bb7f195bbc44afd7e5895.
    • Exact-head CI: run 29302929975 — frontend, Functions, Rules, 38-case commerce-journal emulator, and artifact scrubber passed; Netlify PR preview passed.
    • Post-merge CI: run 29303009065 — all five jobs passed, including the real commerce-journal emulator.
    • Four independent exact-diff reviews approved security, concurrency/tests, code, and dependency/documentation boundaries with no findings.
    • All acceptance boxes are checked.

    Deployment/state truth:

    • Source changed, tests passed, and code merged: proven.
    • Website publication and runmprc.com production behavior: not changed or claimed; this exact merge has no GitHub deployment record and no web asset/runtime adoption.
    • Firebase deployment: not performed; the new library API is still unused and is not exported by a deployed endpoint/index.
    • Stripe/provider configuration or network calls: none.
    • Production data read/write or migration: none.
    • Live reconciliation behavior: not available; C3C authorization and every runtime adopter remain separate future work.

    The exact 11-path claim is released.

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